C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using Oxide.Plugins.SimpleStatusExtensionMethods;
using Newtonsoft.Json;
using System.Collections.Generic;
using UnityEngine;
using Oxide.Core.Libraries.Covalence;
using Newtonsoft.Json.Converters;
using Oxide.Core.Plugins;
using System.Linq;
using ProtoBuf;
using Oxide.Game.Rust.Cui;
using System;
using Oxide.Core;
using System.Globalization;
namespace Oxide.Plugins {
[Info("SimpleStatus", "mr01sam", "1.2.9")]
[Description("Allows plugins to add custom status displays for the UI.")]
partial class SimpleStatus : CovalencePlugin {
/* // Changelog
[v1.2.0]
-SimpleStatus now works together with AdvancedStatus.You can now have both installed on your server and they wont overlap with each other.Might be a few bugs with this integration, just report them if you see them.-Added progress bars, which mimic the style of the health/thirst/hunger/vehicle durability bars
-Added new hook for OnSimpleStatusReady that is called after the plugin has finished loading and is called when a plugin that uses SimpleStatus is loaded, ideal for initializing statuses
-Added a rank property that can determine the priority of listing custom statuses
-Updated some API endpoints, old ones still exist but the new ones are recommended to use
-Fixed issue where statuses wouldnt account for horse stamina
-Updated rendering so it should be quicker to redraw
[v1.2.1]
-Fixed issue where statuses would be invisible after dying
-Fixed issue where holding a planner would mess up the statuses
[v1.2.2]
-Fixed issue where the SetColor api wouldnt work
-Fixed issue where statuses would appear at the wrong index if the color was changed
-Fixed issue where the title/text woutuld not be translated if changed
[v1.2.3]
-Fixed issue where statuses would not load properly if you were dead and tried to reconnect
-Statuses now disappear visually when you die and sleep
[v1.2.4]
-Fixed null reference issue on PlayerSleepEnded hook
-Fixed issue where hiding the status would cause it to not come back
[v1.2.5]
-Fixed issue where some statuses would not redraw after being removed once
[v1.2.6]
-Fixed issue where some statuses would not show up after respawning in a bed/sleeping bag
-Removed OnSimpleStatusReady hook, I recommend just doing this logic in the ServerInitialized like before
[v1.2.7]
-Brought OnSimpleStatusReady back to not break plugins
-Fixed issue where hooks were not being called, causing statuses not to show up
[v1.2.8]
-Fixed issue where OnCollectiblePickup would sometimes throw an error
-Fixed issue where statuses would not realign properly when using a stamina based vehicle, like bikes
-Fixed issue of statuses overlapping when you build
-Fixed bug with AdvancedStatus integration where SetText would not properly update the SubText color property
[v1.2.9]
-Fix for 3/6/2025 Rust update
*/
public static SimpleStatus PLUGIN;
[PluginReference]
private readonly Plugin ImageLibrary, CustomStatusFramework, AdvancedStatus;
private readonly bool Debugging = false;
// If you are a developer, you can enable this to get console logs.private readonly int[] DebugCodes = new int[] { }; // Add codes here for specific debug statements you want to see, empty array will show all.#region Init
private void Init() {
UnsubscribeAll(nameof(OnPlayerSleepEnded), nameof(OnPlayerSleep), nameof(OnPlayerDeath), nameof(CanPickupEntity), nameof(OnItemPickup), nameof(OnStructureUpgrade), nameof(OnStructureRepair), nameof(OnCupboardAuthorize), nameof(OnCupboardDeauthorize), nameof(OnDispenserGather), nameof(OnCollectiblePickup), nameof(OnPlayerRespawn) );
PLUGIN = this;
}
private void OnServerInitialized() {
if (!ImageLibrary?.IsLoaded ?? true) {
PrintError("ImageLibary is REQUIRED for this plugin to work properly.Please load it onto your server and reload this plugin.");
return;
}
if (CustomStatusFramework?.IsLoaded ?? false) {
PrintError("You have both Simple Status and Custom Status Framework installed.These plugins do the same thing and will conflict with each other.Please unload Custom Status Framework and reload this plugin.");
return;
}
AddCovalenceCommand(config.ToggleStatusCommand, nameof(CmdToggleStatus));
LoadData();
if (UsingAdvancedStatus) {
Puts("AdvancedStatus will be used in place of SimpleStatus for your plugins, you still need both though!");
}
SubscribeAll();
foreach (var player in BasePlayer.activePlayerList) {
OnPlayerConnected(player);
OnPlayerSleepEnded(player);
}
Interface.CallHook("OnSimpleStatusReady");
}
private void Unload() {
SaveData();
foreach (var player in BasePlayer.activePlayerList) {
OnPlayerDisconnected(player);
}
}
private void OnPluginUnloaded(Plugin plugin) {
var name = plugin?.Name;
if (name == Name) {
return;
}
if (Data.Statuses.Values.Any(x => x.PluginName == name)) {
RemovePluginData(name);
}
}
#endregion
#region Subscribing
public List<string> SubscribedHooks = new List<string>();
private void SubscribeAll() {
foreach (var hook in SubscribedHooks) {
Subscribe(hook);
}
}
private void UnsubscribeAll(params string[] hooks) {
foreach (var hook in hooks) {
SubscribedHooks.Add(hook);
Unsubscribe(hook);
}
}
#endregion
#region Oxide Hooks
private void OnPlayerConnected(BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
BehaviorManager.AddBehavior(basePlayer);
}
private void OnPlayerDisconnected(BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
BehaviorManager.RemoveBehavior(basePlayer.UserIDString);
Debug($"Disconnecting {basePlayer.displayName} has {(Data.Player.ContainsKey(basePlayer.UserIDString) ? Data.Player[basePlayer.UserIDString].Count : 0)} statuses: {Data.Player.GetValueOrDefault(basePlayer.UserIDString)?.Keys.ToSentence()}");
}
private void OnPlayerSleepEnded(BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
if (!Data.PlayersHiding.Contains(basePlayer.UserIDString)) {
BehaviorManager.ShowBehavior(basePlayer);
}
}
private void OnPlayerSleep(BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
BehaviorManager.HideBehavior(basePlayer);
}
private void OnPlayerRespawn(BasePlayer basePlayer, BasePlayer.SpawnPoint spawnPoint) {
if (basePlayer == null) {
return;
}
OnPlayerConnected(basePlayer);
}
private void OnPlayerRespawn(BasePlayer basePlayer, SleepingBag sleepingBag2) {
if (basePlayer == null) {
return;
}
OnPlayerConnected(basePlayer);
}
private void OnPlayerDeath(BasePlayer basePlayer, HitInfo info) => OnPlayerDisconnected(basePlayer);
private void CanPickupEntity(BasePlayer basePlayer, BaseEntity entity) {
if (basePlayer == null || entity == null) {
return;
}
var name = entity?.name;
NextTick(() => {
if (basePlayer != null && name != null) {
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc(name);
}
}
);
}
private void OnEntityBuilt(Planner plan, GameObject go) {
if (plan == null || go == null) {
return;
}
var basePlayer = plan.GetOwnerPlayer();
if (basePlayer == null) {
return;
}
var buildingBlock = go.ToBaseEntity() as BuildingBlock;
if (buildingBlock == null) {
return;
}
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc($"removed {buildingBlock.grade}");
}
private void OnItemPickup(Item item, BasePlayer basePlayer) {
if (basePlayer == null || item == null) {
return;
}
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc(item.info.shortname);
}
private void OnStructureUpgrade(BaseCombatEntity entity, BasePlayer basePlayer, BuildingGrade.Enum grade) {
if (basePlayer == null) {
return;
}
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc($"removed {grade}");
}
private void OnStructureRepair(BuildingBlock entity, BasePlayer basePlayer) {
NextTick(() => {
if (entity != null && basePlayer != null) {
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc($"removed {entity.grade}");
}
}
);
}
private void OnCupboardAuthorize(BuildingPrivlidge privilege, BasePlayer basePlayer) {
NextTick(() => {
var b = Behaviours.GetValueOrDefault(basePlayer?.UserIDString);
if (b == null) {
return;
}
b.ForceCheckModifiers();
b.ForceUpdateUI();
}
);
}
private void OnCupboardDeauthorize(BuildingPrivlidge privilege, BasePlayer basePlayer) {
NextTick(() => {
var b = Behaviours.GetValueOrDefault(basePlayer?.UserIDString);
if (b == null) {
return;
}
b.ForceCheckModifiers();
b.ForceUpdateUI();
}
);
}
private void OnDispenserGather(ResourceDispenser dispenser, BasePlayer basePlayer, Item item) {
if (basePlayer == null || item == null) {
return;
}
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc(item.info.shortname);
}
private void OnCollectiblePickup(CollectibleEntity collectible, BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
if (collectible == null || collectible.itemList == null) {
return;
}
collectible.itemList.ForEach(item => {
if (item != null) {
Behaviours.GetValueOrDefault(basePlayer.UserIDString)?.itemStatuses.Inc(item.itemDef.shortname);
}
}
);
}
#endregion
#region Status Info
protected class SavedData {
public Dictionary<string, StatusInfo> Statuses = new Dictionary<string, StatusInfo>();
public HashSet<string> PlayersHiding = new HashSet<string>();
public Dictionary<string, Dictionary<string, PlayerStatusInfo>> Player = new Dictionary<string, Dictionary<string, PlayerStatusInfo>>();
}
private static string GetImageData(string path) {
if (string.IsNullOrWhiteSpace(path)) {
return string.Empty;
}
else if (path.IsAssetPath()) {
return path;
}
else if (path.IsItemId()) {
return path.AsItemId();
}
else if (path.IsRawImage()) {
return PLUGIN.ImageLibrary?.Call<string>("GetImage", path.AsRawImage()) ?? string.Empty;
}
return PLUGIN.ImageLibrary?.Call<string>("GetImage", path) ?? string.Empty;
}
[JsonConverter(typeof(StringEnumConverter))]
protected enum StatusType {
titletext, progress
}
protected class PlayerStatusInfo {
public int Duration;
public string Color = null;
public string Title = null;
public string TitleColor = null;
public string Text = null;
public string TextColor = null;
public string ImagePathOrUrl = null;
public string IconColor = null;
public string Progress = null;
public string ProgressColor = null;
public string UserId = "0";
public StatusType StatusType = StatusType.titletext;
[JsonIgnore]
public string ImageData => GetImageData(ImagePathOrUrl);
public DateTime? EndTime = null;
[JsonIgnore]
public bool IsPastEndTime => EndTime.HasValue && EndTime.Value < DateTime.Now;
[JsonIgnore]
public int DurationUntilEndTime => !EndTime.HasValue ? Duration : (int)Math.Floor((EndTime.Value.Subtract(DateTime.Now)).TotalSeconds);
[JsonIgnore]
public bool Drawn = false;
}
private SavedData _data = new SavedData();
protected static SavedData Data => PLUGIN._data;
private void RemovePluginData(string pluginName) {
Debug($"Removing {pluginName} because its no longer loaded");
var statuses = Data.Statuses.Where(x => x.Value.PluginName == pluginName).Select(x => x.Key).ToArray();
foreach (var status in statuses) {
Data.Statuses.Remove(status);
}
var userIdsToUpdate = new HashSet<string>();
foreach (var playerData in Data.Player.ToArray()) {
var userId = playerData.Key;
foreach (var key in playerData.Value.Keys.ToArray()) {
if (statuses.Contains(key)) {
Data.Player[userId].Remove(key);
}
}
userIdsToUpdate.Add(userId);
}
foreach (var userId in userIdsToUpdate) {
var behavior = Behaviours.GetValueOrDefault(userId);
if (behavior == null) {
continue;
}
behavior.rowsNeedUpdate = true;
var basePlayer = BasePlayer.Find(userId);
if (basePlayer != null) {
foreach(var status in statuses) {
CuiHelper.DestroyUi(basePlayer, string.Format(UI_Status_ID, status));
}
}
}
}
private void SaveData() {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/data", Data);
}
private void LoadData() {
Debug("Load data called");
var data = Interface.Oxide.DataFileSystem.ReadObject<SavedData>($"{Name}/data") ?? new SavedData();
if (data.Statuses == null) {
data.Statuses = new Dictionary<string, StatusInfo>();
}
if (data.Player == null) {
data.Player = new Dictionary<string, Dictionary<string, PlayerStatusInfo>>();
}
_data.Player = data.Player;
if (data.Statuses == null) {
data.Statuses = new Dictionary<string, StatusInfo>();
}
foreach (var status in data.Statuses.ToArray()) {
if (!status.Value.Plugin?.IsLoaded ?? true) {
RemovePluginData(status.Value.PluginName);
}
else if (!_data.Statuses.ContainsKey(status.Key)) {
Debug("Assigned new status from load");
_data.Statuses[status.Key] = status.Value;
}
}
}
private static void Debug(string message) {
if (PLUGIN == null || !PLUGIN.Debugging) {
return;
}
var code = message.Split(" ").First().GetHashCode();
if (PLUGIN.DebugCodes != null && PLUGIN.DebugCodes.Length > 0 && !PLUGIN.DebugCodes.Contains(code)) {
return;
}
PLUGIN?.Puts($"DEBUG({code}): {message}");
}
protected class StatusInfo {
[JsonIgnore]
public Plugin Plugin => Interface.uMod.RootPluginManager.GetPlugin(PluginName);
[JsonIgnore]
public bool PluginIsLoaded => Plugin?.IsLoaded ?? false;
public string PluginName;
public string Id;
public string Color;
public string Title;
public string TitleColor;
public string Text = null;
public string TextColor;
public string ImageLibraryNameOrAssetPath;
public string Progress = null;
public string ProgressColor = "0 0 0 0.9";
public int Rank = 0;
public StatusType Type = StatusType.titletext;
[JsonProperty("ImageLibraryIconId")]
private string ImageLibraryIconId // old version
{
set {
ImageLibraryNameOrAssetPath = value;
}
}
public string IconColor;
[JsonIgnore]
public bool IsAssetImage => !string.IsNullOrEmpty(ImageLibraryNameOrAssetPath) && ImageLibraryNameOrAssetPath.IsAssetPath();
[JsonIgnore]
public bool HasImage => !string.IsNullOrEmpty(ImageLibraryNameOrAssetPath);
[JsonIgnore]
public string ImageData => GetImageData(ImageLibraryNameOrAssetPath);
}
#endregion
#region Utility
private static void Message(BasePlayer basePlayer, string message) {
var icon = PLUGIN.config.ChatMessageSteamId;
ConsoleNetwork.SendClientCommand(basePlayer.Connection, "chat.add", 2, icon, message);
}
public static string Json(CuiElement element) {
return JsonConvert.SerializeObject(element, Formatting.None, new JsonSerializerSettings {
DefaultValueHandling = DefaultValueHandling.Ignore
}
);
}
#endregion
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
[HookMethod(nameof(CreateStatus))]
private void CreateStatus(Plugin plugin, string statusId, string backgroundColor = "1 1 1 1", string title = "Text", string titleColor = "1 1 1 1", string text = null, string textColor = "1 1 1 1", string imageLibraryNameOrAssetPath = null, string imageColor = "1 1 1 1") {
CreateStatus(plugin, statusId, new Dictionary<string, object> {
["color"]
= backgroundColor, ["title"] = title, ["titleColor"] = titleColor, ["text"] = text, ["textColor"] = textColor, ["icon"] = imageLibraryNameOrAssetPath, ["iconColor"] = imageColor
}
);
}
[HookMethod(nameof(CreateStatus))]
private void CreateStatus(Plugin plugin, string statusId, Dictionary<string, object> properties) {
Debug("CreateStatus called");
Data.Statuses[statusId] = new StatusInfo {
PluginName = plugin.Name, Id = statusId, Color = properties.GetProperty("color", string.Empty), Title = properties.GetProperty("title", string.Empty), TitleColor = properties.GetProperty("titleColor", string.Empty), Text = properties.GetProperty("text", string.Empty), TextColor = properties.GetProperty("textColor", string.Empty), ImageLibraryNameOrAssetPath = properties.GetProperty("icon", string.Empty), IconColor = properties.GetProperty("iconColor", string.Empty), Progress = properties.GetPropertyFloatOrString("progress"), ProgressColor = properties.GetProperty("progressColor", string.Empty), Rank = properties.GetProperty("rank", 0)
}
;
}
[HookMethod(nameof(SetStatus))]
private void SetStatus(ulong userId, string statusId, int duration = int.MaxValue, bool pauseOffline = true) => SetStatus(userId.ToString(), statusId, duration, pauseOffline);
private void SetStatus(EncryptedValue<ulong> userId, string statusId, int duration = int.MaxValue, bool pauseOffline = true) => SetStatus(userId.Get().ToString(), statusId, duration, pauseOffline);
private void SetStatus(string userId, string statusId, int duration = int.MaxValue, bool pauseOffline = true) {
Debug($"SetStatus called {userId} {statusId} {duration} {pauseOffline}");
#region AdvancedStatus
if (UsingAdvancedStatus) {
var createdStatus = Data.Statuses.GetValueOrDefault(statusId);
if (createdStatus == null) {
return;
}
var data = Data.Player.GetValueOrNew(userId).GetValueOrDefault(statusId);
var userIdParsed = ulong.Parse(userId);
if (duration == 0) {
AS_DeleteBar(userIdParsed, createdStatus);
}
else if ((bool)(AdvancedStatus?.Call("BarExists", userIdParsed, statusId, Name) ?? false)) {
AS_SetDuration(userIdParsed, createdStatus, duration);
}
else {
AS_CreateBar(userIdParsed, createdStatus, data, duration);
}
return;
}
#endregion
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
// save status for later if player is offline
SetStatusForOfflinePlayer(userId, statusId, duration, pauseOffline);
return;
}
if (duration > 0) {
b.SetStatus(statusId, duration, pauseOffline);
}
else {
b.RemoveStatus(statusId);
}
}
[HookMethod(nameof(SetStatusColor))]
private void SetStatusColor(ulong userId, string statusId, string color = null) => SetStatusColor(userId.ToString(), statusId, color);
private void SetStatusColor(EncryptedValue<ulong> userId, string statusId, string color = null) => SetStatusColor(userId.Get().ToString(), statusId, color);
private void SetStatusColor(string userId, string statusId, string color = null) {
Debug("SetStatusColor called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["color"]
= color ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusTitle))]
private void SetStatusTitle(ulong userId, string statusId, string title = null) => SetStatusTitle(userId.ToString(), statusId.ToString(), title);
private void SetStatusTitle(EncryptedValue<ulong> userId, string statusId, string title = null) => SetStatusTitle(userId.Get().ToString(), statusId, title);
private void SetStatusTitle(string userId, string statusId, string title = null) {
Debug("SetStatusTitle called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["title"]
= title ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusTitleColor))]
private void SetStatusTitleColor(ulong userId, string statusId, string color = null) => SetStatusTitleColor(userId.ToString(), statusId, color);
private void SetStatusTitleColor(EncryptedValue<ulong> userId, string statusId, string color = null) => SetStatusColor(userId.Get().ToString(), statusId, color);
private void SetStatusTitleColor(string userId, string statusId, string color = null) {
Debug("SetStatusTitleColor called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["titleColor"]
= color ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusText))]
private void SetStatusText(ulong userId, string statusId, string text = null) => SetStatusText(userId.ToString(), statusId, text);
private void SetStatusText(EncryptedValue<ulong> userId, string statusId, string text = null) => SetStatusText(userId.Get().ToString(), statusId, text);
private void SetStatusText(string userId, string statusId, string text = null) {
Debug("SetStatusText called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["text"]
= text ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusTextColor))]
private void SetStatusTextColor(ulong userId, string statusId, string color = null) => SetStatusText(userId.ToString(), statusId, color);
private void SetStatusTextColor(EncryptedValue<ulong> userId, string statusId, string color = null) => SetStatusText(userId.Get().ToString(), statusId, color);
private void SetStatusTextColor(string userId, string statusId, string color = null) {
Debug("SetStatusTextColor called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["textColor"]
= color ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusIcon))]
private void SetStatusIcon(ulong userId, string statusId, string imageLibraryNameOrAssetPath = null) => SetStatusIcon(userId.ToString(), statusId, imageLibraryNameOrAssetPath);
private void SetStatusIcon(EncryptedValue<ulong> userId, string statusId, string imageLibraryNameOrAssetPath = null) => SetStatusIcon(userId.Get().ToString(), statusId, imageLibraryNameOrAssetPath);
private void SetStatusIcon(string userId, string statusId, string imageLibraryNameOrAssetPath = null) {
Debug("SetStatusIcon called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["icon"]
= imageLibraryNameOrAssetPath ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusIconColor))]
private void SetStatusIconColor(ulong userId, string statusId, string color = null) => SetStatusIcon(userId.ToString(), statusId, color);
private void SetStatusIconColor(EncryptedValue<ulong> userId, string statusId, string color = null) => SetStatusIcon(userId.Get().ToString(), statusId, color);
private void SetStatusIconColor(string userId, string statusId, string color = null) {
Debug("SetStatusIconColor called");
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, new Dictionary<string, object> {
["iconColor"]
= color ?? RESET_KEYWORD
}
, true);
}
[HookMethod(nameof(SetStatusProperty))]
private void SetStatusProperty(ulong userId, string statusId, Dictionary<string, object> properties) => SetStatusProperty(userId.ToString(), statusId, properties);
private void SetStatusProperty(EncryptedValue<ulong> userId, string statusId, Dictionary<string, object> properties) => SetStatusProperty(userId.Get().ToString(), statusId, properties);
private void SetStatusProperty(string userId, string statusId, Dictionary<string, object> properties) {
//Debug("SetStatusProperty called");
if (UsingAdvancedStatus) {
var status = Data.Statuses.GetValueOrDefault(statusId);
if (status == null) {
PrintWarning($"status {statusId} not found");
return;
}
var data = Data.Player.GetValueOrNew(userId).GetValueOrDefault(statusId);
AS_UpdateBar(ulong.Parse(userId), status, data, properties);
return;
}
if (IsStatusIdInvalid(statusId)) {
return;
}
var b = Behaviours.GetValueOrDefault(userId);
if (b == null) {
return;
}
b.SetProperties(statusId, properties, !UsingAdvancedStatus);
}
[HookMethod(nameof(GetDuration))]
private int GetDuration(ulong userId, string statusId) => GetDuration(userId.ToString(), statusId);
private int GetDuration(EncryptedValue<ulong> userId, string statusId) => GetDuration(userId.Get().ToString(), statusId);
private int GetDuration(string userId, string statusId) {
Debug("GetDuration called");
if (IsStatusIdInvalid(statusId)) {
return 0;
}
if (!Data.Player.ContainsKey(userId) || !Data.Player[userId].ContainsKey(statusId)) {
return 0;
}
return Data.Player[userId][statusId].Duration;
}
internal bool IsStatusIdInvalid(string statusId) {
if (Data?.Statuses?.ContainsKey(statusId) ?? true) {
return false;
}
if (Debugging) {
PrintError($"There is no status with the id of '{statusId}'");
}
return true;
}
/* Subscribable Hooks */
/*
* # Called when a status is initially set for a player.* void OnStatusSet(ulong userId, string statusId, int duration)
*
*
* # Called when a status is removed for a player.(When the duration reaches 0).* void OnStatusEnd(ulong userId, string statusId, int duration)
*
*
* # Called when a status property is updated.* # The 'property' parameter can be: 'title', 'titleColor', 'text', 'textColor', 'icon', 'iconColor', 'color'
* void OnStatusUpdate(ulong userId, string statusId, string property, string value);
*/
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
private void CmdToggleStatus(IPlayer player, string command, string[] args) {
var basePlayer = player.Object as BasePlayer;
if (basePlayer == null) {
return;
}
if (!Data.PlayersHiding.Contains(basePlayer.UserIDString)) {
Data.PlayersHiding.Add(basePlayer.UserIDString);
BehaviorManager.HideBehavior(basePlayer);
//BehaviorManager.RemoveBehavior(basePlayer.UserIDString);
Message(basePlayer, Lang(PLUGIN, "hiding", basePlayer.UserIDString));
}
else {
Data.PlayersHiding.Remove(basePlayer.UserIDString);
BehaviorManager.ShowBehavior(basePlayer);
//BehaviorManager.AddBehavior(basePlayer);
Message(basePlayer, Lang(PLUGIN, "showing", basePlayer.UserIDString));
}
}
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
private Configuration config;
private partial class Configuration {
public ulong ChatMessageSteamId = 0;
public string ToggleStatusCommand = "ts";
public bool WarnPlayersThatStatusIsHidden = true;
}
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.Using default configuration values.");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultConfig() => config = new Configuration();
}
}
namespace Oxide.Plugins.SimpleStatusExtensionMethods {
public static class ExtensionMethods {
public static void RemoveAll<TKey, TValue>(this Dictionary<TKey, TValue> dict, Func<KeyValuePair<TKey, TValue>, bool> condition) {
foreach (var cur in dict.Where(condition).ToList()) {
dict.Remove(cur.Key);
}
}
public static void Inc<TKey>(this Dictionary<TKey, float> dict, TKey key) {
dict[key] = Time.realtimeSinceStartup + 3.6f;
}
public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) {
foreach (T element in source) action(element);
}
public static bool IsEmpty(this string text) => string.IsNullOrEmpty(text);
public static bool IsBlank(this string text) => string.IsNullOrWhiteSpace(text);
public static bool IsAssetPath(this string path) => !path.IsBlank() && path.StartsWith("assets/");
public static bool IsItemId(this string path) => !path.IsBlank() && path.StartsWith("itemid:");
public static bool IsRawImage(this string path) => !path.IsBlank() && path.StartsWith("raw:");
public static string AsRawImage(this string path) => !IsRawImage(path) ? "" : $"{path.Substring(4)}";
public static string AsItemId(this string path) => !IsItemId(path) ? "" : path.Substring(7);
public static T GetProperty<T>(this Dictionary<string, object> dict, string key, T defaultValue) => (T)dict.GetValueOrDefault(key, defaultValue);
public static string GetPropertyFloatOrString(this Dictionary<string, object> dict, string key) {
try {
var floatVal = (float)dict.GetValueOrDefault(key);
return floatVal.ToString();
}
catch {
return dict.GetValueOrDefault(key, string.Empty).ToString();
}
}
public static void CopyFrom<V>(this Dictionary<string, V> dict, Dictionary<string, V> other, string key1, string key2, Func<V, V> clean = null) {
if (other.ContainsKey(key2)) {
dict[key1] = clean == null ? other[key2] : clean.Invoke(other[key2]);
}
}
public static V GetValueOrNew<K, V>(this Dictionary<K, V> dict, K key) where V : new() {
var value = dict.GetValueOrDefault(key);
if (value != null) {
return value;
}
dict[key] = new V();
return dict[key];
}
public static string FormatDuration(this int duration) {
var ts = TimeSpan.FromSeconds(duration);
return ts.TotalDays >= 1 ? $"{Math.Floor(ts.TotalDays):0}d {ts.Hours}h {ts.Minutes}m" : ts.TotalHours >= 1 ? $"{Math.Floor(ts.TotalHours):0}h {ts.Minutes}m" : ts.TotalMinutes >= 1 ? $"{Math.Floor(ts.TotalMinutes):0}m" : $"{ts.TotalSeconds:0}";
}
public static string CheckReset(this string value, string defaultVal) {
if (value == SimpleStatus.RESET_KEYWORD) {
return defaultVal;
}
return value;
}
public static T GetProperty<T>(this Dictionary<string, object> dict, string key) => (T)dict.GetValueOrDefault(key, null);
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
#region Advanced Status Integration
public bool UsingAdvancedStatus => AdvancedStatus?.IsLoaded ?? false;
protected Dictionary<string, StatusInfo> AS_CreatedStatuses = new Dictionary<string, StatusInfo>();
protected void AS_DeleteBar(ulong userId, StatusInfo status) {
AdvancedStatus?.Call("DeleteBar", userId, status.Id, status.PluginName);
}
protected void AS_SetDuration(ulong userId, StatusInfo status, int duration) {
if (duration == 0) {
AS_DeleteBar(userId, status);
return;
}
Dictionary<string, object> parameters = new Dictionary<string, object> {
{
"Id", status.Id
}
, {
"Plugin", status.Plugin
}
}
;
if (duration != int.MaxValue) {
parameters["TimeStamp"] = Network.TimeEx.currentTimestamp + duration;
parameters["TimeStampStart"] = Network.TimeEx.currentTimestamp;
parameters["TimeStampDestroy"] = Network.TimeEx.currentTimestamp + duration;
}
AdvancedStatus?.Call("UpdateContent", userId, parameters);
}
protected void AS_CreateBar(ulong userId, StatusInfo status, PlayerStatusInfo data, int duration) {
Dictionary<string, object> parameters = new Dictionary<string, object> {
["Id"]
= status.Id, ["BarType"] = (duration != int.MaxValue && status.Text == null && data?.Text == null) ? "TimeCounter" : "Default", ["Plugin"] = status.PluginName, ["Main_Color"] = RgbaToHex(Opts(data?.Color, status.Color, null, (x) => x == null)), ["Main_Transparency"] = RgbaToAlpha(Opts(data?.Color, status.Color, null, (x) => x == null)), ["Text"] = Lang(status.Plugin, Opts(data?.Title, status.Title, string.Empty, (x) => x == null), userId), ["Text_Color"] = RgbaToHex(Opts(data?.TitleColor, status.TitleColor, null, (x) => x == null)), ["SubText"] = Lang(status.Plugin, Opts(data?.Text, status.Text, null, (x) => x == null), userId), ["SubText_Color"] = RgbaToHex(Opts(data?.TextColor, status.TextColor, null, (x) => x == null)), ["Progress"] = Opts(data?.Progress, status.Progress, null, (x) => x == null), ["Progress_Color"] = RgbaToHex(Opts(data?.ProgressColor, status.ProgressColor, null, (x) => x == null)), ["Text_Offset_Horizontal"] = Opts(data?.Progress, status.Progress, null, (x) => x.IsBlank()) != null ? 6 : 0
}
;
if (duration != int.MaxValue) {
parameters["TimeStamp"] = Network.TimeEx.currentTimestamp + duration;
parameters["TimeStampStart"] = Network.TimeEx.currentTimestamp;
parameters["TimeStampDestroy"] = Network.TimeEx.currentTimestamp + duration;
}
if (!status.ImageLibraryNameOrAssetPath.IsBlank()) {
parameters["Image_Color"] = RgbaToHex(Opts(data?.IconColor, status.IconColor, null, (x) => x == null));
parameters["Image_Transparency"] = RgbaToAlpha(Opts(data?.IconColor, status.IconColor, null, (x) => x == null));
if (status.ImageLibraryNameOrAssetPath?.IsAssetPath() ?? false) {
parameters["Image_Sprite"] = status.ImageLibraryNameOrAssetPath;
}
else {
parameters["Image"] = status.ImageLibraryNameOrAssetPath;
}
}
AdvancedStatus?.Call("CreateBar", userId, parameters);
}
protected void AS_UpdateBar(ulong userId, StatusInfo status, PlayerStatusInfo data, Dictionary<string, object> ssprops) {
Dictionary<string, object> parameters = new Dictionary<string, object> {
["Id"]
= status.Id, ["Plugin"] = status.PluginName,
}
;
parameters.CopyFrom(ssprops, "Main_Color", "color", (x) => RgbaToHex(x.ToString()));
parameters.CopyFrom(ssprops, "Text", "title", (x) => Lang(status.Plugin, x.ToString(), userId));
parameters.CopyFrom(ssprops, "Text_Color", "titleColor", (x) => RgbaToHex(x.ToString()));
parameters.CopyFrom(ssprops, "SubText", "text", (x) => RgbaToHex(x.ToString()));
parameters.CopyFrom(ssprops, "SubText_Color", "textColor", (x) => RgbaToHex(x.ToString()));
parameters.CopyFrom(ssprops, "Progress", "progress", (x) => (float)x);
parameters.CopyFrom(ssprops, "ProgressColor", "progressColor", (x) => RgbaToHex(x.ToString()));
AdvancedStatus?.Call("UpdateContent", userId, parameters);
}
public static T Opts<T>(T one, T two, T three, Func<T, bool> isnull) {
return !isnull.Invoke(one) ? one : !isnull.Invoke(two) ? two : three;
}
public static string RgbaToHex(string rgba) {
if (rgba.IsBlank()) {
return string.Empty;
}
var components = rgba.Split(' ');
int r = (int)(float.Parse(components[0], CultureInfo.InvariantCulture) * 255);
int g = (int)(float.Parse(components[1], CultureInfo.InvariantCulture) * 255);
int b = (int)(float.Parse(components[2], CultureInfo.InvariantCulture) * 255);
int a = (int)(float.Parse(components[3], CultureInfo.InvariantCulture) * 255);
return $"#{r:X2}{g:X2}{b:X2}{a:X2}";
}
public static float RgbaToAlpha(string rgba) {
if (rgba.IsBlank()) {
return 1f;
}
return float.Parse(rgba.Split(' ')[3]);
}
#endregion
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["showing"]
= "Showing statuses.", ["hiding"] = "Hiding statuses.", ["warning"] = "You have statuses hidden.Use the /{0} command to show them again."
}
, this);
}
private string Lang(Plugin plugin, string key, string userId, params object[] args) => key.IsBlank() ? string.Empty : string.Format(lang.GetMessage(key, plugin, userId), args);
private string Lang(Plugin plugin, string key, ulong userId, params object[] args) => key.IsBlank() ? string.Empty : string.Format(lang.GetMessage(key, plugin, userId.ToString()), args);
}
}
namespace Oxide.Plugins {
partial class SimpleStatus : CovalencePlugin {
public static class BehaviorManager {
public static StatusBehaviour AddBehavior(BasePlayer basePlayer) {
if (basePlayer == null) {
return null;
}
if (!PLUGIN.Behaviours.ContainsKey(basePlayer.UserIDString)) {
var obj = basePlayer.gameObject.AddComponent<StatusBehaviour>();
PLUGIN.Behaviours.Add(basePlayer.UserIDString, obj);
Debug($"Resuming statuses for {basePlayer.displayName}..");
if (Data.Player.ContainsKey(basePlayer.UserIDString)) {
foreach (var data in Data.Player[basePlayer.UserIDString]) {
var statusName = data.Key;
Debug($"Resuming {data.Key} {data.Value.Duration} {data.Value.Title} {data.Value.Text} {data.Value.EndTime.HasValue} {data.Value.DurationUntilEndTime}");
obj.SetStatus(data.Key, data.Value.Duration, !data.Value.EndTime.HasValue, true);
}
}
return obj;
}
return PLUGIN.Behaviours[basePlayer.UserIDString];
}
public static void RemoveBehavior(string userid) {
var obj = PLUGIN.Behaviours.GetValueOrDefault(userid);
if (obj == null) {
return;
}
UnityEngine.Object.Destroy(obj);
PLUGIN.Behaviours.Remove(userid);
if (Data.Player.ContainsKey(userid)) {
foreach (var data in Data.Player[userid]) {
data.Value.Drawn = false;
}
}
}
public static void HideBehavior(BasePlayer basePlayer) {
if (basePlayer == null) {
return;
}
var obj = PLUGIN.Behaviours.GetValueOrDefault(basePlayer.UserIDString);
if (obj == null) {
return;
}
Debug("HideBehavior Called");
obj.isHidden = true;
var data = Data.Player.GetValueOrDefault(basePlayer.UserIDString);
if (data != null) {
foreach (var kvp in data) {
kvp.Value.Drawn = false;
}
}
CuiHelper.DestroyUi(basePlayer, UI_Base_ID);
}
public static void ShowBehavior(BasePlayer basePlayer) {
if (basePlayer == null || PLUGIN.UsingAdvancedStatus) {
return;
}
var obj = PLUGIN.Behaviours.GetValueOrDefault(basePlayer.UserIDString);
if (obj == null) {
return;
}
Debug("ShowBehavior Called");
obj.isHidden = false;
CuiHelper.DestroyUi(basePlayer, UI_Base_ID);
CuiHelper.AddUi(basePlayer, PLUGIN.UI_Base());
obj.rowsNeedUpdate = true;
}
}
private void SetStatusForOfflinePlayer(string userId, string statusId, int duration, bool pauseOffline) {
if (duration <= 0) {
var data = Data.Player.GetValueOrDefault(userId);
if (data == null) {
return;
}
Debug($"Remove status {statusId} for offline player {userId}");
data.Remove(statusId);
if (data.Count <= 0) {
Data.Player.Remove(userId);
}
return;
}
if (!Data.Player.ContainsKey(userId)) {
Data.Player[us
// ... [Code preview truncated due to length. Full source in attached file] ...