C#:
/*
*� <----- End-User License Agreement ----->
*�
* �Copyright � 2024-26 Iftebinjan
*� Devoloper: Iftebinjan (Contact: https://discord.gg/HFaGs8YwsH)
*�
*� You may not copy, modify, merge, publish, distribute, sublicense, or sell copies of This Software without the Developer�s consent
* �
*� THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
*� THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
*� BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
*� GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*� LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*�
*� <----- End-User License Agreement ----->
*/
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Toastify", "yUN", "2.0.3")]
[Description("Create custom toast notifications")]
public partial class Toastify : RustPlugin
{
/*------------------------------------
*
* Toastify by Ifte
* Support: https://discord.gg/cCWadjcapr
* Fiverr: https://www.fiverr.com/s/e2pkYY
* Eror404 not found
*
------------------------------------*/
#region Fields
[PluginReference]
private Plugin ImageLibrary = null;
private static Toastify ins;
private const string permissionName = "toastify.use";
private string renderLayer = null;
private bool floatLeft = false;
private class Toast
{
public string id = Guid.NewGuid().ToString();
public string toastId;
public string title;
public string content;
public float duration;
public bool showing;
}
#endregion
#region Hooks
private void OnServerInitialized()
{
ins = this;
permission.RegisterPermission(permissionName, this);
floatLeft = config.General.Float.ToLower() == "left";
renderLayer = config.General.RenderLayer;
if (ImageLibrary != null)
{
CacheImages();
}
}
private void Unload()
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (player.TryGetComponent<Toaster>(out var component))
{
UnityEngine.Object.Destroy(component);
}
}
ins = null;
}
#endregion
#region Helpers
#region ImageLibrary
private void CacheImages()
{
Dictionary<string, string> importImages = new Dictionary<string, string>();
foreach (var pair in config.Toasts)
{
ToastConfig toastConfig = pair.Value;
if (IsImageUrl(toastConfig.Icon?.Url))
{
importImages.Add($"toastify.{pair.Key}.icon", toastConfig.Icon.Url);
}
if (toastConfig.Background != null)
{
if (IsImageUrl(toastConfig.Background.ImageUrl))
{
importImages.Add($"toastify.{pair.Key}.background", toastConfig.Background.ImageUrl);
}
if (toastConfig.Background.Decorations != null && toastConfig.Background.Decorations.Length > 0)
{
foreach (var decoration in toastConfig.Background.Decorations)
{
if (IsImageUrl(decoration.ImageUrl))
{
importImages.Add(decoration.ImageUrl, decoration.ImageUrl);
}
}
}
}
}
if (importImages.Count > 0)
{
ImageLibrary.CallHook("ImportImageList", Title, importImages, 0ul, true);
}
}
private string GetImage(string name)
{
if (ImageLibrary == null)
{
return null;
}
return ImageLibrary.Call<string>("GetImage", name, 0ul, true);
}
#endregion
private Toaster GetToaster(BasePlayer player)
{
return player.TryGetComponent<Toaster>(out var toaster)
? toaster
: player.gameObject.AddComponent<Toaster>();
}
private bool IsImageUrl(string url)
{
if (string.IsNullOrEmpty(url))
{
return false;
}
if (!url.StartsWith("http://") && !url.StartsWith("https://"))
{
return false;
}
return true;
}
#endregion
#region API
[HookMethod("SendToast")]
private string SendToast(BasePlayer player, string toastId, string title, string content = null, float duration = 0f)
{
if (!config.Toasts.ContainsKey(toastId))
{
throw new Exception("Invalid Toast ID");
}
Toast toast = new Toast()
{
toastId = toastId,
title = content == null ? null : title,
content = content == null ? title : content,
duration = duration
};
Toaster toaster = GetToaster(player);
toaster.ShowToast(toast);
string effect = config.Toasts[toastId].EffectPrefab;
if (!string.IsNullOrEmpty(effect))
{
Effect.server.Run(effect, player, 0u, Vector3.zero, Vector3.zero);
}
return toast.id;
}
[HookMethod("DestroyToast")]
private void DestroyToast(BasePlayer player, string toastId)
{
Toaster toaster = player.GetComponent<Toaster>();
if (toaster != null)
{
toaster.DestroyToast(toastId);
}
}
#endregion
#region MonoBehaviour
private class Toaster : MonoBehaviour
{
private BasePlayer player;
private List<Toast> queue = new List<Toast>();
private int ShowingCount { get => queue.Count((x) => x.showing); }
private int RenderLimit { get => Mathf.Min(ins.config.General.MaxToasts, queue.Count); }
private void Awake()
{
player = GetComponent<BasePlayer>();
}
private void OnDestroy()
{
foreach (Toast toast in queue.Where((x) => x.showing).ToArray())
{
CuiHelper.DestroyUi(player, toast.id);
}
queue.Clear();
}
private void UpdateToasts()
{
for (int i = 0; i < RenderLimit; i++)
{
Toast toast = queue[i];
StartCoroutine(RenderToast(toast, i));
}
}
private IEnumerator RenderToast(Toast toast, int index)
{
ToastConfig settings = ins.config.Toasts[toast.toastId];
PrintDebug("Rendering a new toast[{0}] ({1})", index, toast.toastId);
float y = index * (settings.Height + ins.config.General.Spacing);
ins.RenderToast(player, toast, y);
PrintDebug("Toast[{0}] rendered with content:\n{1}", index, toast.content);
if (!toast.showing)
{
queue[index].showing = true;
// Wait the duration
yield return CoroutineEx.waitForSeconds(toast.duration > 0f ? toast.duration : settings.Duration);
// Destroy the ui
DestroyToast(toast.id);
}
}
public void ShowToast(Toast toast)
{
queue.Add(toast);
if (ShowingCount < RenderLimit)
{
StartCoroutine(RenderToast(toast, ShowingCount));
}
}
public void DestroyToast(string id)
{
int index = queue.FindIndex((x) => x.id == id);
if (index > -1)
{
PrintDebug("Destroying toast[{0}] ID: {1}", index, id);
queue.RemoveAt(index);
CuiHelper.DestroyUi(player, id);
UpdateToasts();
}
}
}
#endregion
#region UI
private void RenderToast(BasePlayer player, Toast toast, float startY)
{
if (string.IsNullOrEmpty(toast.id))
{
toast.id = CuiHelper.GetGuid();
}
// Set the settings to shortname variables
ToastConfig s = config.Toasts[toast.toastId];
ToastBackgroundSettings bg = s.Background;
ToastIconSettings icon = s.Icon;
ToastTitleSettings title = s.Title;
ToastTextSettings text = s.Text;
float mx = config.General.MarginX;
float mt = config.General.MarginTop;
float fade = toast.showing ? 0f : .15f;
// Instantiate the ui builder
UIBuilder ui = new UIBuilder();
string anchor = floatLeft ? "0 1 0 1" : "1 1 1 1";
string offset = null;
if (floatLeft)
{
offset = $"{mx} -{s.Height + startY + mt} {mx + s.Width} -{startY + mt}";
}
else
{
offset = $"-{mx + s.Width} -{s.Height + startY + mt} -{mx} -{startY + mt}";
}
ui.AddPanel(renderLayer, "0 0 0 0", anchor, offset, name: toast.id);
// Background color
if (!string.IsNullOrEmpty(bg.Color))
{
ui.AddPanel(
toast.id,
UIBuilder.ParseColor(bg.Color, bg.Opacity),
"0 0 1 1",
"0 0 0 0",
bg.Material,
bg.Sprite,
fade
);
}
// Background image
if (!string.IsNullOrEmpty(bg.ImageUrl))
{
ui.AddImage(toast.id, GetImage($"toastify.{toast.toastId}.background") ?? bg.ImageUrl, null, "0 0 1 1", "0 0 0 0", fade);
}
// Background decorations
if (bg.Decorations != null && bg.Decorations.Length > 0)
{
int i = 0;
foreach (var d in bg.Decorations)
{
string name = $"{toast.id}.decoration.{i++}";
string color = !string.IsNullOrEmpty(d.BackgroundColor)
? UIBuilder.ParseColor(d.BackgroundColor)
: null;
float x = d.PosX, y = d.PosY, w = d.Width, h = d.Height;
ui.AddPanel(
toast.id,
color,
"0 0 0 0",
$"{x} {y} {x + w} {y + h}",
fadeIn: fade,
name: name
);
if (!string.IsNullOrEmpty(d.ImageUrl))
{
ui.AddImage(name, GetImage(d.ImageUrl) ?? d.ImageUrl, null, "0 0 1 1", "0 0 0 0", fade);
}
}
}
// Add the icon
if (!string.IsNullOrEmpty(icon.Url))
{
float x = icon.PosX, y = icon.PosY, size = icon.Size;
string iconImage = IsImageUrl(icon.Url)
? GetImage($"toastify.{toast.toastId}.icon") ?? icon.Url
: icon.Url;
ui.AddImage(
toast.id,
iconImage,
icon.Color != null ? UIBuilder.ParseColor(icon.Color) : null,
"0 0 0 0",
$"{x} {y} {x + size} {y + size}",
fade
);
}
// Add the title
if (!string.IsNullOrEmpty(title.LangKey))
{
float x = title.PosX, y = title.PosY, w = title.Width, h = title.Height;
ui.AddText(
toast.id,
string.IsNullOrEmpty(toast.title) ? Msg(player, title.LangKey) : toast.title,
"0 0 0 0",
$"{x} {y} {x + w} {y + h}",
title.FontSize,
title.Font,
title.Align,
fade,
0f
);
}
// Add the text
if (!string.IsNullOrEmpty(toast.content))
{
float x = text.PosX, y = text.PosY, w = text.Width, h = text.Height;
ui.AddText(
toast.id,
toast.content,
"0 0 0 0",
$"{x} {y} {x + w} {y + h}",
text.FontSize,
text.Font,
text.Align,
fade,
0f
);
}
// Add a transparent button
if (!string.IsNullOrEmpty(s.Command) || s.Closable)
{
ui.AddButton(
toast.id,
$"toastify.execute {toast.id} {s.Closable} {(string.IsNullOrEmpty(s.Command) ? "" : s.Command)}".TrimEnd(),
"0 0 1 1",
"0 0 0 0"
);
}
ui.Add(player);
}
#endregion
#region Commands
[ConsoleCommand("toastify")]
private void ConsoleCommandToastify(ConsoleSystem.Arg arg)
{
if (arg == null)
{
return;
}
BasePlayer player = arg.Player();
if (!arg.IsRcon && player == null)
{
return;
}
if (player != null && !player.IsAdmin && !permission.UserHasPermission(player.UserIDString, permissionName))
{
arg.ReplyWith(Msg(player, "NoPermission"));
return;
}
if (!arg.HasArgs(3))
{
arg.ReplyWith(Msg(player, "SyntaxError"));
return;
}
string toastId = arg.Args[0].ToString();
if (!config.Toasts.ContainsKey(toastId))
{
arg.ReplyWith(Msg(player, "InvalidToast", toastId));
return;
}
BasePlayer target = BasePlayer.Find(arg.Args[1].ToString());
if (target == null)
{
arg.ReplyWith(Msg(player, "PlayerNotFound"));
return;
}
SendToast(target, toastId, string.Join(' ', arg.Args.Skip(2)));
arg.ReplyWith(Msg(player, "ToastSent", target.displayName));
}
[ConsoleCommand("toastify.global")]
private void ConsoleCommandToastifyGlobal(ConsoleSystem.Arg arg)
{
if (arg == null)
{
return;
}
BasePlayer player = arg.Player();
if (!arg.IsRcon && player == null)
{
return;
}
if (player != null && !player.IsAdmin && !permission.UserHasPermission(player.UserIDString, permissionName))
{
arg.ReplyWith(Msg(player, "NoPermission"));
return;
}
if (!arg.HasArgs(2))
{
arg.ReplyWith(Msg(player, "SyntaxErrorGlobal"));
return;
}
string toastId = arg.Args[0].ToString();
if (!config.Toasts.ContainsKey(toastId))
{
arg.ReplyWith(Msg(player, "InvalidToast", toastId));
return;
}
string content = string.Join(' ', arg.Args.Skip(1));
foreach (BasePlayer activePlayer in BasePlayer.activePlayerList)
{
SendToast(activePlayer, toastId, content);
}
arg.ReplyWith(Msg(player, "ToastSentGlobal", BasePlayer.activePlayerList.Count));
}
[ConsoleCommand("toastify.execute")]
private void ConsoleCommandExecute(ConsoleSystem.Arg arg)
{
BasePlayer player = arg?.Player();
if (player == null || !arg.HasArgs(2))
{
return;
}
bool close = arg.Args[1].ToString().ToLower() == "true";
string toastId = arg.Args[0].ToString();
string command = string.Join(' ', arg.Args.Skip(2));
Toaster toaster = player.GetComponent<Toaster>();
if (toaster == null)
{
return;
}
if (close)
{
toaster.DestroyToast(toastId);
}
if (!string.IsNullOrEmpty(command))
{
rust.RunServerCommand(command);
}
}
#endregion
#region Configuration
private Configuration config;
#region Toast config
private class ToastTextSettings
{
[JsonProperty("Text align (combination with: 'top middle bottom' and 'left center right')")]
public string Align { get; set; }
[JsonProperty("Font")]
public string Font { get; set; }
[JsonProperty("Font size")]
public int FontSize { get; set; }
[JsonProperty("Width")]
public float Width { get; set; }
[JsonProperty("Height")]
public float Height { get; set; }
[JsonProperty("Position X")]
public float PosX { get; set; }
[JsonProperty("Position Y")]
public float PosY { get; set; }
}
private class ToastTitleSettings
{
[JsonProperty("Lang key")]
public string LangKey { get; set; }
[JsonProperty("Text align (combination with: 'top middle bottom' and 'left center right')")]
public string Align { get; set; }
[JsonProperty("Font")]
public string Font { get; set; }
[JsonProperty("Font size")]
public int FontSize { get; set; }
[JsonProperty("Width")]
public float Width { get; set; }
[JsonProperty("Height")]
public float Height { get; set; }
[JsonProperty("Position X")]
public float PosX { get; set; }
[JsonProperty("Position Y")]
public float PosY { get; set; }
}
private class ToastIconSettings
{
[JsonProperty("Url")]
public string Url { get; set; }
[JsonProperty("Color")]
public string Color { get; set; }
[JsonProperty("Size")]
public float Size { get; set; }
[JsonProperty("Position X")]
public float PosX { get; set; }
[JsonProperty("Position Y")]
public float PosY { get; set; }
}
private class ToastBackgroundDecorationSettings
{
[JsonProperty("Width")]
public float Width { get; set; }
[JsonProperty("Height")]
public float Height { get; set; }
[JsonProperty("Position X")]
public float PosX { get; set; }
[JsonProperty("Position Y")]
public float PosY { get; set; }
[JsonProperty("Background color")]
public string BackgroundColor { get; set; }
[JsonProperty("Image URL")]
public string ImageUrl { get; set; }
}
private class ToastBackgroundSettings
{
[JsonProperty("Color")]
public string Color { get; set; }
[JsonProperty("Opacity")]
public float Opacity { get; set; }
[JsonProperty("Image URL")]
public string ImageUrl { get; set; }
[JsonProperty("Material")]
public string Material { get; set; }
[JsonProperty("Sprite")]
public string Sprite { get; set; }
[JsonProperty("Decorations")]
public ToastBackgroundDecorationSettings[] Decorations { get; set; }
}
private class ToastConfig
{
[JsonProperty("Default duration")]
public float Duration { get; set; }
[JsonProperty("Width")]
public float Width { get; set; }
[JsonProperty("Height")]
public float Height { get; set; }
[JsonProperty("Background")]
public ToastBackgroundSettings Background { get; set; }
[JsonProperty("Icon settings")]
public ToastIconSettings Icon { get; set; }
[JsonProperty("Title settings")]
public ToastTitleSettings Title { get; set; }
[JsonProperty("Text settings")]
public ToastTextSettings Text { get; set; }
[JsonProperty("Close on click?")]
public bool Closable { get; set; }
[JsonProperty("Command on click")]
public string Command { get; set; }
[JsonProperty("Effect prefab")]
public string EffectPrefab { get; set; }
}
#endregion
private class GeneralConfig
{
[JsonProperty("Render layer")]
public string RenderLayer { get; set; }
[JsonProperty("Float side (left or right)")]
public string Float { get; set; }
[JsonProperty("Max toasts in the screen")]
public int MaxToasts { get; set; }
[JsonProperty("Margin X")]
public float MarginX { get; set; }
[JsonProperty("Margin top")]
public float MarginTop { get; set; }
[JsonProperty("Spacing between toasts")]
public float Spacing { get; set; }
}
private class Configuration
{
[JsonProperty("General")]
public GeneralConfig General { get; set; }
[JsonProperty("Toasts", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<string, ToastConfig> Toasts { get; set; }
[JsonProperty("Debug mode")]
public bool Debug { get; set; }
}
private Configuration GetBaseConfig()
{
return new Configuration()
{
General = new GeneralConfig()
{
RenderLayer = "Overlay",
Float = "right",
MaxToasts = 8,
MarginTop = 24f,
MarginX = 24f,
Spacing = 6f
},
Toasts = new Dictionary<string, ToastConfig>()
{
["success"] = new ToastConfig()
{
Width = 260f,
Height = 60f,
Duration = 10f,
Closable = true,
EffectPrefab = "assets/prefabs/locks/keypad/effects/lock.code.unlock.prefab",
Background = new ToastBackgroundSettings()
{
Color = "#5b7038",
Opacity = 1f,
Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat",
Decorations = new ToastBackgroundDecorationSettings[]
{
new ToastBackgroundDecorationSettings()
{
Width = 60f,
Height = 60f,
PosX = 0f,
PosY = 0f,
BackgroundColor = "0 0 0 0.4"
}
}
},
Icon = new ToastIconSettings()
{
Color = "#c4ff61",
PosX = 16f,
PosY = 16f,
Size = 28f,
Url = "assets/icons/check.png"
},
Title = new ToastTitleSettings()
{
LangKey = "ToastSuccessTitle",
FontSize = 14,
Width = 176f,
Height = 18f,
PosX = 72f,
PosY = 36f,
Align = "middle left"
},
Text = new ToastTextSettings()
{
Font = "robotocondensed-regular.ttf",
FontSize = 11,
Width = 176f,
Height = 28f,
PosX = 72f,
PosY = 6f,
Align = "top left"
}
},
["error"] = new ToastConfig()
{
Width = 260f,
Height = 60f,
Duration = 10f,
Closable = true,
EffectPrefab = "assets/prefabs/weapons/toolgun/effects/repairerror.prefab",
Background = new ToastBackgroundSettings()
{
Color = "#cd412b",
Opacity = 1f,
Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat",
Decorations = new ToastBackgroundDecorationSettings[]
{
new ToastBackgroundDecorationSettings()
{
Width = 60f,
Height = 60f,
PosX = 0f,
PosY = 0f,
BackgroundColor = "0 0 0 0.4"
}
}
},
Icon = new ToastIconSettings()
{
Color = "#ff9989",
PosX = 16f,
PosY = 16f,
Size = 28f,
Url = "https://i.ibb.co/xm7ZwPh/x-512.png"
},
Title = new ToastTitleSettings()
{
LangKey = "ToastErrorTitle",
FontSize = 14,
Width = 176f,
Height = 18f,
PosX = 72f,
PosY = 36f,
Align = "middle left"
},
Text = new ToastTextSettings()
{
Font = "robotocondensed-regular.ttf",
FontSize = 11,
Width = 176f,
Height = 28f,
PosX = 72f,
PosY = 6f,
Align = "top left"
}
}
},
Debug = false
};
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<Configuration>();
if (config == null)
{
throw new Exception();
}
}
catch
{
Interface.Oxide.LogWarning("Your configuration file is corrupted; Using default configuration instead;");
LoadDefaultConfig();
}
}
protected override void SaveConfig()
{
Config.WriteObject(config);
}
protected override void LoadDefaultConfig()
{
config = GetBaseConfig();
}
#endregion
#region Utils
private static void PrintDebug(string message, params object[] args)
{
if (ins.config.Debug)
{
Interface.Oxide.LogDebug(message, args);
}
}
#endregion
#region Localization
private string Msg(BasePlayer player, string key, params object[] args)
{
return string.Format(lang.GetMessage(key, this, player?.UserIDString), args);
}
protected override void LoadDefaultMessages()
{
Dictionary<string, string> messages = new Dictionary<string, string>()
{
{ "NoPermission", "You don't have permission to use this command." },
{ "SyntaxError", "toastify [toast_id] [player] [message]" },
{ "SyntaxErrorGlobal", "toastify.global [toast_id] [message]" },
{ "InvalidToast", "No toast was found with this id" },
{ "PlayerNotFound", "No player was found with this name or id" },
{ "ToastSent", "You sent a toast to {0}!" },
{ "ToastSentGlobal", "You sent a toast to {0} players!" }
};
// Create a new lang message for each toast title
foreach (ToastConfig toastConfig in config.Toasts.Values)
{
if (toastConfig.Title != null && !string.IsNullOrEmpty(toastConfig.Title.LangKey))
{
if (!messages.ContainsKey(toastConfig.Title.LangKey))
{
messages.Add(toastConfig.Title.LangKey, "CHANGE IT IN THE LANG FILE");
}
}
}
lang.RegisterMessages(messages, this);
}
#endregion
[ChatCommand("testtoast")]
private void TestCMD(BasePlayer player, string command, string[] args)
{
if (args.Length == 0)
{
SendReply(player, "Usage: /testtoast <message>");
return;
}
string text = string.Join(" ", args);
ShowToast(player, text);
timer.In(10f, () => CuiHelper.DestroyUi(player, "GameToast"));
}
private const string UI_NAME = "GameToastDynamic"; // Ensure you define this at the class level
private void ShowToast(BasePlayer player, string message)
{
CuiHelper.DestroyUi(player, "GameToast");
CuiElementContainer container = new CuiElementContainer();
// ---- SETTINGS ----
float charWidth = 7.2f; // tweak this for font accuracy
float iconWidth = 32f;
float padding = 30f; // left + right spacing
float spacing = 10f; // space between icon & text
float minWidth = 120f;
float maxWidth = 800f;
// ---- CALCULATE WIDTH ----
float textWidth = message.Length * charWidth;
float totalWidth = iconWidth + spacing + textWidth + padding;
float finalWidth = Mathf.Clamp(totalWidth, minWidth, maxWidth);
float halfWidth = finalWidth / 2f;
// ---- PANEL ----
container.Add(new CuiElement
{
Name = "GameToast",
Parent = "Overlay",
Components =
{
new CuiImageComponent { Color = "0.12 0.42 0.63 1", Material = "assets/content/ui/uibackgroundblur.mat" },
new CuiRectTransformComponent
{
AnchorMin = "0.5 0",
AnchorMax = "0.5 0",
OffsetMin = $"{-halfWidth} 120",
OffsetMax = $"{halfWidth} 165"
}
}
});
// ---- ICON ----
container.Add(new CuiElement
{
Name = "ToastIcon",
Parent = "GameToast",
Components =
{
new CuiRawImageComponent
{
Url = "https://i.postimg.cc/9084TfX2/info.png", //assets/icons/warning_2.png assets/icons/connection.png //https://i.postimg.cc/k4yRJcLp/warning.png https://i.postimg.cc/9084TfX2/info.png
Color = "1 1 1 1"
},
new CuiRectTransformComponent
{
AnchorMin = "0 0.5",
AnchorMax = "0 0.5",
OffsetMin = "12 -14",
OffsetMax = "44 14"
}
}
});
// ---- TEXT ----
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0",
AnchorMax = "1 1",
OffsetMin = $"{iconWidth + spacing + 10} 0",
OffsetMax = "-10 0"
},
Text =
{
Text = message,
FontSize = 14,
Align = TextAnchor.MiddleLeft,
Font = "RobotoCondensed-Bold.ttf",
Color = "1 1 1 1"
}
}, "GameToast");
CuiHelper.AddUi(player, container);
}
}
}
namespace Oxide.Plugins
{
partial class Toastify : RustPlugin
{
private class UIBuilder
{
private enum ImageType
{
Url,
ImageId,
Asset
};
private Dictionary<string, TextAnchor> textAligns = new Dictionary<string, TextAnchor>()
{
["top left"] = TextAnchor.UpperLeft,
["top center"] = TextAnchor.UpperCenter,
["top right"] = TextAnchor.UpperRight,
["middle left"] = TextAnchor.MiddleLeft,
["middle center"] = TextAnchor.MiddleCenter,
["middle right"] = TextAnchor.MiddleRight,
["bottom left"] = TextAnchor.LowerLeft,
["bottom center"] = TextAnchor.LowerCenter,
["bottom right"] = TextAnchor.LowerRight
};
public CuiElementContainer container { get; private set; }
public UIBuilder()
{
container = new CuiElementContainer();
}
public void Add(BasePlayer player)
{
CuiHelper.AddUi(player, container);
}
public void AddPanel(string parent, string color, string anchor, string offset, string material = null, string sprite = null, float fadeIn = 0f, float fadeOut = 0f, string name = null)
{
name ??= CuiHelper.GetGuid();
CuiElement element = new CuiElement()
{
Parent = parent,
Name = name,
DestroyUi = name,
FadeOut = fadeOut,
Components = {
ParseRect(anchor, offset),
new CuiImageComponent()
{
Color = color,
FadeIn = fadeIn,
Material = material,
Sprite = sprite
}
}
};
container.Add(element);
}
public void AddImage(string parent, string image, string color, string anchor, string offset, float fadeIn = 0f, float fadeOut = 0f, string name = null)
{
name ??= CuiHelper.GetGuid();
ImageType imageType = ImageType.Url;
if (image.StartsWith("assets/"))
{
imageType = ImageType.Asset;
}
else if (image.All(char.IsNumber))
{
imageType = ImageType.ImageId;
}
CuiElement element = new CuiElement();
element.Name = name;
element.Parent = parent;
element.DestroyUi = name;
element.Components.Add(ParseRect(anchor, offset));
if (imageType == ImageType.Url)
{
element.Components.Add(new CuiRawImageComponent()
{
Color = color,
FadeIn = fadeIn,
Url = image
});
}
else
{
element.Components.Add(new CuiRawImageComponent()
{
Color = color,
FadeIn = fadeIn,
Material = "assets/icons/iconmaterial.mat",
Png = imageType == ImageType.ImageId ? image : null,
Sprite = imageType == ImageType.Asset ? image : null
});
}
container.Add(element);
}
public void AddText(string parent, string text, string anchor, string offset, int fontSize = 12, string font = null, string textAlign = "middle left", float fadeIn = 0f, float fadeOut = 0f, string name = null)
{
name ??= CuiHelper.GetGuid();
CuiElement element = new CuiElement()
{
Parent = parent,
Name = name,
DestroyUi = name,
FadeOut = fadeOut,
Components = {
ParseRect(anchor, offset),
new CuiTextComponent()
{
Text = text,
Align = textAligns.ContainsKey(textAlign.ToLower()) ? textAligns[textAlign.ToLower()] : TextAnchor.MiddleLeft,
FontSize = fontSize,
Font = font ?? "robotocondensed-bold.ttf",
FadeIn = fadeIn
}
}
};
container.Add(element);
}
public void AddButton(string parent, string command, string anchor, string offset)
{
CuiElement element = new CuiElement()
{
Name = CuiHelper.GetGuid(),
Parent = parent,
Components = {
ParseRect(anchor, offset),
new CuiButtonComponent()
{
Color = "0 0 0 0",
Command = command
}
}
};
container.Add(element);
}
public static string ParseColor(string hex, float? alpha = null)
{
Color color;
if (!ColorUtility.TryParseHtmlString(hex, out color))
{
return hex;
}
return $"{color.r} {color.g} {color.b} {(alpha == null ? color.a : alpha)}";
}
private CuiRectTransformComponent ParseRect(string anchor, string offset)
{
string[] anchors = anchor.Split(' ');
string[] offsets = offset.Split(' ');
return new CuiRectTransformComponent()
{
AnchorMin = $"{anchors[0]} {anchors[1]}",
AnchorMax = $"{anchors[2]} {anchors[3]}",
OffsetMin = $"{offsets[0]} {offsets[1]}",
OffsetMax = $"{offsets[2]} {offsets[3]}"
};
}
}
}
}