OnNetworkGroupEntered
OnNetworkGroupEntered is called when a BaseNetworkable is added to a network visibility group through BaseNetworkable.OnNetworkGroupEnter, meaning the entity's network subscriptions were recomputed and it now belongs to that group.
void OnNetworkGroupEntered(BaseNetworkable entity, Network.Visibility.Group group)Parameters
| Parameter | Type | Description |
|---|---|---|
entity | BaseNetworkable | The BaseNetworkable that just became visible to a network group. Check IsDestroyed and ShortPrefabName before acting on it, and cast with 'as' to your type of interest. |
group | Network.Visibility.Group | The Network.Visibility.Group the entity was added to. A network group is the visibility scope used by network subscriptions; it holds objects that share a subscription set. |
Return value
The return value is ignored; the injection sits at the top of OnNetworkGroupEnter and the original method runs regardless of what your hook returns. Return nothing and keep the hook side-effect only.
How it works
The hook fires inside BaseNetworkable.OnNetworkGroupEnter, right before the game checks server occlusion and registers the entity with the occlusion system. The game calls this method when an entity's network subscriptions are recomputed and the entity is placed into a Network.Visibility.Group - typically when it is spawned in, when a player or entity moves and the set of subscribers changes, or when its network state is refreshed. It is a network plumbing hook, not a gameplay event: it fires often on busy servers for many entity types.
entity is the object whose visibility changed. Use net.ID.Value, ShortPrefabName or a cast with as to filter to the types you care about, such as BasePlayer, StorageContainer, HackableLockedCrate or BuildingBlock. group is the destination Network.Visibility.Group; you can use its ID to know which visibility scope the entity joined.
Declaring a more specific first parameter, for example BasePlayer, makes Oxide skip the call for every argument that is not a BasePlayer, which cuts the cost of a hook that fires very frequently. Return value is ignored, so the hook can only observe, not cancel. Avoid heavy work and any logging in the body.
Example plugin: Announce crate drops to the group they appear in
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
using Network;
namespace Oxide.Plugins
{
[Info("Group Entered Crate Announcer", "RustPluginGenerator", "1.0.0")]
[Description("Broadcasts a message when a hackable locked crate enters a network visibility group")]
public class GroupEnteredCrateAnnouncer : RustPlugin
{
private const string PermView = "groupenteredcrateannouncer.view";
private PluginConfig config;
private readonly Dictionary<ulong, float> recentCrates = new Dictionary<ulong, float>();
private Timer cleanupTimer;
private class PluginConfig
{
[JsonProperty("Announce crate in chat")]
public bool Announce { get; set; } = true;
[JsonProperty("Repeat cooldown per crate (seconds)")]
public float Cooldown { get; set; } = 30f;
}
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>
{
["Announce"] = "A hackable crate became network-visible in group {0}"
}, 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(PermView, this);
}
private void OnServerInitialized()
{
cleanupTimer = timer.Every(60f, Cleanup);
}
private void OnNetworkGroupEntered(BaseNetworkable entity, Network.Visibility.Group group)
{
if (entity == null || entity.IsDestroyed) return;
if (!(entity is HackableLockedCrate crate)) return;
if (crate.OwnerID != 0) return;
float now = UnityEngine.Time.realtimeSinceStartup;
float last;
if (recentCrates.TryGetValue(crate.net.ID.Value, out last) && now - last < config.Cooldown) return;
recentCrates[crate.net.ID.Value] = now;
if (!config.Announce) return;
Puts(Msg("Announce", null, group.ID));
foreach (BasePlayer player in BasePlayer.activePlayerList)
{
if (player == null || !player.IsConnected) continue;
if (!permission.UserHasPermission(player.UserIDString, PermView)) continue;
player.ChatMessage(Msg("Announce", player.UserIDString, group.ID));
}
}
private void Cleanup()
{
float now = UnityEngine.Time.realtimeSinceStartup;
List<ulong> stale = new List<ulong>();
foreach (KeyValuePair<ulong, float> pair in recentCrates)
{
if (now - pair.Value > config.Cooldown * 2f) stale.Add(pair.Key);
}
foreach (ulong id in stale) recentCrates.Remove(id);
}
private void Unload()
{
if (cleanupTimer != null)
{
cleanupTimer.Destroy();
cleanupTimer = null;
}
recentCrates.Clear();
}
}
}The plugin watches for HackableLockedCrate entities showing up in a network visibility group. When one is detected, it confirms the crate has no owner yet and reads the group id. If the announce option is enabled in the config, it broadcasts a lang message showing the short prefab name and group id, then skips the same crate for 30 seconds so repeated group changes do not spam chat. Because the hook fires for every networkable, the body exits immediately unless the entity is a HackableLockedCrate, keeping the cost minimal. A rate-limit dictionary guards against duplicates, and Unload clears it.
Common use cases
Detect when players become visible to a group
Declare the first parameter as
BasePlayerand log or track which players joined which visibility group, for example to feed a custom map or spectator tool.Watch rare entity types spawn into network
Filter for
HackableLockedCrate,PatrolHelicopterorBradleyAPCto trigger notifications when those entities become network-visible, without polling server entities on a timer.Debug visibility problems
Temporarily record entity short prefab names and group ids in a data file to understand why an entity is or is not visible to players during a wipe test.
Pitfalls
It does not mean the player saw the entity
Group membership is network plumbing; a player in the group may still not render it if occlusion or distance rules apply. Do not treat this hook as a 'player saw X' event.
Fires constantly on populated servers
Every network group change for every networkable runs this hook. Never print, Puts or run FindEntities inside it; cheap type checks or an early return are essential.
Group is not a player
Network.Visibility.Groupidentifies a subscription scope, not a person. To reach a player you need to resolve subscribers yourself via other network hooks such asOnNetworkSubscriptionsGather.
Build a plugin with OnNetworkGroupEntered
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 OnNetworkGroupEntered
Generate