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.
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
Assign the provider to the 2D targeting state used by the active session, then add ProviderCellBlockRule2D to the settings/profile/entry that should respect it.
Attach the rule narrowly while testing. Move it to a profile/global rule only if that matches the intended game policy.
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.