Table of Contents

Class PlacementSystem

Namespace
GridPlacement.GDScript
Assembly
MoonBark.GridPlacement.GDScript.dll

Manages placement of objects in the game world.\n\nHandles preview, placement validation, and placement actions. Uses tile collision indicators to show valid/invalid spots before placement. Checks all rules before adding objects to the world and emits signals for placement success or failure.\n\n@deprecated(class_name) Use PlacementSystem instead. PlacementSystem is a backward-compatible alias.

class PlacementSystem extends PlacementSystemBase
PlacementSystem

Fields

PlaceMode

Explicit build mode for the building system (5.2+) NONE: No build mode active OBJECT: Placing scene objects via ScenePlacementEntry resources TERRAIN: Painting terrain tiles by terrain name, resolved against the TileSet SSOT DECORATION: Kept for backward compatibility but aliases OBJECT Canonical name for the placement mode enum. Use [PlaceMode.OBJECT] etc. in new code — BuildMode is kept as a backward-compatible alias for the same enum (the names are interchangeable; values are identical).

const PlaceMode = BuildMode

WARNING_INVALID_PLACEABLE

const WARNING_INVALID_PLACEABLE = "Invalid placeable resource. Can't instantiate. [%s]"

WARNING_NO_PREVIEW

const WARNING_NO_PREVIEW = "No preview instance created to instantiate yet. Returning null."

MAX_SKIPPED_REASONS

const MAX_SKIPPED_REASONS = 3

Properties

system

var system = PlacementSystem.new()

issues

var issues: Array[String] = []

logger

var logger = container.get_logger()

system

var system = PlacementSystem.new()

issues

var issues: Array[String] = []

placement_polygons

Collision polygons for placement indicators.

var placement_polygons: Array[CollisionPolygon2D]

preview_layer

Preview layer index for buildable/unbuildable tiles.

var preview_layer: int

selected_placeable

Currently selected placeable resource.

var selected_placeable: ScenePlacementEntry

selected_terrain_name

Currently selected terrain name (new path). Empty when no terrain is selected. Resolved against the target TileMapLayer's TileSet at paint-time.

var selected_terrain_name: StringName

selected_terrain_entry

The currently selected terrain entry (if any).

var selected_terrain_entry: TilePlacementEntry

selected_terrain_palette

The currently selected terrain palette (if any).

var selected_terrain_palette: TerrainPalette

current_mode

var current_mode: int = _states.mode.current if _states and _states.mode else PlacementEnums.Mode.OFF

current_place_submode

Current router-facing submode inside global PLACE mode. Computed from [member _place_machine].

var current_place_submode: PlaceSubmode:

brush_state

Brush state accessor (read-only). The actual [BrushState] is owned by [member _brush_coordinator] (P4 god-class extraction); this property preserves the public test-facing API that pre-existed the extraction so test code can still read building_system.brush_state to introspect drag/pending state. Returns null if the coordinator has not been constructed yet (e.g. before [method resolve_placement_dependencies]).

var brush_state: BrushState:

indicators_group

Parent node for collision indicators.

var indicators_group: Node2D

r_ctx

var r_ctx = PlacementBuildOrchestrator.PlacementReadinessContext.new()

r_ctx

var r_ctx = PlacementBuildOrchestrator.PlacementReadinessContext.new()

positioner

var positioner: Node2D = _states.targeting.positioner

current_cell

var current_cell: Vector2i = target_map.local_to_map(target_map.to_local(positioner.global_position))

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

target_map

var target_map: TileMapLayer = _states.targeting.target_map

positioner

var positioner: Node2D = _states.targeting.positioner

cell

var cell = target_map.local_to_map(target_map.to_local(positioner.global_position))

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

target_map

var target_map: TileMapLayer = _states.targeting.target_map

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

positioner

var positioner: Node2D = _states.targeting.positioner

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

current_cell

var current_cell: Vector2i = target_map.local_to_map(target_map.to_local(positioner.global_position))

cells

var cells: Array[Vector2i] = _brush_coordinator.complete_terrain_brush_dry()

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

placed_count

var placed_count: int = 0

skipped_count

var skipped_count: int = 0

skipped_reasons

var skipped_reasons: Array[String] = []

world_pos

var world_pos: Vector2 = target_map.map_to_local(cell)

cell_report

var cell_report: PlacementReport = try_build_at_position(world_pos)

issues

var issues: Array[String] = []

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

summary_report

var summary_report = PlacementReport.new(get_builder_owner(), target_map, null, PlacementEnums.Action.BUILD)

manip_settings

var manip_settings = ManipulationSettings.new()

ctx

var ctx = PlacementBuildOrchestrator.PlacementBuildContext.new()

target_map

var target_map: TileMapLayer = _states.targeting.target_map

positioner

var positioner: Node2D = _states.targeting.positioner

target_cell

var target_cell: Vector2i = target_map.local_to_map(target_map.to_local(positioner.global_position))

failure_report

var failure_report = PlacementReport.new(get_builder_owner(), _get_lazy_preview_builder().get_preview(), null, PlacementEnums.Action.BUILD)

positioner

var positioner: Node2D = _states.targeting.positioner

original_pos

var original_pos = positioner.global_position

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

failure_report

var failure_report = PlacementReport.new(get_builder_owner(), _get_lazy_preview_builder().get_preview(), null, PlacementEnums.Action.BUILD)

preview_instance

var preview_instance: Node2D = _get_lazy_preview_builder().create_preview(p_placeable)

ignore_base_rules

var ignore_base_rules = p_placeable != null and (

setup_report

var setup_report: PlacementReport = _try_setup(preview_instance, selected_placeable, selected_placeable.placement_rules, ignore_base_rules)

found

var found = false

resolved

var resolved = TerrainTilePainter.resolve_terrain_by_name(map.tile_set, p_name)

map_name_lower

var map_name_lower = map.name.to_lower()

terrain_name_lower

var terrain_name_lower = p_name.to_lower()

resolved

var resolved = TerrainTilePainter.resolve_terrain_by_name(map.tile_set, p_name)

has_placeable

var has_placeable = selected_placeable != null

has_terrain

var has_terrain = not selected_terrain_name.is_empty()

current_mode

var current_mode: int = _states.mode.current if _states and _states.mode else PlacementEnums.Mode.OFF

intent

var intent: PlacementInputHandler.InputIntent = _input_handler.resolve(

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

cells

var cells: Array[Vector2i] = _brush_coordinator.complete_terrain_brush_dry()

target_map

var target_map: TileMapLayer = _states.targeting.target_map

positioner

var positioner: Node2D = _states.targeting.positioner

cell

var cell = target_map.local_to_map(target_map.to_local(positioner.global_position))

obj_report

var obj_report = _try_complete_object_line()

pending_report

var pending_report = _commit_pending()

st_report

var st_report = try_place_selected_terrain()

so_report

var so_report = try_build()

so_report

var so_report = try_build()

ol_report

var ol_report = _try_complete_object_line()

preview_instance

var preview_instance: Node2D = _get_lazy_preview_builder().create_preview(p_placeable)

rules

var rules = p_placeable.placement_rules if p_placeable else []

ignore_base_rules

var ignore_base_rules = p_placeable != null and (

placement_report

var placement_report: PlacementReport = _try_setup(preview_instance, p_placeable, rules, ignore_base_rules)

issues

var issues: Array[String] = []

check_props

var check_props: Array[String] = ["_indicator_context"]

selected_resource

var selected_resource: Resource = _active_build_resource()

terrain_for_data

var terrain_for_data: StringName = p_terrain_name if not p_terrain_name.is_empty() else selected_terrain_name

data

var data = PlacementActionData.new(selected_placeable, p_report, p_build_type, selected_resource, terrain_for_data, p_terrain_cell, p_terrain_cell_count)

conn_list

var conn_list = _states.building.get_signal_connection_list("success")

selected_resource

var selected_resource: Resource = _active_build_resource()

terrain_for_data

var terrain_for_data: StringName = p_terrain_name if not p_terrain_name.is_empty() else selected_terrain_name

data

var data = PlacementActionData.new(selected_placeable, p_report, p_build_type, selected_resource, terrain_for_data, p_terrain_cell, p_terrain_cell_count)

f_ctx

var f_ctx = PlacementBuildOrchestrator.PlacementFailureContext.new()

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

manager

var manager = _indicator_context.get_manager()

targeting_state

var targeting_state = _states.targeting

category_rules

var category_rules: Array[PlacementRule] = []

report

var report: PlacementReport = manager.try_setup(p_placeable_rules, targeting_state, p_ignore_base_rules, category_rules)

target_parent

var target_parent: Node = _states.building.placed_parent

parent_name

var parent_name = _get_profile_placed_parent_name(p_placeable.profiles)

override_parent

var override_parent = target_parent.get_node_or_null(parent_name)

instance

var instance = p_placeable.packed_scene.instantiate()

placeable_instance

var placeable_instance = PlaceableInstance.new(p_placeable.resource_path)

issues

var issues: Array[String] = []

critical_issue

Make sure placement manager exists to put preview instances onto

var critical_issue = "CRITICAL: No IndicatorManager found in IndicatorContext. IndicatorManager must be manually created in the scene hierarchy as a child of ManipulationParent (under GridPositioner). Indicators are always parented to IndicatorManager. IndicatorManager must be a child of ManipulationParent to inherit rotation/transform via scene tree. IndicatorManager will register itself through dependency injection."

Methods

create_with_injection

static func create_with_injection(container: PlacementContainer) -> PlacementSystem:

Parameters

container

Returns

create_with_session

static func create_with_session(p_session: PlacementSession) -> PlacementSystem:

Parameters

p_session

Returns

get_building_state

func get_building_state() -> PlacementState:

Returns

get_targeting_state

func get_targeting_state() -> GridTargetingState:

Returns

get_states

func get_states() -> PlacementStates:

Returns

get_logger

func get_logger() -> PlacementLogger:

Returns

set_logger

func set_logger(p_logger: PlacementLogger) -> void:

Parameters

p_logger

Returns

get_actions

func get_actions() -> PlacementActions:

Returns

get_indicator_context

func get_indicator_context() -> IndicatorContext:

Returns

set_states

func set_states(p_states: PlacementStates) -> void:

Parameters

p_states

Returns

set_actions

func set_actions(p_actions: PlacementActions) -> void:

Parameters

p_actions

Returns

set_indicator_context

func set_indicator_context(p_ctx: IndicatorContext) -> void:

Parameters

p_ctx

Returns

is_ready_to_place

func is_ready_to_place() -> bool:

Returns

is_ready_to_paint_terrain

func is_ready_to_paint_terrain() -> bool:

Returns

get_terrain_preview_cells

func get_terrain_preview_cells(p_target_map: TileMapLayer, p_terrain_name: StringName) -> Array[Vector2i]:

Parameters

p_target_map
p_terrain_name

Returns

try_place_terrain_brush

func try_place_terrain_brush( p_cells: Array[Vector2i],

set_brush_shape

func set_brush_shape(p_shape: int) -> void:

Parameters

p_shape

Returns

exit_build_mode

func exit_build_mode() -> void:

Returns

get_terrain_service

func get_terrain_service() -> RefCounted:

Returns

set_host

func set_host(p_host: GridPlacementHost) -> void:

Parameters

p_host

Returns

get_manipulation_service

func get_manipulation_service() -> ManipulationService:

Returns

get_grid_targeting_service

func get_grid_targeting_service() -> GridTargetingService:

Returns

enter_place_router

func enter_place_router() -> void:

Returns

set_place_submode

func set_place_submode(p_submode: PlaceSubmode, p_clear_conflicting_selection: bool = true) -> void:

Parameters

p_submode
p_clear_conflicting_selection

Returns

resolve_placement_dependencies

func resolve_placement_dependencies(p_container : PlacementContainer) -> void:

Parameters

p_container

Returns

try_build

func try_build(p_build_type: PlacementEnums.PlacementType = PlacementEnums.PlacementType.SINGLE) -> PlacementReport:

Parameters

p_build_type

Returns

try_place_selected_terrain

func try_place_selected_terrain() -> PlacementReport:

Returns

try_place_terrain_by_name

func try_place_terrain_by_name( p_terrain_name: StringName,

is_brush_drag_active

func is_brush_drag_active() -> bool:

Returns

is_pending_active

func is_pending_active() -> bool:

Returns

get_current_brush_shape

func get_current_brush_shape() -> int:

Returns

get_brush_drag_start

func get_brush_drag_start() -> Vector2i:

Returns

try_build_at_position

func try_build_at_position(p_global_position: Vector2) -> PlacementReport:

Parameters

p_global_position

Returns

enter_build_mode

func enter_build_mode(p_placeable: ScenePlacementEntry) -> PlacementReport:

Parameters

p_placeable

Returns

select_terrain

func select_terrain(p_name: StringName) -> void:

Parameters

p_name

Returns

select_terrain_with_metadata

func select_terrain_with_metadata(p_name: StringName, p_entry: TilePlacementEntry = null, p_palette: TerrainPalette = null) -> void:

Parameters

p_name
p_entry
p_palette

Returns

set_mode

func set_mode(p_mode: BuildMode, p_clear_selections: bool = true) -> void:

Parameters

p_mode
p_clear_selections

Returns

clear_preview

func clear_preview() -> void:

Returns

instance_preview

func instance_preview(p_placeable: ScenePlacementEntry) -> Node2D:

Parameters

p_placeable

Returns

get_runtime_issues

func get_runtime_issues() -> Array[String]:

Returns

get_builder_owner

func get_builder_owner() -> PlacementOwner:

Returns

report_built

func report_built(p_report : PlacementReport, p_build_type: PlacementEnums.PlacementType = PlacementEnums.PlacementType.SINGLE, p_terrain_name: StringName = &"", p_terrain_cell: Vector2i = PlacementActionData.INVALID_CELL, p_terrain_cell_count: int = 0) -> void:

Parameters

p_report
p_build_type
p_terrain_name
p_terrain_cell
p_terrain_cell_count

Returns

report_failure

func report_failure(p_report : PlacementReport, p_build_type: PlacementEnums.PlacementType = PlacementEnums.PlacementType.SINGLE, p_terrain_name: StringName = &"", p_terrain_cell: Vector2i = PlacementActionData.INVALID_CELL, p_terrain_cell_count: int = 0) -> void:

Parameters

p_report
p_build_type
p_terrain_name
p_terrain_cell
p_terrain_cell_count

Returns

is_in_placement_mode

func is_in_placement_mode() -> bool:

Returns

is_in_build_mode

func is_in_build_mode() -> bool:

Returns

get_current_mode

func get_current_mode() -> BuildMode:

Returns

enter_placement_mode

func enter_placement_mode(p_placeable: ScenePlacementEntry) -> PlacementReport:

Parameters

p_placeable

Returns

exit_placement_mode

func exit_placement_mode() -> void:

Returns

try_place

func try_place(p_build_type: PlacementEnums.PlacementType = PlacementEnums.PlacementType.SINGLE) -> PlacementReport:

Parameters

p_build_type

Returns

try_place_at_position

func try_place_at_position(p_global_position: Vector2) -> PlacementReport:

Parameters

p_global_position

Returns

resolve_gb_dependencies

func resolve_gb_dependencies(p_container: PlacementContainer) -> void:

Parameters

p_container

Returns

Events

build_mode_changed

Router-facing submode inside global PLACE mode. NONE means the user is in PLACE but has not chosen terrain or objects yet. Emitted when the build mode changes

signal build_mode_changed(new_mode: BuildMode)

place_submode_changed

Emitted when the router-facing place submode changes (see PlaceSubmode).

signal place_submode_changed(new_submode: PlaceSubmode)