Skip to content
RustPluginGenerator

OnFreeableContainerRelease

OnFreeableContainerRelease is called from FreeableLootContainer.Release just before the container is freed from its buoyancy/kinematic hold. Returning a non-null value cancels the rest of the release.

Signature
object OnFreeableContainerRelease(FreeableLootContainer freeableLootContainer, BasePlayer ply)

Parameters

Hook parameters
ParameterTypeDescription
freeableLootContainerFreeableLootContainerThe FreeableLootContainer entity being released (the floating loot object such as a supply drop or other freeable loot). Use it to read position, net.ID, flags or skin.
plyBasePlayerThe BasePlayer that triggered the release. It can be null if the release was not caused by a player, so check it before using it.

Return value

Returning null (or nothing meaningful) lets Release continue and the container is freed normally. Returning any non-null object skips the rest of the original method, so the container stays anchored and its buoyancy/flags are not updated.

How it works

This hook fires inside FreeableLootContainer.Release(BasePlayer), which is the point where a floating freeable loot container stops being anchored: the game turns off the kinematic flag on the rigidbody, re-enables buoyancy and updates its flags. It runs on the server only and is triggered when the game calls Release on a freeable loot container, passing the container and the player involved.

The freeableLootContainer parameter is the entity itself; use net.ID.Value, transform.position or ShortPrefabName to identify it and to decide what to do. The ply parameter is the player that caused the release and may be null, so always null-check it before calling anything on it.

Declaring BasePlayer for the second parameter is the natural type; there is only one overload, so you do not gain anything by narrowing types here. Because the hook can cancel the release, it is the place to enforce rules such as keeping a crate anchored, notifying nearby players, or recording the event.

Example plugin: Keep event loot containers anchored until a timer expires

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

namespace Oxide.Plugins
{
    [Info("AnchoredLootRelease", "RustPluginGenerator", "1.0.0")]
    [Description("Keeps freeable loot containers anchored for a configurable cooldown after release is triggered.")]
    public class AnchoredLootRelease : RustPlugin
    {
        private const string PermManage = "anchoredlootrelease.manage";

        private PluginConfig config;
        private readonly Dictionary<ulong, double> releaseTimes = new Dictionary<ulong, double>();
        private bool dirty;

        private class PluginConfig
        {
            [JsonProperty("Cooldown seconds before a container can release")]
            public float CooldownSeconds = 30f;

            [JsonProperty("Notify the releasing player")]
            public bool NotifyPlayer = true;
        }

        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>
            {
                ["Locked"] = "This container stays anchored for another {0} seconds.",
                ["Released"] = "Loot released. Grab it before it drifts.",
                ["Saved"] = "Cooldown timestamps saved."
            }, this);
        }

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

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

        private void Unload()
        {
            SaveData();
        }

        private void LoadData()
        {
            try
            {
                var data = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, double>>(Name);
                if (data != null)
                {
                    foreach (var entry in data) releaseTimes[entry.Key] = entry.Value;
                }
            }
            catch
            {
                PrintWarning("Could not read stored release times, starting empty");
            }
        }

        private void SaveData()
        {
            if (!dirty) return;
            Interface.Oxide.DataFileSystem.WriteObject(Name, releaseTimes);
            dirty = false;
        }

        private object OnFreeableContainerRelease(FreeableLootContainer freeableLootContainer, BasePlayer ply)
        {
            if (freeableLootContainer == null) return null;

            ulong id = freeableLootContainer.net.ID.Value;
            double now = Facepunch.Math.Epoch.Current;
            double last;
            if (!releaseTimes.TryGetValue(id, out last))
            {
                releaseTimes[id] = now;
                dirty = true;
                return null;
            }

            double remaining = config.CooldownSeconds - (now - last);
            if (remaining <= 0) return null;

            if (config.NotifyPlayer && ply != null && ply.IsConnected)
            {
                ply.ChatMessage(Msg("Locked", ply.UserIDString, Math.Ceiling(remaining)));
            }

            return false;
        }
    }
}

The plugin records the release time of each freeable loot container when Release is called. When the container releases within the configured cooldown window, the hook returns a non-null value, which blocks the release so the loot stays in place. It also lets the triggering player know the release is locked and, depending on the config, records the container's position. The cooldown timestamp is stored in the plugin's config-backed data so restarts keep the lock, and cooldown state is cleared in Unload after saving.

Common use cases

  • Delay loot release on events

    Return a non-null value to stop a supply drop or other freeable container from releasing until your own timer allows it.

  • Announce releases to nearby players

    Use the container position and ply to send a message or effect to players within range when a container is released.

  • Log release activity

    Record which player released which container and when, so admins can audit event loot behaviour.

Pitfalls

  • ply may be null

    Release is not always triggered by a player; check ply before using displayName, UserIDString or ChatMessage.

  • Blocking release too long

    Returning a non-null value every time leaves the container anchored permanently; use a cooldown or condition so it eventually releases.

  • Do not keep references forever

    Store the container by net.ID.Value rather than holding the entity object, which can be destroyed while your code still references it.

Build a plugin with OnFreeableContainerRelease

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

Prompt: Delay loot release on events using the OnFreeableContainerRelease 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 OnFreeableContainerRelease

Generate