CanAffordToPlace
CanAffordToPlace is called from Planner.CanAffordToPlace when a player confirms placement of a building part, letting you override whether the game treats the placement as affordable.
object CanAffordToPlace(BasePlayer ownerPlayer, Planner planner, Construction component)Parameters
| Parameter | Type | Description |
|---|---|---|
ownerPlayer | BasePlayer | The BasePlayer who owns the planner and is trying to place a building part. Already validated as non-null by the game before the hook runs. |
planner | Planner | The Planner item component being used for placement. Useful for reading the current building grade or the planner's owner, but most checks only need the player and construction. |
component | Construction | The Construction component selected for placement. Its blockDefinition and prefab describe the part (foundation, wall, etc.) that the game is about to cost-check. |
Return value
Return null to let the game's normal material check decide. Return a bool and the game uses it instead of the default check: true allows the placement, false blocks it even when the player has the materials. Returning a non-bool value is ignored and falls back to vanilla behavior.
How it works
The hook fires inside Planner.CanAffordToPlace, which the game calls right before it decides if the placing player has the required materials. Because your hook runs after the owner has already been resolved and before the creative-mode shortcut, it sees every placement path: blueprints via the planner, without needing to wait for OnEntityBuilt. The ownerPlayer gives you the placer, planner the item in hand, and component the construction being placed, which you can use to inspect blockDefinition and react to grade, size or type. Returning a bool replaces the game's own affordability result, so you can grant free placement to a permission group, apply an economy plugin's balance, or veto placement with a custom reason. Declaring the first parameter as a narrower type such as BasePlayer still matches here since the game always passes a player, but declaring it as anything the argument is not (for example a subclass) makes Oxide skip the call and the vanilla check runs.
Example plugin: Grant free placement to a permission group
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Free Building Placer", "RustPluginGenerator", "1.0.0")]
[Description("Allows permission holders to place building parts without spending materials.")]
public class FreeBuildingPlacer : RustPlugin
{
private const string PermUse = "freebuildingplacer.use";
private PluginConfig config;
private class PluginConfig
{
[JsonProperty("Notify on free placement")]
public bool NotifyOnFreePlacement { get; set; } = true;
[JsonProperty("Only when not building blocked")]
public bool OnlyWhenNotBlocked { get; set; } = false;
}
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>
{
["FreePlaced"] = "Free placement granted for {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(PermUse, this);
}
private object CanAffordToPlace(BasePlayer ownerPlayer, Planner planner, Construction component)
{
if (ownerPlayer == null || component == null) return null;
if (!permission.UserHasPermission(ownerPlayer.UserIDString, PermUse)) return null;
if (config.OnlyWhenNotBlocked && ownerPlayer.IsBuildingBlocked()) return null;
var item = ownerPlayer.GetActiveItem();
var definition = item?.info;
if (definition == null) return null;
if (config.NotifyOnFreePlacement)
{
ownerPlayer.ChatMessage(Msg("FreePlaced", ownerPlayer.UserIDString, definition.displayName.english));
}
return true;
}
}
}The plugin registers a freebuildingplacer.use permission and, when CanAffordToPlace fires, checks it against the placing player before the game's material check runs. Players with the permission return true, bypassing the material cost, while everyone else falls through to vanilla. A config option OnlyWhenNotBlocked can restrict the bypass to players who are not building blocked. With NotifyOnFreePlacement enabled, a chat message naming the active item is sent when the free placement is granted. No timers are involved; the hook returns synchronously.
Common use cases
Free build for VIPs
Check a permission or a linked economy plugin balance and return true so that a group can place building parts without spending materials.
Charge for placement
Before allowing placement, verify the player's account balance through a referenced plugin and return false if the balance cannot cover the cost, charging on success.
Restrict by grade or size
Inspect
componentto deny placement of specific grades or large parts during raid windows or in designated zones.
Pitfalls
Returning true skips all material checks
A
truereturn replaces the full default cost logic, so players who can place never spend materials. Pair this with your own accounting if you intend to charge elsewhere.Hook fires per placement attempt
CanAffordToPlace runs on every placement confirmation and can be called rapidly. Keep the body cheap and avoid chat spam, only messaging when a decision matters.
Declaring the wrong parameter type skips the hook
If you declare an argument type that does not match the passed instance (for example a subclass of Construction), Oxide skips your method and the vanilla check runs silently.
Build a plugin with CanAffordToPlace
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 CanAffordToPlace
Generate