CanNetworkTo
CanNetworkTo is called when the server decides whether a networkable entity should be sent to a specific player's client. Returning false stops replication of that entity to that player until the next subscription evaluation.
object CanNetworkTo(BaseNetworkable entity, BasePlayer player)Parameters
| Parameter | Type | Description |
|---|---|---|
entity | BaseNetworkable | The networkable entity that the server is deciding whether to replicate to the given player. For the BasePlayer override this is the player being networked to the observer. |
player | BasePlayer | The receiving BasePlayer (the client whose network subscription is being evaluated). Never null in the base path, but always null-check before reading members. |
Return value
Returning null lets the game's default ShouldNetworkTo logic run unchanged. Returning a bool short-circuits the original method: true marks the pair as networkable without running the default group/occlusion checks, and false hides the entity from that player until the next evaluation. Any other return type is ignored.
How it works
This hook fires from BaseNetworkable.ShouldNetworkTo, which the server runs for every entity/player pair it is about to add to a network group, and from the BasePlayer.ShouldNetworkTo override for player-to-player visibility. It is a per-pair decision: the server asks whether entity should be replicated to player. The base implementation checks the entity's network group and distance/occlusion rules; your hook runs before that logic.
Because the hook is called very often (every subscription pass, every spawn), keep the body cheap: avoid LINQ, allocations, and disk or chat output. Cache what you need in OnServerInitialized. Declaring a more specific entity type (for example BasePlayer) is not enough to isolate the override call, because Oxide dispatches by argument type only and the base path also passes arbitrary BaseNetworkable instances that will fail the type check and be skipped by Oxide, silently changing behavior for entities you did not intend to filter. If you need to act on players specifically, compare entity as BasePlayer inside the hook instead.
Returning false hides the entity from that player's client; other players still receive it. If you hide an entity that the client references elsewhere, expect visual artifacts, missing colliders, or loot UI errors until you allow it again.
Other signatures
Oxide also calls CanNetworkTo from other places in the game with these parameter types. Declare the overload you need, or several:
object CanNetworkTo(BasePlayer player, BasePlayer player2)
Example plugin: Hide players outside a permission group's view distance
using System;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Network Range Limit", "RustPluginGenerator", "1.0.0")]
[Description("Hides distant players from observers in a permission group to reduce client exposure.")]
public class NetworkRangeLimit : RustPlugin
{
private const string PermRestricted = "networkrangelimit.restricted";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Maximum visible distance (meters)")]
public float MaxDistance = 250f;
[JsonProperty("Only apply to players with the permission")]
public bool OnlyRestricted = 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);
private void Init()
{
permission.RegisterPermission(PermRestricted, this);
}
private object CanNetworkTo(BaseNetworkable entity, BasePlayer player)
{
if (entity == null || player == null || config.MaxDistance <= 0f) return null;
var observer = player;
var subject = entity as BasePlayer;
if (subject == null || subject == observer) return null;
if (!observer.IsConnected || !subject.IsConnected) return null;
if (config.OnlyRestricted && !permission.UserHasPermission(observer.UserIDString, PermRestricted))
return null;
float maxSqr = config.MaxDistance * config.MaxDistance;
float dx = observer.transform.position.x - subject.transform.position.x;
float dy = observer.transform.position.y - subject.transform.position.y;
float dz = observer.transform.position.z - subject.transform.position.z;
if ((dx * dx) + (dy * dy) + (dz * dz) > maxSqr)
return false;
return null;
}
}
}The plugin lets admins restrict how far certain players can see other players by adding them to a permission. In CanNetworkTo it checks only player-to-player pairs by casting entity as BasePlayer. If the observer lacks the permission and the entity is a player beyond the configured distance, it returns false, hiding that player's networkable from the observer's client. Distance is measured in world units using squared components to avoid a square root on every call, and the threshold comes from config. Everything else returns null so vanilla behavior is preserved. The hook stays allocation-light: one cast, one permission check, one distance comparison.
Common use cases
Anti-cheat style fog of war
Prevent exploitation clients from discovering remote players by hiding players beyond a configurable distance from restricted accounts, while normal players keep default visibility.
Event or arena isolation
During an event, hide all players outside the arena bounds from participants by returning false for pairs that are not both inside the region, avoiding outside interference and stream sniping.
Staff invisibility
Hide a spectator or admin entity from regular players by checking the entity's owner or a marker component and returning false while leaving other players' visibility untouched.
Pitfalls
Called extremely often
The hook runs for every entity/player subscription pass, so PrintWarning, LINQ, and closures inside the body will cause measurable load on populated servers. Precompute data in OnServerInitialized and store it in dictionaries.
Type-narrowing silently skips calls
Declaring
BasePlayer entityin the parameters makes Oxide skip every call where the entity is not a player, which changes vanilla behavior for structures, items, and NPCs. Keep the parameter asBaseNetworkableand cast inside.Hiding entities breaks clients
Returning false for lootable containers, doors, or players the client already knows about can produce missing colliders, stuck UI, or desync until the pair is evaluated again. Only hide entities that are safe to omit from the client's view.
Build a plugin with CanNetworkTo
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 CanNetworkTo
Generate