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.
object OnFreeableContainerRelease(FreeableLootContainer freeableLootContainer, BasePlayer ply)Parameters
| Parameter | Type | Description |
|---|---|---|
freeableLootContainer | FreeableLootContainer | The 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. |
ply | BasePlayer | The 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
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
plyto 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
plybefore 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.Valuerather 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.
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