@tool extends EditorPlugin const CONTAINER := CustomControlContainer.CONTAINER_SPATIAL_EDITOR_SIDE_RIGHT @onready var controls_scene := preload("terrain_editing_controls.tscn") @onready var controls : TerrainEditingControls = controls_scene.instantiate() var current_terrain : StaticBody3D func _handles(object: Object) -> bool: return is_terrain(object) func _make_visible(visible: bool) -> void: if visible: add_control_to_container(CONTAINER, controls) elif controls and controls.get_parent(): remove_control_from_container(CONTAINER, controls) if current_terrain: current_terrain.EditorUnfocus() current_terrain = null func _forward_3d_gui_input(camera: Camera3D, event: InputEvent) -> int: var position := Vector3.ZERO if event is InputEventMouse: var previous_terrain := current_terrain current_terrain = null var viewport := EditorInterface.get_editor_viewport_3d() if viewport.get_visible_rect().has_point(event.position): var from := camera.project_ray_origin(event.position) var to := from + camera.project_ray_normal(event.position) * camera.far var root := EditorInterface.get_edited_scene_root() as Node3D var space := root.get_world_3d().direct_space_state var query := PhysicsRayQueryParameters3D.create(from, to) var result := space.intersect_ray(query) var terrain := result.get("collider") as StaticBody3D if is_terrain(terrain): current_terrain = terrain position = result["position"] if previous_terrain and previous_terrain != current_terrain: previous_terrain.EditorUnfocus() if current_terrain: # Allow terrain access to editor undo redo functionality. current_terrain.EditorUndoRedo = get_undo_redo() if current_terrain.EditorInput(event, controls, position): return AFTER_GUI_INPUT_STOP return AFTER_GUI_INPUT_PASS func is_terrain(object: Object) -> bool: if not object: return false var script := object.get_script() as CSharpScript return script and script.resource_path.ends_with("/Terrain.cs")