Skip to content
RustPluginGenerator

OnEngineStatsRefresh

OnEngineStatsRefresh is called by VehicleModuleEngine.RefreshPerformanceStats right before the game recalculates a modular car engine's performance from its installed parts. Returning a non-null value skips the vanilla recalculation.

Signature
object OnEngineStatsRefresh(VehicleModuleEngine vehicleModuleEngine, Rust.Modular.EngineStorage engineStorage)

Parameters

Hook parameters
ParameterTypeDescription
vehicleModuleEngineVehicleModuleEngineThe VehicleModuleEngine instance whose performance stats are being recalculated. Use it to read IsUsable, the current performance fractions, and its parent entity (the modular car it is installed in).
engineStorageRust.Modular.EngineStorageThe EngineStorage container that holds the installed engine parts (crankshaft, pistons, valves, spark plugs). It can be null when the engine module has no storage assigned.

Return value

Returning null (or letting the method fall through) lets the game recalculate engine performance normally. Returning any non-null object stops the original method body, so the engine keeps its existing IsUsable and performance fractions; the value itself is not used as a result because RefreshPerformanceStats returns void.

How it works

This hook fires inside VehicleModuleEngine.RefreshPerformanceStats(EngineStorage engineStorage). That method runs when an engine module's part layout changes: parts inserted or removed, an engine storage linked or cleared, and on load of a car with an engine module. The game calls the hook before it computes anything, so at the call site the engine's stats still reflect the previous state.

vehicleModuleEngine is the engine module itself. Read IsUsable after a refresh, and use its parent to identify the car. engineStorage is the container the game is about to evaluate; it is null when the module has no storage, and the original code sets IsUsable = false and drops the performance fractions in that case.

Narrowing by type is not useful here: the module parameter is always a VehicleModuleEngine and the storage is always an EngineStorage or null, so declare the exact signature. If you need to read the resulting values, do it after the vanilla code has run rather than inside this hook. Keep the method cheap, since a refresh can also happen while players are editing a car in the world.

Example plugin: Lock engine stats so installed parts stay at peak output

EngineStatLocker.cs
using UnityEngine;
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;

namespace Oxide.Plugins
{
    [Info("Engine Stat Locker", "RustPluginGenerator", "1.0.0")]
    [Description("Forces modular car engine performance to peak values by skipping the vanilla stat recalculation.")]
    public class EngineStatLocker : RustPlugin
    {
        private const string PermUse = "enginestatlocker.toggle";

        private PluginConfig config;

        private class PluginConfig
        {
            [JsonProperty("Peak performance locked")]
            public bool PeakLocked { get; set; } = true;

            [JsonProperty("Performance fraction when locked")]
            public float Fraction { get; set; } = 1f;
        }

        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>
            {
                ["ToggleOn"] = "Engine stat lock enabled: performance set to {0}.",
                ["ToggleOff"] = "Engine stat lock disabled: vanilla engine calculation restored.",
                ["NoPermission"] = "You do not have permission to use this command."
            }, this);
        }

        private void Init()
        {
            permission.RegisterPermission(PermUse, this);
        }

        private object OnEngineStatsRefresh(VehicleModuleEngine vehicleModuleEngine, Rust.Modular.EngineStorage engineStorage)
        {
            if (!config.PeakLocked || vehicleModuleEngine == null || engineStorage == null) return null;
            if (engineStorage.inventory == null || engineStorage.inventory.itemList.Count == 0) return null;

            var fraction = UnityEngine.Mathf.Clamp01(config.Fraction);
            vehicleModuleEngine.IsUsable = true;
            vehicleModuleEngine.PerformanceFractionAcceleration = fraction;
            vehicleModuleEngine.PerformanceFractionTopSpeed = fraction;

            // Non-null return tells Oxide the work is done, so vanilla keeps our numbers.
            return true;
        }

        [ChatCommand("enginelock")]
        private void CmdEngineLock(BasePlayer player, string command, string[] args)
        {
            if (player == null) return;
            if (!permission.UserHasPermission(player.UserIDString, PermUse))
            {
                player.ChatMessage(Msg("NoPermission", player.UserIDString));
                return;
            }

            config.PeakLocked = !config.PeakLocked;
            SaveConfig();
            player.ChatMessage(Msg(config.PeakLocked ? "ToggleOn" : "ToggleOff", player.UserIDString, config.Fraction));
        }

        private string Msg(string key, string userId = null, params object[] args) =>
            string.Format(lang.GetMessage(key, this, userId), args);
    }
}

The plugin intercepts OnEngineStatsRefresh for every engine module. When the feature is enabled in config and the engine actually has an EngineStorage with at least one part, it sets IsUsable to true on the module, writes the configured Fraction (clamped between 0 and 1) to both PerformanceFractionAcceleration and PerformanceFractionTopSpeed, then returns a non-null object. The non-null return makes Oxide skip the vanilla recalculation, so the values written by the plugin are the ones the car keeps after editing parts. A chat command checks the enginestatlocker.toggle permission, toggles the feature and saves the state to the config file. Admins can flip it back off at any time, after which engines use the vanilla calculation on the next part change.

Common use cases

  • Performance floors for part damage

    Force a minimum performance fraction so that cars with worn or low-grade parts still drive predictably, instead of letting the vanilla calculation produce near-zero output.

  • Server-wide engine tuning

    Override the vanilla formula entirely to make all modular car engines accelerate equally, for example on a racing or event server.

  • Break-in stage before the first start

    Set a reduced performance value after a part swap and let another system raise it later, giving the engine a warm-up period that ends when the car has been driven a set distance.

Pitfalls

  • Returning non-null freezes all stats

    A non-null return skips the vanilla method, which also handles the empty-storage case. If you return a value for a module without storage, you must set IsUsable = false and reset the fractions yourself.

  • Fires outside of active driving

    Refreshes happen while players edit a car, on plugin-triggered module changes and on load, so never send chat messages or print warnings from this hook.

  • Only affects the engine module

    Other module stats and the car's overall handling are computed elsewhere. Changing engine fractions does not adjust fuel use or the gearbox.

Build a plugin with OnEngineStatsRefresh

Describe what should happen and get a compiled plugin that uses this hook.

Prompt: Performance floors for part damage using the OnEngineStatsRefresh hook, with a config file and a permission
Generate this plugin

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 OnEngineStatsRefresh

Generate