OnCrateHack
OnCrateHack is called when a HackableLockedCrate begins its hacking sequence, right after StartHacking is invoked and before the crate broadcasts the 'HackingStarted' message and sets its hacking flag.
void OnCrateHack(HackableLockedCrate hackableLockedCrate)Parameters
| Parameter | Type | Description |
|---|---|---|
hackableLockedCrate | HackableLockedCrate | The HackableLockedCrate (locked hackable crate, e.g. from a Chinook event) whose hacking sequence has just started. Null-check it before touching inventory or net members. |
Return value
The return value is ignored and the original StartHacking code runs normally. Returning null or any value has no effect on the crate's hacking behavior.
How it works
The hook fires inside HackableLockedCrate.StartHacking, immediately when the crate transitions into the hacking state. That happens once a player has completed the laptop minigame on a hackable locked crate. Because the call is placed at the top of the method, it runs before the crate sends its HackingStarted broadcast to nearby clients and before it sets Flags.Reserved1, which is the flag the crate uses to track that hacking is in progress.
The single parameter is the crate entity itself. Use it to read its position, net.ID.Value, owner or surrounding entities, and to run your own announcements, rewards bookkeeping or event logging. You can also narrow the parameter by declaring a more specific type, although HackableLockedCrate is already the exact type so there is nothing narrower to choose. Declaring BaseEntity would let the hook fire for every crate subtype that reaches this call, which in practice is still only hackable crates.
Since this fires once per hack start and not per tick, it is safe to do heavier work here such as iterating players or writing data. Pair it with OnCrateHackEnd to know when the sequence finishes or is interrupted.
Example plugin: Reward nearby players when a locked crate is hacked
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("CrateHackReward", "RustPluginGenerator", "1.0.0")]
[Description("Rewards nearby players when a hackable locked crate starts hacking.")]
public class CrateHackReward : RustPlugin
{
private const string PermAdmin = "cratehackreward.admin";
private PluginConfig config;
private readonly Dictionary<ulong, float> recentHacks = new Dictionary<ulong, float>();
private class PluginConfig
{
[JsonProperty("Reward Items")]
public Dictionary<string, int> RewardItems = new Dictionary<string, int>
{
["scrap"] = 50,
["components"] = 1
};
[JsonProperty("Reward Radius")]
public float RewardRadius = 30f;
[JsonProperty("Cooldown Seconds")]
public float CooldownSeconds = 300f;
}
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>
{
["Reward"] = "You were near a hacked crate and received: {0}",
["Broadcast"] = "A hackable crate started hacking near {0}",
["NoRewardItems"] = "No valid reward items are configured."
}, 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(PermAdmin, this);
if (config.RewardItems.Count == 0)
PrintWarning(Msg("NoRewardItems"));
}
private void OnCrateHack(HackableLockedCrate hackableLockedCrate)
{
if (hackableLockedCrate == null || hackableLockedCrate.IsDestroyed) return;
ulong crateId = hackableLockedCrate.net.ID.Value;
float now = UnityEngine.Time.realtimeSinceStartup;
if (recentHacks.TryGetValue(crateId, out float last) && now - last < config.CooldownSeconds)
return;
recentHacks[crateId] = now;
Vector3 origin = hackableLockedCrate.transform.position;
float radiusSqr = config.RewardRadius * config.RewardRadius;
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (player == null || !player.IsConnected || player.IsDead()) continue;
if (Vector3.SqrMagnitude(player.transform.position - origin) > radiusSqr) continue;
GiveRewards(player);
}
}
private void GiveRewards(BasePlayer player)
{
List<string> received = new List<string>();
foreach (KeyValuePair<string, int> entry in config.RewardItems)
{
if (entry.Value <= 0) continue;
Item item = ItemManager.CreateByName(entry.Key, entry.Value);
if (item == null) continue;
player.GiveItem(item);
received.Add($"{entry.Value}x {item.info.displayName.english}");
}
if (received.Count > 0)
player.ChatMessage(Msg("Reward", player.UserIDString, string.Join(", ", received)));
}
[ChatCommand("cratehackreward")]
private void CmdStatus(BasePlayer player, string command, string[] args)
{
if (player == null) return;
if (!permission.UserHasPermission(player.UserIDString, PermAdmin))
{
player.ChatMessage("You do not have permission to use this command.");
return;
}
recentHacks.Clear();
player.ChatMessage("Crate hack reward cooldowns cleared.");
}
private void Unload()
{
recentHacks.Clear();
}
}
}The plugin listens for OnCrateHack, which runs the moment a locked crate starts hacking. On that event it reads the configured reward list and iterates every connected player within the configured radius of the crate. Each player receives one of each configured item and a chat notice through the language file. The plugin tracks a per-crate cooldown so that if a crate is re-hacked within the window it does not pay out twice. Reward items are created with ItemManager.CreateByName and handed over with player.GiveItem, which drops the item if the inventory is full. Everything is driven by config (Reward Items, Reward Radius, Cooldown Seconds) so admins can tune payouts without recompiling.
Common use cases
Announce crate hacks to the server
Send a server-wide or team-scoped chat message naming the region or grid where the crate started hacking so players know a fight is about to happen.
Reward nearby participants
Give small rewards to players standing near the crate when StartHacking fires, encouraging contested crates.
Log hack events for admins
Persist the crate position, timestamp and surrounding player IDs to a data file for later review of event behavior.
Pitfalls
Fires once per StartHacking call
If a crate is hacked again after stopping, StartHacking runs again and the hook fires a second time. Track crate IDs if you only want a single payout.
Hacking flag not yet set
The hook runs before the crate sets Flags.Reserved1, so checking whether the crate is currently flagged as hacking will return the previous state, not the new one.
Crate may be destroyed
Always null-check the crate and short-circuit if
IsDestroyedis true; a crate can be destroyed between events during a raid.
Plugin recipes that use OnCrateHack
- How to make a Rust hackable crate timer plugin (shorter VIP hack)Overrides the hack duration of HackableLockedCrate entities and lets players with a VIP permission unlock them faster, using the OnCrateHack hook and a server-wide announcement when a hack begins.
- How to make a Rust locked crate event plugin (timed monument drops)Spawns a hackable locked crate at a random configured monument on a repeating timer, announces the monument in chat, and removes the previous event crate before each new one. Uses OnServerInitialized, OnCrateHack, OnEntityKill and OnServerShutdown with a repeating Oxide timer.
Build a plugin with OnCrateHack
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 OnCrateHack
Generate