Use PlacementWorldFactsProvider2D when 2D TileMapLayer placement must respect world facts owned by your game rather than Grid Placement.
Examples:
- reserved build cells;
- occupancy stored in another simulation/registry;
- protected zones;
- server/game-state restrictions represented by cells.
This provider is specifically a 2D cell-facts bridge. Do not treat it as the 3D slope/mount validation API; 3D core support is documented separately.
Why this exists
Games often keep cell restrictions in their own systems: a town simulation owns plots, a server owns build permissions, or a strategy layer owns territory. Keep those facts in the game and expose the cell check through this provider.
Implement two methods — is this cell blocked, and why — then attach ProviderCellBlockRule2D to the placement settings, profile, or entry that should use the check. The rule applies the result during preview and final validation for 2D object placement and terrain painting.
Mental model
game-owned world data
→ PlacementWorldFactsProvider2D
→ ProviderCellBlockRule2D
→ normal preview/final placement validationThe game owns the data. The provider translates it into the small question Grid Placement needs: is this cell blocked, and why?
Minimal provider
class_name MyWorldFactsProvider
extends PlacementWorldFactsProvider2D
var blocked_cells:Dictionary = {}
func is_cell_blocked(cell:Vector2i)-> bool:
return blocked_cells.has(cell)
func get_block_reason(cell:Vector2i)-> String:
return String(blocked_cells.get(cell,""))The provider can read a dictionary, occupancy registry, ECS/simulation, physics integration, server state, or another game-owned source. Keep source-specific dependencies inside your project adapter, not inside generic addon rules.
Connect it to the active session
Set the provider on the targeting state's world_facts_provider_2d field, then add ProviderCellBlockRule2D to the settings/profile/entry that should respect it.
An attached ProviderCellBlockRule2D requires a provider: missing context, targeting state, or provider fails validation with a named setup issue. Projects that do not use external world facts should leave the rule unattached, rather than attaching it without an adapter.
Start with the rule on the single entry you are testing. Promote it to a profile or settings only once the policy proves global — a rule attached too broadly blocks placements you have not thought about yet.
Failure reasons
Return short actionable reasons such as:
"Reserved for another structure""Occupied by town hall""Protected build zone"
The normal placement result/report should carry this reason to preview/commit UI. Do not repeat the provider query in UI code.
Provider behavior
A provider should be:
- read-only during validation;
- deterministic for the current world snapshot;
- cheap enough to query during preview;
- independent from the addon implementation;
- safe when its backing game service is unavailable.
Choose fail-open or fail-closed behavior deliberately for your game. If missing provider data would make placement unsafe, return a blocking fact rather than silently pretending the cell is free.
When not to use this
Do not add a provider when built-in placement facts already answer the question.
Examples:
- normal Grid Placement object occupancy;
- 3D CELL/EDGE/FACE mount occupancy;
- 3D slope/support;
- SMOOTH footprint overlap.
Duplicating those facts in a game provider creates two authorities that can drift.
Checklist
- Basic placement works before the custom provider is added.
- Known blocked/allowed cells return the expected results.
- Provider is assigned to the active session's 2D targeting path.
-
ProviderCellBlockRule2Dis attached at the intended scope. - Preview and final commit show the same provider result.
- UI displays the placement issue instead of re-running the world query.
Related guides
Using this in a game?
Grid Placement v6.3.0 — full source, playable demos, commercial license
The guide above is the same setup the shipped demos use. Try the build in your browser before you buy it.