CanUpdateSign
CanUpdateSign is called when a player tries to change the text or image on a sign, photo frame or carved pumpkin, before any of the game's own permission checks run.
object CanUpdateSign(BasePlayer player, Signage signage)Parameters
| Parameter | Type | Description |
|---|---|---|
player | BasePlayer | The BasePlayer attempting to edit the sign, photo frame or carved pumpkin. Use player.UserIDString for permission checks and player.IsAdmin / player.IsDeveloper for staff bypasses. |
signage | Signage | The entity being edited, passed as the base Signage type. Cast or test with `as PhotoFrame` / `as CarvablePumpkin` when you need to treat those differently. |
Return value
Return true to allow the edit and false to block it; both bypass the game's admin bypass. Return null (or any non-bool) to let vanilla logic decide, which allows admins and developers regardless of ownership.
How it works
The hook fires from Signage.CanUpdateSign, PhotoFrame.CanUpdateSign and CarvablePumpkin.CanUpdateSign. Each of these is a server-side gate that decides whether a player may write to the entity, so the hook runs whenever the client requests an edit, for example when a sign is placed or when a player opens a sign UI and submits new text.
The first parameter is the player doing the edit. The second is the entity itself, typed as Signage in the base class but actually a PhotoFrame or CarvablePumpkin for those subclasses. If you declare the parameter as Signage, one method handles all three; if you declare PhotoFrame or CarvablePumpkin, Oxide only calls your method for that concrete type, which is the preferred way to special-case photo frames without an as cast.
Returning a boolean fully overrides the vanilla gate, including the admin bypass (AdminsCanAlwaysUpdateSigns on signs, and the plain IsAdmin || IsDeveloper check on frames and pumpkins). Return null to leave that logic intact. Because the hook fires on every edit attempt, keep it cheap; no printing or data writes inside.
Other signatures
Oxide also calls CanUpdateSign from other places in the game with these parameter types. Declare the overload you need, or several:
object CanUpdateSign(BasePlayer player, PhotoFrame photoFrame)object CanUpdateSign(BasePlayer player, CarvablePumpkin carvablePumpkin)
Example plugin: Restrict sign editing to owners and admins
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using Oxide.Core;
namespace Oxide.Plugins
{
[Info("Sign Owner Only", "RustPluginGenerator", "1.0.0")]
[Description("Restricts editing of signs, photo frames and carved pumpkins to their owner and staff")]
public class SignOwnerOnly : RustPlugin
{
private const string PermAdmin = "signowneronly.admin";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Enable owner lock (true) or allow everyone (false)")]
public bool Enabled = 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>
{
["NotOwner"] = "You do not own this sign. Only the owner may edit it."
}, 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);
}
private object CanUpdateSign(BasePlayer player, Signage signage)
{
if (player == null || signage == null) return null;
if (!config.Enabled) return null;
if (player.IsAdmin || player.IsDeveloper || permission.UserHasPermission(player.UserIDString, PermAdmin)) return null;
ulong ownerId = signage.OwnerID;
if (ownerId != 0 && ownerId == player.userID.Get()) return null;
player.ChatMessage(Msg("NotOwner", player.UserIDString));
return false;
}
}
}The plugin hooks CanUpdateSign and checks whether the player owns the sign, frame or pumpkin. Ownership is read from signage.OwnerID and compared against the player's userID. Admins and developers are always allowed. If the config does not enable locking, the hook returns null so vanilla behaviour is untouched. If the player is not the owner and not staff, a language message is sent and false is returned to block the edit. A config flag and a permission allow operators to turn the lock on or off without recompiling.
Common use cases
Owner-only sign locks
Stop other players from overwriting a sign on a base they raided or share a wall with, while keeping admins able to fix text.
Permission-gated photo frames
Allow only players with a permission to upload images to photo frames, blocking the rest while leaving plain signs untouched.
Protected signage in towns
Block edits to signs placed inside a no-build zone unless the player is authorised on the nearby tool cupboard or is staff.
Pitfalls
Returning null vs true
Returning
nullfalls back to vanilla, which permits admins and developers; returningtrueorfalsereplaces that gate entirely, so admins lose their bypass unless you handle them explicitly.Specific parameter types
Declaring
BasePlayernarrows nothing here, but declaring a subclass parameter such asPhotoFramemeans your method never sees plain signs; keepSignageif you want one handler for all three entity types.OwnerID is not always set
Signs deployed from an item receive the deployer's userID as OwnerID, but signs spawned by plugins or the map may have OwnerID 0; treat 0 as unowned and decide the policy yourself.
Build a plugin with CanUpdateSign
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 CanUpdateSign
Generate