Jump to content

1 Screenshot

  • 81
  • 5
  • 31.11 kB
  • Update details
    v1.0.0
    Released
    Download size31.11 kB
    Total versions1
    Freshness Updated today

depends on

Required files or plugins needed for this resource to work properly.

Works with

Compatible add-ons, packages, or tools that pair well with this resource.

About Custom Vitals Manager

CustomVitalsManager is a lightweight developer-focused Rust plugin for creating and managing custom player status effects using Rust’s native CustomVitalsInfo system. It allows other plugins to display custom vitals with icons, colors, left/right text, timers, active states, and automatic expiry handling directly in the player’s native status/vitals UI.

⭐Features

  • Native Rust custom vitals support through ProtoBuf.CustomVitalInfo
  • Shared/global vitals visible to all connected players
  • Player-specific custom vitals
  • Optional automatic expiry/removal
  • Manual update, remove, clear, and resend APIs
  • Developer hooks for blocking, tracking, and reacting to vital changes
  • Uses pooled ProtoBuf objects for cleaner server-side memory handling

🚀Developer API

|--------------------------------------------------------------------------
| CREATE:
| CustomVitalInfo API_RentVitalInfo(
|     string icon = null,
|     string iconColor = null,
|     string backgroundColor = null,
|     string leftText = null,
|     string leftTextColor = null,
|     string rightText = null,
|     string rightTextColor = null,
|     int timeLeft = 0,
|     bool active = true
| );
|
| CustomVitalInfo API_RentVitalInfoRaw(
|     string icon = null,
|     Color iconColor = default(Color),
|     Color backgroundColor = default(Color),
|     string leftText = null,
|     Color leftTextColor = default(Color),
|     string rightText = null,
|     Color rightTextColor = default(Color),
|     int timeLeft = 0,
|     bool active = true
| );
|
|--------------------------------------------------------------------------
| ADD:
| uint API_AddVital(
|     BasePlayer player,
|     CustomVitalInfo vital,
|     float expiry = 0f,
|     bool sendUpdate = true
| );
|
| uint API_AddVital(
|     BasePlayer player,
|     string icon = null,
|     string iconColor = null,
|     string backgroundColor = null,
|     string leftText = null,
|     string leftTextColor = null,
|     string rightText = null,
|     string rightTextColor = null,
|     int timeLeft = 0,
|     bool active = true,
|     float expiry = 0f,
|     bool sendUpdate = true
| );
|
| uint API_AddPlayerVital(
|     ulong playerId,
|     string icon = null,
|     string iconColor = null,
|     string backgroundColor = null,
|     string leftText = null,
|     string leftTextColor = null,
|     string rightText = null,
|     string rightTextColor = null,
|     int timeLeft = 0,
|     bool active = true,
|     float expiry = 0f,
|     bool sendUpdate = true
| );
|
| uint API_AddSharedVital(
|     CustomVitalInfo vital,
|     float expiry = 0f,
|     bool sendUpdate = true
| );
|
| uint API_AddSharedVital(
|     string icon = null,
|     string iconColor = null,
|     string backgroundColor = null,
|     string leftText = null,
|     string leftTextColor = null,
|     string rightText = null,
|     string rightTextColor = null,
|     int timeLeft = 0,
|     bool active = true,
|     float expiry = 0f,
|     bool sendUpdate = true
| );
|
|--------------------------------------------------------------------------
| UPDATE:
| bool API_UpdateVitalText(BasePlayer player, uint id, string leftText = null, string rightText = null, bool sendUpdate = true);
| bool API_UpdateVitalText(ulong playerId, uint id, string leftText = null, string rightText = null, bool sendUpdate = true);
| bool API_UpdateSharedVitalText(uint id, string leftText = null, string rightText = null, bool sendUpdate = true);
|
| bool API_SetVitalActive(BasePlayer player, uint id, bool active, bool sendUpdate = true);
| bool API_SetVitalActive(ulong playerId, uint id, bool active, bool sendUpdate = true);
| bool API_SetSharedVitalActive(uint id, bool active, bool sendUpdate = true);
|
| bool API_SetVitalTimeLeft(BasePlayer player, uint id, int timeLeft, bool sendUpdate = true);
| bool API_SetVitalTimeLeft(ulong playerId, uint id, int timeLeft, bool sendUpdate = true);
| bool API_SetSharedVitalTimeLeft(uint id, int timeLeft, bool sendUpdate = true);
|
| bool API_SetVitalExpiry(BasePlayer player, uint id, float expiry, bool restart = true);
| bool API_SetVitalExpiry(ulong playerId, uint id, float expiry, bool restart = true);
| bool API_SetSharedVitalExpiry(uint id, float expiry, bool restart = true);
|
|--------------------------------------------------------------------------
| REMOVE:
| bool API_RemoveVital(BasePlayer player, uint id, bool sendUpdate = true);
| bool API_RemoveVital(ulong playerId, uint id, bool sendUpdate = true);
| bool API_RemoveSharedVital(uint id, bool sendUpdate = true);
|
|--------------------------------------------------------------------------
| CLEAR:
| void API_ClearVitals(BasePlayer player, bool sendUpdate = true);
| void API_ClearPlayerVitals(BasePlayer player, bool sendUpdate = true);
| void API_ClearPlayerVitals(ulong playerId, bool sendUpdate = true);
| void API_ClearSharedVitals(bool sendUpdate = true);
|
|--------------------------------------------------------------------------
| SEND:
| void API_SendVitals(BasePlayer player);
| void API_SendVitals(ulong playerId);
| void API_SendVitalsToEveryone();
|
|--------------------------------------------------------------------------
| CHECK / INFO:
| int API_GetSharedVitalCount();
| int API_GetPlayerVitalCount(BasePlayer player);
| int API_GetPlayerVitalCount(ulong playerId);
| int API_GetTotalPlayerVitalCount(BasePlayer player);
| int API_GetTotalPlayerVitalCount(ulong playerId);
|
| bool API_HasVital(BasePlayer player, uint id);
| bool API_HasVital(ulong playerId, uint id);
| bool API_HasSharedVital(uint id);
|
| Dictionary<string, object> API_GetVitalInfo(BasePlayer player, uint id);
| Dictionary<string, object> API_GetVitalInfo(ulong playerId, uint id);
| Dictionary<string, object> API_GetSharedVitalInfo(uint id);
|
|--------------------------------------------------------------------------
| HOOKS:
| object CanAddCustomVital(BasePlayer player, CustomVitalInfo vital, bool shared);
| void OnCustomVitalAdded(BasePlayer player, uint id, bool shared, CustomVitalInfo info);
| void OnCustomVitalUpdated(BasePlayer player, uint id, bool shared, CustomVitalInfo info);
| void OnCustomVitalRemoved(BasePlayer player, uint id, bool shared);
| void OnCustomVitalsCleared(BasePlayer player, bool shared);
| void OnCustomVitalsSent(BasePlayer player, int count);
|
|--------------------------------------------------------------------------
Quote

EXAMPLE PLUGIN

/*
|--------------------------------------------------------------------------
| CustomVitalsManager Example Plugin
|--------------------------------------------------------------------------
| This plugin demonstrates:
|
| - How to preload icons with ImageLibrary
| - How to get the ImageLibrary image ID with GetImage
| - How to pass that image ID into CustomVitalsManager as string icon
| - How to add player-specific custom vitals
| - How to add shared/global custom vitals
| - How to update/remove vitals safely
|--------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using Oxide.Core.Plugins;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("CustomVitalsExample", "ifte", "1.0.0")]
    [Description("Example plugin showing how to use CustomVitalsManager with ImageLibrary icons.")]
    public class CustomVitalsExample : RustPlugin
    {
        #region Plugin References

        [PluginReference]
        private Plugin CustomVitalsManager, ImageLibrary;

        #endregion

        #region Fields

        /*
        |--------------------------------------------------------------------------
        | Image keys
        |--------------------------------------------------------------------------
        | These keys are what we register into ImageLibrary.
        |
        | You can use either:
        | - A normal key name, example: "cve.boost"
        | - The URL itself as the key
        |
        | Best practice:
        | Use clean custom keys, then map each key to a URL.
        |--------------------------------------------------------------------------
        */

        private const string IconBoost = "cve.boost";
        private const string IconBleeding = "cve.bleeding";
        private const string IconRadiation = "cve.radiation";
        private const string IconEvent = "cve.event";

        /*
        |--------------------------------------------------------------------------
        | Image URLs
        |--------------------------------------------------------------------------
        | Replace these URLs with your own hosted PNG icons.
        |
        | Recommended:
        | - PNG
        | - Transparent background
        | - 128x128 or 256x256
        | - Simple white icon works best because CustomVitalsManager can recolor it
        |--------------------------------------------------------------------------
        */

        private readonly Dictionary<string, string> _images = new Dictionary<string, string>
        {
            [IconBoost] = "https://i.imgur.com/YOUR_BOOST_ICON.png",
            [IconBleeding] = "https://i.imgur.com/YOUR_BLEEDING_ICON.png",
            [IconRadiation] = "https://i.imgur.com/YOUR_RADIATION_ICON.png",
            [IconEvent] = "https://i.imgur.com/YOUR_EVENT_ICON.png"
        };

        /*
        |--------------------------------------------------------------------------
        | Runtime vital storage
        |--------------------------------------------------------------------------
        | Store the returned vital IDs if you want to update/remove them later.
        |--------------------------------------------------------------------------
        */

        private readonly Dictionary<ulong, uint> _boostVitals = new Dictionary<ulong, uint>();
        private readonly Dictionary<ulong, uint> _bleedingVitals = new Dictionary<ulong, uint>();

        private uint _sharedEventVital;

        #endregion

        #region Oxide Hooks

        private void OnServerInitialized()
        {
            if (!CheckDependencies())
                return;

            LoadImages();

            /*
            |--------------------------------------------------------------------------
            | Optional shared vital example
            |--------------------------------------------------------------------------
            | Delayed slightly so ImageLibrary has time to register/download icons.
            |--------------------------------------------------------------------------
            */

            timer.Once(3f, StartSharedEventVital);
        }

        private void Unload()
        {
            if (CustomVitalsManager == null)
                return;

            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                CustomVitalsManager.Call("API_ClearPlayerVitals", player, true);
            }

            if (_sharedEventVital != 0)
            {
                CustomVitalsManager.Call("API_RemoveSharedVital", _sharedEventVital, true);
                _sharedEventVital = 0;
            }
        }

        private void OnPlayerDisconnected(BasePlayer player, string reason)
        {
            if (player == null)
                return;

            _boostVitals.Remove(player.userID);
            _bleedingVitals.Remove(player.userID);
        }

        #endregion

        #region Commands

        [ChatCommand("vitalboost")]
        private void CmdVitalBoost(BasePlayer player, string command, string[] args)
        {
            if (!CanUse(player))
                return;

            GiveBoostVital(player);
            SendReply(player, "Boost custom vital added for 60 seconds.");
        }

        [ChatCommand("vitalbleed")]
        private void CmdVitalBleed(BasePlayer player, string command, string[] args)
        {
            if (!CanUse(player))
                return;

            GiveBleedingVital(player);
            SendReply(player, "Bleeding custom vital added for 20 seconds.");
        }

        [ChatCommand("vitalremove")]
        private void CmdVitalRemove(BasePlayer player, string command, string[] args)
        {
            if (!CanUse(player))
                return;

            RemovePlayerVitals(player);
            SendReply(player, "Your example custom vitals were removed.");
        }

        [ChatCommand("vitalevent")]
        private void CmdVitalEvent(BasePlayer player, string command, string[] args)
        {
            if (!CanUse(player))
                return;

            if (_sharedEventVital == 0)
            {
                StartSharedEventVital();
                SendReply(player, "Shared event vital started.");
                return;
            }

            StopSharedEventVital();
            SendReply(player, "Shared event vital stopped.");
        }

        #endregion

        #region ImageLibrary

        private void LoadImages()
        {
            if (ImageLibrary == null)
                return;

            foreach (KeyValuePair<string, string> entry in _images)
            {
                string key = entry.Key;
                string url = entry.Value;

                /*
                |--------------------------------------------------------------------------
                | ImageLibrary AddImage
                |--------------------------------------------------------------------------
                | Common ImageLibrary usage:
                |
                | ImageLibrary.Call("AddImage", url, key);
                |
                | url = direct image URL
                | key = the name/id you will use later with GetImage
                |--------------------------------------------------------------------------
                */

                ImageLibrary.Call("AddImage", url, key);
            }
        }

        private string GetImageId(string imageKey)
        {
            /*
            |--------------------------------------------------------------------------
            | THIS IS THE IMPORTANT PART
            |--------------------------------------------------------------------------
            |
            | CustomVitalsManager's string icon should be the ImageLibrary result:
            |
            |     string icon = (string)ImageLibrary.Call("GetImage", imageKey);
            |
            | Do NOT pass:
            |     "https://i.imgur.com/icon.png"
            |
            | Do pass:
            |     ImageLibrary.GetImage result
            |
            | Why:
            | CustomVitalsManager stores your icon string directly into:
            |
            |     CustomVitalInfo.icon
            |
            | Rust's custom vital UI expects the resolved image identifier, not a raw
            | web URL, when using custom downloaded images.
            |--------------------------------------------------------------------------
            */

            if (ImageLibrary == null)
                return string.Empty;

            object result = ImageLibrary.Call("GetImage", imageKey);

            if (result == null)
            {
                PrintWarning($"ImageLibrary returned null for image key '{imageKey}'.");
                return string.Empty;
            }

            string imageId = result.ToString();

            if (string.IsNullOrEmpty(imageId))
            {
                PrintWarning($"ImageLibrary returned an empty image ID for image key '{imageKey}'.");
                return string.Empty;
            }

            return imageId;
        }

        #endregion

        #region CustomVitalsManager Usage

        private void GiveBoostVital(BasePlayer player)
        {
            if (CustomVitalsManager == null || player == null)
                return;

            RemoveBoostVital(player);

            string icon = GetImageId(IconBoost);
            if (string.IsNullOrEmpty(icon))
            {
                SendReply(player, "Boost icon is not loaded yet. Try again in a few seconds.");
                return;
            }

            /*
            |--------------------------------------------------------------------------
            | API_AddVital
            |--------------------------------------------------------------------------
            |
            | Parameter order:
            |
            | BasePlayer player
            | string icon
            | string iconColor
            | string backgroundColor
            | string leftText
            | string leftTextColor
            | string rightText
            | string rightTextColor
            | int timeLeft
            | bool active
            | float expiry
            | bool sendUpdate
            |--------------------------------------------------------------------------
            */

            uint vitalId = Convert.ToUInt32(CustomVitalsManager.Call(
                "API_AddVital",
                player,
                icon,           // ImageLibrary GetImage ID
                "#FFD479",      // Icon color
                "#000000AA",    // Background color
                "BOOST",        // Left text
                "#FFD479",      // Left text color
                "2x / 60s",     // Right text
                "#FFFFFF",      // Right text color
                60,             // Native countdown timer
                true,           // Active
                60f,            // Auto-remove after 60 seconds
                true            // Send update instantly
            ));

            if (vitalId == 0)
            {
                SendReply(player, "Failed to add boost vital.");
                return;
            }

            _boostVitals[player.userID] = vitalId;
        }

        private void GiveBleedingVital(BasePlayer player)
        {
            if (CustomVitalsManager == null || player == null)
                return;

            RemoveBleedingVital(player);

            string icon = GetImageId(IconBleeding);
            if (string.IsNullOrEmpty(icon))
            {
                SendReply(player, "Bleeding icon is not loaded yet. Try again in a few seconds.");
                return;
            }

            uint vitalId = Convert.ToUInt32(CustomVitalsManager.Call(
                "API_AddVital",
                player,
                icon,           // ImageLibrary GetImage ID
                "#FF4444",      // Icon color
                "#180000DD",    // Background color
                "BLEEDING",     // Left text
                "#FF4444",      // Left text color
                "20s",          // Right text
                "#FFFFFF",      // Right text color
                20,             // Native countdown timer
                true,           // Active
                20f,            // Auto-remove after 20 seconds
                true            // Send update instantly
            ));

            if (vitalId == 0)
            {
                SendReply(player, "Failed to add bleeding vital.");
                return;
            }

            _bleedingVitals[player.userID] = vitalId;
        }

        private void StartSharedEventVital()
        {
            if (CustomVitalsManager == null)
                return;

            if (_sharedEventVital != 0)
                return;

            string icon = GetImageId(IconEvent);
            if (string.IsNullOrEmpty(icon))
            {
                PrintWarning("Shared event icon is not loaded yet.");
                return;
            }

            /*
            |--------------------------------------------------------------------------
            | API_AddSharedVital
            |--------------------------------------------------------------------------
            | Shared vitals are visible to every connected player.
            |--------------------------------------------------------------------------
            */

            _sharedEventVital = Convert.ToUInt32(CustomVitalsManager.Call(
                "API_AddSharedVital",
                icon,               // ImageLibrary GetImage ID
                "#FFAA33",          // Icon color
                "#000000AA",        // Background color
                "SERVER EVENT",     // Left text
                "#FFAA33",          // Left text color
                "DOUBLE GATHER",    // Right text
                "#FFFFFF",          // Right text color
                3600,               // Native countdown timer
                true,               // Active
                3600f,              // Auto-remove after 1 hour
                true                // Send update to everyone
            ));

            if (_sharedEventVital == 0)
                PrintWarning("Failed to start shared event vital.");
        }

        private void StopSharedEventVital()
        {
            if (CustomVitalsManager == null || _sharedEventVital == 0)
                return;

            CustomVitalsManager.Call("API_RemoveSharedVital", _sharedEventVital, true);
            _sharedEventVital = 0;
        }

        private void RemoveBoostVital(BasePlayer player)
        {
            if (CustomVitalsManager == null || player == null)
                return;

            uint vitalId;
            if (!_boostVitals.TryGetValue(player.userID, out vitalId))
                return;

            CustomVitalsManager.Call("API_RemoveVital", player, vitalId, true);
            _boostVitals.Remove(player.userID);
        }

        private void RemoveBleedingVital(BasePlayer player)
        {
            if (CustomVitalsManager == null || player == null)
                return;

            uint vitalId;
            if (!_bleedingVitals.TryGetValue(player.userID, out vitalId))
                return;

            CustomVitalsManager.Call("API_RemoveVital", player, vitalId, true);
            _bleedingVitals.Remove(player.userID);
        }

        private void RemovePlayerVitals(BasePlayer player)
        {
            RemoveBoostVital(player);
            RemoveBleedingVital(player);
        }

        #endregion

        #region Developer Hook Examples

        private object CanAddCustomVital(BasePlayer player, ProtoBuf.CustomVitalInfo vital, bool shared)
        {
            /*
            |--------------------------------------------------------------------------
            | Return false to block another plugin from adding a vital.
            | Return null to allow it.
            |--------------------------------------------------------------------------
            */

            return null;
        }

        private void OnCustomVitalAdded(BasePlayer player, uint id, bool shared, ProtoBuf.CustomVitalInfo info)
        {
            Puts($"Custom vital added | ID: {id} | Shared: {shared}");
        }

        private void OnCustomVitalRemoved(BasePlayer player, uint id, bool shared)
        {
            Puts($"Custom vital removed | ID: {id} | Shared: {shared}");
        }

        #endregion

        #region Helpers

        private bool CheckDependencies()
        {
            bool valid = true;

            if (CustomVitalsManager == null)
            {
                PrintError("CustomVitalsManager is not loaded. This example plugin cannot run.");
                valid = false;
            }

            if (ImageLibrary == null)
            {
                PrintError("ImageLibrary is not loaded. Icons will not work.");
                valid = false;
            }

            return valid;
        }

        private bool CanUse(BasePlayer player)
        {
            if (player == null)
                return false;

            if (CustomVitalsManager == null)
            {
                SendReply(player, "CustomVitalsManager is not loaded.");
                return false;
            }

            if (ImageLibrary == null)
            {
                SendReply(player, "ImageLibrary is not loaded.");
                return false;
            }

            return true;
        }

        #endregion
    }
}

Special thanks to CarbonMod
https://carbonmod.gg/

💬 Support


image.png.c5f070b6c5521b07d37ba87db201425d.png


User Feedback

About Us

Codefling is the largest marketplace for plugins, maps, tools, and more, making it easy for customers to discover new content and for creators to monetize their work.

Downloads
2.5m
Total downloads
Customers
11.3k
Customers served
Files Sold
161.3k
Total sales
Payments
3.5m
Processed total
×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.