OnPlayerMetabolize
OnPlayerMetabolize is called from PlayerMetabolism.ServerUpdate, after the base metabolism update runs and before the network snapshot is prepared. It fires regularly for each connected player while the metabolism simulation ticks.
void OnPlayerMetabolize(PlayerMetabolism playerMetabolism, BaseCombatEntity ownerEntity, float delta)Parameters
| Parameter | Type | Description |
|---|---|---|
playerMetabolism | PlayerMetabolism | The PlayerMetabolism component being updated this tick. Its fields such as calories, hydration, temperature, bleeding, radiation and oxygen are the live calorie/health simulation state for the owner player. |
ownerEntity | BaseCombatEntity | The BaseCombatEntity that owns the metabolism, in practice the BasePlayer whose ServerUpdate drove the call. Cast or check it as BasePlayer before touching player-only members. |
delta | float | Seconds elapsed since the previous metabolism update, used by the game to scale calorie burn, hydration loss and health effects. Guard against zero or negative values before dividing by it. |
Return value
The call site ignores any return value (the game continues from its own ServerUpdate result), so returning null or a value makes no difference. Return nothing and treat the hook as an observation point.
How it works
The hook fires inside PlayerMetabolism.ServerUpdate(BaseCombatEntity ownerEntity, float delta). The game first runs base.ServerUpdate, then calls Interface.CallHook("OnPlayerMetabolize", this, ownerEntity, delta), and afterwards checks whether the update is dirty or needs a full snapshot before sending the state to the client. Because this sits inside the per-tick metabolism update, it fires repeatedly for every connected player while the server runs, not once per event.
Use it when you need a recurring view of the metabolism without writing your own timer: playerMetabolism.calories, hydration, temperature, radiationPoisoning, bleeding, oxygen and the related fields are already advanced for this tick when your hook runs. ownerEntity is the owner being simulated and should be checked as a BasePlayer before using player-only APIs; delta lets you scale your own logic to time.
Because the hook is high-frequency, keep the body cheap. Do not write chat, spawn entities or run expensive loops here without a cheap guard. If you only need occasional checks, throttle yourself using UnityEngine.Time.realtimeSinceStartup or a per-player cooldown map.
Example plugin: Comfort warning when players run low on food or water
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Metabolism Warnings", "RustPluginGenerator", "1.0.0")]
[Description("Warns players in chat when their calories or hydration drop below configured thresholds")]
public class MetabolismWarnings : RustPlugin
{
private const string PermWarn = "metabolismwarnings.warn";
private PluginConfig config;
private readonly Dictionary<ulong, float> nextWarn = new Dictionary<ulong, float>();
private class PluginConfig
{
[JsonProperty("Calories threshold")]
public float CaloriesThreshold = 250f;
[JsonProperty("Hydration threshold")]
public float HydrationThreshold = 200f;
[JsonProperty("Warning cooldown seconds")]
public float CooldownSeconds = 60f;
}
protected override void LoadDefaultConfig() => config = new PluginConfig();
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<PluginConfig>();
if (config == null) throw new Exception();
}
catch
{
PrintWarning("Configuration file is invalid, using defaults");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["LowCalories"] = "You are starving. Eat something before you start losing health.",
["LowHydration"] = "You are dehydrated. Drink water before you start losing health."
}, this);
}
private string Msg(string key, string userId = null) => lang.GetMessage(key, this, userId);
private void Init()
{
permission.RegisterPermission(PermWarn, this);
}
private void OnPlayerMetabolize(PlayerMetabolism playerMetabolism, BaseCombatEntity ownerEntity, float delta)
{
if (playerMetabolism == null || ownerEntity == null) return;
BasePlayer player = ownerEntity as BasePlayer;
if (player == null || !player.IsConnected || player.IsDead() || player.IsSleeping()) return;
if (!permission.UserHasPermission(player.UserIDString, PermWarn)) return;
float calories = playerMetabolism.calories.value;
float hydration = playerMetabolism.hydration.value;
if (calories > config.CaloriesThreshold && hydration > config.HydrationThreshold) return;
ulong userId = player.userID;
float now = Time.realtimeSinceStartup;
float next;
if (nextWarn.TryGetValue(userId, out next) && now < next) return;
nextWarn[userId] = now + config.CooldownSeconds;
if (calories <= config.CaloriesThreshold)
{
player.ChatMessage(Msg("LowCalories", player.UserIDString));
}
else
{
player.ChatMessage(Msg("LowHydration", player.UserIDString));
}
}
private void Unload()
{
nextWarn.Clear();
}
}
}The plugin watches the metabolism hook and only acts when a player's calories or hydration drop below a configurable threshold. A per-player cooldown dictionary prevents the busy hook from spamming chat: it stores the next allowed UnityEngine.Time.realtimeSinceStartup per user id and returns early otherwise. ownerEntity is checked as a BasePlayer and skipped for dead, sleeping or disconnected players. Warnings go through the language system so admins can translate them, and the cooldown map is cleared in Unload so no stale state survives a reload. Config lets you tune the thresholds and cooldown seconds without touching code.
Common use cases
Starvation and dehydration alerts
Warn players in chat when calories or hydration fall below a threshold before real damage starts, giving them a chance to eat or drink.
Temperature and radiation monitoring
Detect prolonged cold or radiation exposure and apply server-specific side effects or notifications instead of running your own polling timer.
Custom survival balancing
Read the metabolism fields each tick to build a per-player survival log or drive an external economy payment for staying fed and hydrated.
Pitfalls
It is not a per-event callback
The hook fires for every connected player on a recurring tick. Without a cooldown or cheap guard, chat output, effects and entity spawning here will flood the server and clients.
ownerEntity needs a type check
The parameter is declared as BaseCombatEntity. Cast or check it as BasePlayer before using player-only members, and skip it when null or destroyed.
Do not try to block the update
The call site discards the return value, so returning a value cannot stop or modify the metabolism update. Change state through the metabolism object or the player instead.
Build a plugin with OnPlayerMetabolize
Describe what should happen and get a compiled plugin that uses this hook.
Edit the prompt on the next screen. 2 free plugins a month, no card.
Last updated Oct 26, 2026. Found a mistake? Email support@rustplugingenerator.com.
Build a plugin with OnPlayerMetabolize
Generate