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
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_mapp_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_submodep_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_namep_entryp_palette
Returns
set_mode
func set_mode(p_mode: BuildMode, p_clear_selections: bool = true) -> void:
Parameters
p_modep_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_reportp_build_typep_terrain_namep_terrain_cellp_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_reportp_build_typep_terrain_namep_terrain_cellp_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)