Browse Source

Merge pull request #27742 from rxlecky/camera-replication

Game camera override
Rémi Verschelde 5 years ago
parent
commit
621dc7022f

+ 0 - 27
core/script_language.h

@@ -427,31 +427,6 @@ class ScriptDebugger {
 	ScriptLanguage *break_lang;
 
 public:
-	typedef void (*RequestSceneTreeMessageFunc)(void *);
-
-	struct LiveEditFuncs {
-
-		void *udata;
-		void (*node_path_func)(void *, const NodePath &p_path, int p_id);
-		void (*res_path_func)(void *, const String &p_path, int p_id);
-
-		void (*node_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value);
-		void (*node_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value);
-		void (*node_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE);
-		void (*res_set_func)(void *, int p_id, const StringName &p_prop, const Variant &p_value);
-		void (*res_set_res_func)(void *, int p_id, const StringName &p_prop, const String &p_value);
-		void (*res_call_func)(void *, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE);
-		void (*root_func)(void *, const NodePath &p_scene_path, const String &p_scene_from);
-
-		void (*tree_create_node_func)(void *, const NodePath &p_parent, const String &p_type, const String &p_name);
-		void (*tree_instance_node_func)(void *, const NodePath &p_parent, const String &p_path, const String &p_name);
-		void (*tree_remove_node_func)(void *, const NodePath &p_at);
-		void (*tree_remove_and_keep_node_func)(void *, const NodePath &p_at, ObjectID p_keep_id);
-		void (*tree_restore_node_func)(void *, ObjectID p_id, const NodePath &p_at, int p_at_pos);
-		void (*tree_duplicate_node_func)(void *, const NodePath &p_at, const String &p_new_name);
-		void (*tree_reparent_node_func)(void *, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
-	};
-
 	_FORCE_INLINE_ static ScriptDebugger *get_singleton() { return singleton; }
 	void set_lines_left(int p_left);
 	int get_lines_left() const;
@@ -480,8 +455,6 @@ public:
 	virtual bool is_remote() const { return false; }
 	virtual void request_quit() {}
 
-	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
-	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
 	virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {}
 
 	virtual bool is_profiling() const = 0;

+ 44 - 0
editor/plugins/canvas_item_editor_plugin.cpp

@@ -3811,6 +3811,7 @@ void CanvasItemEditor::_notification(int p_what) {
 		grid_snap_button->set_icon(get_icon("SnapGrid", "EditorIcons"));
 		snap_config_menu->set_icon(get_icon("GuiTabMenu", "EditorIcons"));
 		skeleton_menu->set_icon(get_icon("Bone", "EditorIcons"));
+		override_camera_button->set_icon(get_icon("Camera2D", "EditorIcons"));
 		pan_button->set_icon(get_icon("ToolPan", "EditorIcons"));
 		ruler_button->set_icon(get_icon("Ruler", "EditorIcons"));
 		pivot_button->set_icon(get_icon("EditPivot", "EditorIcons"));
@@ -3880,6 +3881,15 @@ void CanvasItemEditor::_notification(int p_what) {
 
 		anchor_mode_button->set_icon(get_icon("Anchor", "EditorIcons"));
 	}
+
+	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+		if (!is_visible() && override_camera_button->is_pressed()) {
+			ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+			debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+			override_camera_button->set_pressed(false);
+		}
+	}
 }
 
 void CanvasItemEditor::_selection_changed() {
@@ -4221,6 +4231,15 @@ void CanvasItemEditor::_button_toggle_grid_snap(bool p_status) {
 	grid_snap_active = p_status;
 	viewport->update();
 }
+void CanvasItemEditor::_button_override_camera(bool p_pressed) {
+	ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+	if (p_pressed) {
+		debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_2D);
+	} else {
+		debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+	}
+}
 
 void CanvasItemEditor::_button_tool_select(int p_index) {
 
@@ -4318,6 +4337,17 @@ void CanvasItemEditor::_button_toggle_anchor_mode(bool p_status) {
 	viewport->update();
 }
 
+void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
+	if (p_game_running) {
+		override_camera_button->set_disabled(false);
+		override_camera_button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera."));
+	} else {
+		override_camera_button->set_disabled(true);
+		override_camera_button->set_pressed(false);
+		override_camera_button->set_tooltip(TTR("Game camera override\nNo game instance running."));
+	}
+}
+
 void CanvasItemEditor::_popup_callback(int p_op) {
 
 	last_option = MenuOption(p_op);
@@ -4915,6 +4945,8 @@ void CanvasItemEditor::_bind_methods() {
 	ClassDB::bind_method("_button_zoom_plus", &CanvasItemEditor::_button_zoom_plus);
 	ClassDB::bind_method("_button_toggle_smart_snap", &CanvasItemEditor::_button_toggle_smart_snap);
 	ClassDB::bind_method("_button_toggle_grid_snap", &CanvasItemEditor::_button_toggle_grid_snap);
+	ClassDB::bind_method(D_METHOD("_button_override_camera", "pressed"), &CanvasItemEditor::_button_override_camera);
+	ClassDB::bind_method(D_METHOD("_update_override_camera_button", "game_running"), &CanvasItemEditor::_update_override_camera_button);
 	ClassDB::bind_method("_button_toggle_anchor_mode", &CanvasItemEditor::_button_toggle_anchor_mode);
 	ClassDB::bind_method("_update_scroll", &CanvasItemEditor::_update_scroll);
 	ClassDB::bind_method("_update_scrollbars", &CanvasItemEditor::_update_scrollbars);
@@ -5246,6 +5278,9 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
 	editor_selection->connect("selection_changed", this, "update");
 	editor_selection->connect("selection_changed", this, "_selection_changed");
 
+	editor->call_deferred("connect", "play_pressed", this, "_update_override_camera_button", make_binds(true));
+	editor->call_deferred("connect", "stop_pressed", this, "_update_override_camera_button", make_binds(false));
+
 	hb = memnew(HBoxContainer);
 	add_child(hb);
 	hb->set_anchors_and_margins_preset(Control::PRESET_WIDE);
@@ -5491,6 +5526,15 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
 
 	hb->add_child(memnew(VSeparator));
 
+	override_camera_button = memnew(ToolButton);
+	hb->add_child(override_camera_button);
+	override_camera_button->connect("toggled", this, "_button_override_camera");
+	override_camera_button->set_toggle_mode(true);
+	override_camera_button->set_disabled(true);
+	_update_override_camera_button(false);
+
+	hb->add_child(memnew(VSeparator));
+
 	view_menu = memnew(MenuButton);
 	view_menu->set_text(TTR("View"));
 	hb->add_child(view_menu);

+ 4 - 0
editor/plugins/canvas_item_editor_plugin.h

@@ -364,6 +364,7 @@ private:
 	ToolButton *ungroup_button;
 
 	MenuButton *skeleton_menu;
+	ToolButton *override_camera_button;
 	MenuButton *view_menu;
 	HBoxContainer *animation_hb;
 	MenuButton *animation_menu;
@@ -537,8 +538,11 @@ private:
 	void _button_zoom_plus();
 	void _button_toggle_smart_snap(bool p_status);
 	void _button_toggle_grid_snap(bool p_status);
+	void _button_override_camera(bool p_pressed);
 	void _button_tool_select(int p_index);
 
+	void _update_override_camera_button(bool p_game_running);
+
 	HSplitContainer *palette_split;
 	VSplitContainer *bottom_split;
 

+ 72 - 0
editor/plugins/spatial_editor_plugin.cpp

@@ -901,6 +901,8 @@ void SpatialEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
 	Ref<InputEventMouseButton> b = p_event;
 
 	if (b.is_valid()) {
+		emit_signal("clicked", this);
+
 		float zoom_factor = 1 + (ZOOM_MULTIPLIER - 1) * b->get_factor();
 		switch (b->get_button_index()) {
 
@@ -3101,6 +3103,7 @@ void SpatialEditorViewport::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("drop_data_fw"), &SpatialEditorViewport::drop_data_fw);
 
 	ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
+	ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
 }
 
 void SpatialEditorViewport::reset() {
@@ -4373,6 +4376,19 @@ void SpatialEditor::_menu_item_toggled(bool pressed, int p_option) {
 			tool_option_button[TOOL_OPT_USE_SNAP]->set_pressed(pressed);
 			snap_enabled = pressed;
 		} break;
+
+		case MENU_TOOL_OVERRIDE_CAMERA: {
+			ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
+
+			if (pressed) {
+				using Override = ScriptEditorDebugger::CameraOverride;
+
+				debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+			} else {
+				debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+			}
+
+		} break;
 	}
 }
 
@@ -4400,6 +4416,35 @@ void SpatialEditor::_menu_gizmo_toggled(int p_option) {
 	update_all_gizmos();
 }
 
+void SpatialEditor::_update_camera_override_button(bool p_game_running) {
+	Button *const button = tool_option_button[TOOL_OPT_OVERRIDE_CAMERA];
+
+	if (p_game_running) {
+		button->set_disabled(false);
+		button->set_tooltip(TTR("Game camera override\nNo game instance running."));
+	} else {
+		button->set_disabled(true);
+		button->set_pressed(false);
+		button->set_tooltip(TTR("Game camera override\nOverrides game camera with editor viewport camera."));
+	}
+}
+
+void SpatialEditor::_update_camera_override_viewport(Object *p_viewport) {
+	SpatialEditorViewport *current_viewport = Object::cast_to<SpatialEditorViewport>(p_viewport);
+
+	if (!current_viewport)
+		return;
+
+	ScriptEditorDebugger *const debugger = ScriptEditor::get_singleton()->get_debugger();
+
+	camera_override_viewport_id = current_viewport->index;
+	if (debugger->get_camera_override() >= ScriptEditorDebugger::OVERRIDE_3D_1) {
+		using Override = ScriptEditorDebugger::CameraOverride;
+
+		debugger->set_camera_override((Override)(Override::OVERRIDE_3D_1 + camera_override_viewport_id));
+	}
+}
+
 void SpatialEditor::_menu_item_pressed(int p_option) {
 
 	switch (p_option) {
@@ -5294,6 +5339,7 @@ void SpatialEditor::_notification(int p_what) {
 
 		tool_option_button[SpatialEditor::TOOL_OPT_LOCAL_COORDS]->set_icon(get_icon("Object", "EditorIcons"));
 		tool_option_button[SpatialEditor::TOOL_OPT_USE_SNAP]->set_icon(get_icon("Snap", "EditorIcons"));
+		tool_option_button[SpatialEditor::TOOL_OPT_OVERRIDE_CAMERA]->set_icon(get_icon("Camera", "EditorIcons"));
 
 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons"));
 		view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons"));
@@ -5309,6 +5355,9 @@ void SpatialEditor::_notification(int p_what) {
 		get_tree()->connect("node_removed", this, "_node_removed");
 		EditorNode::get_singleton()->get_scene_tree_dock()->get_tree_editor()->connect("node_changed", this, "_refresh_menu_icons");
 		editor_selection->connect("selection_changed", this, "_refresh_menu_icons");
+
+		editor->connect("stop_pressed", this, "_update_camera_override_button", make_binds(false));
+		editor->connect("play_pressed", this, "_update_camera_override_button", make_binds(true));
 	} else if (p_what == NOTIFICATION_ENTER_TREE) {
 
 		_register_all_gizmos();
@@ -5343,6 +5392,13 @@ void SpatialEditor::_notification(int p_what) {
 		// Update grid color by rebuilding grid.
 		_finish_grid();
 		_init_grid();
+	} else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+		if (!is_visible() && tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->is_pressed()) {
+			ScriptEditorDebugger *debugger = ScriptEditor::get_singleton()->get_debugger();
+
+			debugger->set_camera_override(ScriptEditorDebugger::OVERRIDE_NONE);
+			tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_pressed(false);
+		}
 	}
 }
 
@@ -5487,6 +5543,8 @@ void SpatialEditor::_bind_methods() {
 	ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo);
 	ClassDB::bind_method("_toggle_maximize_view", &SpatialEditor::_toggle_maximize_view);
 	ClassDB::bind_method("_refresh_menu_icons", &SpatialEditor::_refresh_menu_icons);
+	ClassDB::bind_method("_update_camera_override_button", &SpatialEditor::_update_camera_override_button);
+	ClassDB::bind_method("_update_camera_override_viewport", &SpatialEditor::_update_camera_override_viewport);
 
 	ADD_SIGNAL(MethodInfo("transform_key_request"));
 	ADD_SIGNAL(MethodInfo("item_lock_status_changed"));
@@ -5540,6 +5598,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
 	snap_key_enabled = false;
 	tool_mode = TOOL_MODE_SELECT;
 
+	camera_override_viewport_id = 0;
+
 	hbc_menu = memnew(HBoxContainer);
 	vbc->add_child(hbc_menu);
 
@@ -5637,6 +5697,17 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
 
 	hbc_menu->add_child(memnew(VSeparator));
 
+	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA] = memnew(ToolButton);
+	hbc_menu->add_child(tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]);
+	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_toggle_mode(true);
+	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_flat(true);
+	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->set_disabled(true);
+	button_binds.write[0] = MENU_TOOL_OVERRIDE_CAMERA;
+	tool_option_button[TOOL_OPT_OVERRIDE_CAMERA]->connect("toggled", this, "_menu_item_toggled", button_binds);
+	_update_camera_override_button(false);
+
+	hbc_menu->add_child(memnew(VSeparator));
+
 	// Drag and drop support;
 	preview_node = memnew(Spatial);
 	preview_bounds = AABB();
@@ -5725,6 +5796,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
 
 		viewports[i] = memnew(SpatialEditorViewport(this, editor, i));
 		viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view");
+		viewports[i]->connect("clicked", this, "_update_camera_override_viewport");
 		viewports[i]->assign_pending_data_pointers(preview_node, &preview_bounds, accept);
 		viewport_base->add_child(viewports[i]);
 	}

+ 7 - 5
editor/plugins/spatial_editor_plugin.h

@@ -494,6 +494,7 @@ public:
 
 		TOOL_OPT_LOCAL_COORDS,
 		TOOL_OPT_USE_SNAP,
+		TOOL_OPT_OVERRIDE_CAMERA,
 		TOOL_OPT_MAX
 
 	};
@@ -559,6 +560,7 @@ private:
 		MENU_TOOL_LIST_SELECT,
 		MENU_TOOL_LOCAL_COORDS,
 		MENU_TOOL_USE_SNAP,
+		MENU_TOOL_OVERRIDE_CAMERA,
 		MENU_TRANSFORM_CONFIGURE_SNAP,
 		MENU_TRANSFORM_DIALOG,
 		MENU_VIEW_USE_1_VIEWPORT,
@@ -585,9 +587,6 @@ private:
 	PopupMenu *gizmos_menu;
 	MenuButton *view_menu;
 
-	ToolButton *lock_button;
-	ToolButton *unlock_button;
-
 	AcceptDialog *accept;
 
 	ConfirmationDialog *snap_dialog;
@@ -615,13 +614,16 @@ private:
 	void _menu_item_pressed(int p_option);
 	void _menu_item_toggled(bool pressed, int p_option);
 	void _menu_gizmo_toggled(int p_option);
+	void _update_camera_override_button(bool p_game_running);
+	void _update_camera_override_viewport(Object *p_viewport);
 
 	HBoxContainer *hbc_menu;
 
 	void _generate_selection_box();
 	UndoRedo *undo_redo;
 
-	void _instance_scene();
+	int camera_override_viewport_id;
+
 	void _init_indicators();
 	void _update_gizmos_menu();
 	void _update_gizmos_menu_theme();
@@ -716,7 +718,7 @@ public:
 	void set_can_preview(Camera *p_preview);
 
 	SpatialEditorViewport *get_editor_viewport(int p_idx) {
-		ERR_FAIL_INDEX_V(p_idx, 4, NULL);
+		ERR_FAIL_INDEX_V(p_idx, static_cast<int>(VIEWPORTS_COUNT), NULL);
 		return viewports[p_idx];
 	}
 

+ 78 - 0
editor/script_editor_debugger.cpp

@@ -33,6 +33,8 @@
 #include "core/io/marshalls.h"
 #include "core/project_settings.h"
 #include "core/ustring.h"
+#include "editor/plugins/canvas_item_editor_plugin.h"
+#include "editor/plugins/spatial_editor_plugin.h"
 #include "editor_network_profiler.h"
 #include "editor_node.h"
 #include "editor_profiler.h"
@@ -1232,6 +1234,42 @@ void ScriptEditorDebugger::_notification(int p_what) {
 						}
 					}
 				}
+
+				if (camera_override == OVERRIDE_2D) {
+					CanvasItemEditor *editor = CanvasItemEditor::get_singleton();
+
+					Dictionary state = editor->get_state();
+					float zoom = state["zoom"];
+					Point2 offset = state["ofs"];
+					Transform2D transform;
+
+					transform.scale_basis(Size2(zoom, zoom));
+					transform.elements[2] = -offset * zoom;
+
+					Array msg;
+					msg.push_back("override_camera_2D:transform");
+					msg.push_back(transform);
+					ppeer->put_var(msg);
+
+				} else if (camera_override >= OVERRIDE_3D_1) {
+					int viewport_idx = camera_override - OVERRIDE_3D_1;
+					SpatialEditorViewport *viewport = SpatialEditor::get_singleton()->get_editor_viewport(viewport_idx);
+					Camera *const cam = viewport->get_camera();
+
+					Array msg;
+					msg.push_back("override_camera_3D:transform");
+					msg.push_back(cam->get_camera_transform());
+					if (cam->get_projection() == Camera::PROJECTION_ORTHOGONAL) {
+						msg.push_back(false);
+						msg.push_back(cam->get_size());
+					} else {
+						msg.push_back(true);
+						msg.push_back(cam->get_fov());
+					}
+					msg.push_back(cam->get_znear());
+					msg.push_back(cam->get_zfar());
+					ppeer->put_var(msg);
+				}
 			}
 
 			if (error_count != last_error_count || warning_count != last_warning_count) {
@@ -1446,6 +1484,7 @@ void ScriptEditorDebugger::start() {
 
 	set_process(true);
 	breaked = false;
+	camera_override = OVERRIDE_NONE;
 }
 
 void ScriptEditorDebugger::pause() {
@@ -1890,6 +1929,45 @@ void ScriptEditorDebugger::live_debug_reparent_node(const NodePath &p_at, const
 	}
 }
 
+ScriptEditorDebugger::CameraOverride ScriptEditorDebugger::get_camera_override() const {
+	return camera_override;
+}
+
+void ScriptEditorDebugger::set_camera_override(CameraOverride p_override) {
+
+	if (p_override == OVERRIDE_2D && camera_override != OVERRIDE_2D) {
+		if (connection.is_valid()) {
+			Array msg;
+			msg.push_back("override_camera_2D:set");
+			msg.push_back(true);
+			ppeer->put_var(msg);
+		}
+	} else if (p_override != OVERRIDE_2D && camera_override == OVERRIDE_2D) {
+		if (connection.is_valid()) {
+			Array msg;
+			msg.push_back("override_camera_2D:set");
+			msg.push_back(false);
+			ppeer->put_var(msg);
+		}
+	} else if (p_override >= OVERRIDE_3D_1 && camera_override < OVERRIDE_3D_1) {
+		if (connection.is_valid()) {
+			Array msg;
+			msg.push_back("override_camera_3D:set");
+			msg.push_back(true);
+			ppeer->put_var(msg);
+		}
+	} else if (p_override < OVERRIDE_3D_1 && camera_override >= OVERRIDE_3D_1) {
+		if (connection.is_valid()) {
+			Array msg;
+			msg.push_back("override_camera_3D:set");
+			msg.push_back(false);
+			ppeer->put_var(msg);
+		}
+	}
+
+	camera_override = p_override;
+}
+
 void ScriptEditorDebugger::set_breakpoint(const String &p_path, int p_line, bool p_enabled) {
 
 	if (connection.is_valid()) {

+ 17 - 0
editor/script_editor_debugger.h

@@ -35,6 +35,7 @@
 #include "core/io/tcp_server.h"
 #include "editor/editor_inspector.h"
 #include "editor/property_editor.h"
+#include "scene/3d/camera.h"
 #include "scene/gui/box_container.h"
 #include "scene/gui/button.h"
 
@@ -58,6 +59,17 @@ class ScriptEditorDebugger : public Control {
 
 	GDCLASS(ScriptEditorDebugger, Control);
 
+public:
+	enum CameraOverride {
+		OVERRIDE_NONE,
+		OVERRIDE_2D,
+		OVERRIDE_3D_1, // 3D Viewport 1
+		OVERRIDE_3D_2, // 3D Viewport 2
+		OVERRIDE_3D_3, // 3D Viewport 3
+		OVERRIDE_3D_4 // 3D Viewport 4
+	};
+
+private:
 	enum MessageType {
 		MESSAGE_ERROR,
 		MESSAGE_WARNING,
@@ -165,6 +177,8 @@ class ScriptEditorDebugger : public Control {
 
 	bool live_debug;
 
+	CameraOverride camera_override;
+
 	void _performance_draw();
 	void _performance_select();
 	void _stack_dump_frame_selected();
@@ -250,6 +264,9 @@ public:
 	void live_debug_duplicate_node(const NodePath &p_at, const String &p_new_name);
 	void live_debug_reparent_node(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
 
+	CameraOverride get_camera_override() const;
+	void set_camera_override(CameraOverride p_override);
+
 	void set_breakpoint(const String &p_path, int p_line, bool p_enabled);
 
 	void update_live_edit_root();

+ 7 - 1
main/main.cpp

@@ -44,7 +44,6 @@
 #include "core/project_settings.h"
 #include "core/register_core_types.h"
 #include "core/script_debugger_local.h"
-#include "core/script_debugger_remote.h"
 #include "core/script_language.h"
 #include "core/translation.h"
 #include "core/version.h"
@@ -59,6 +58,7 @@
 #include "main/tests/test_main.h"
 #include "modules/register_module_types.h"
 #include "platform/register_platform_apis.h"
+#include "scene/debugger/script_debugger_remote.h"
 #include "scene/main/scene_tree.h"
 #include "scene/main/viewport.h"
 #include "scene/register_scene_types.h"
@@ -1581,6 +1581,12 @@ bool Main::start() {
 
 		if (!project_manager && !editor) { // game
 			if (game_path != "" || script != "") {
+				if (script_debugger && script_debugger->is_remote()) {
+					ScriptDebuggerRemote *remote_debugger = static_cast<ScriptDebuggerRemote *>(script_debugger);
+
+					remote_debugger->set_scene_tree(sml);
+				}
+
 				//autoload
 				List<PropertyInfo> props;
 				ProjectSettings::get_singleton()->get_property_list(&props);

+ 1 - 0
scene/SCsub

@@ -30,6 +30,7 @@ SConscript('2d/SCsub')
 SConscript('animation/SCsub')
 SConscript('audio/SCsub')
 SConscript('resources/SCsub')
+SConscript('debugger/SCsub')
 
 
 # Build it all as a library

+ 5 - 0
scene/debugger/SCsub

@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import('env')
+
+env.add_source_files(env.scene_sources, "*.cpp")

+ 115 - 57
core/script_debugger_remote.cpp → scene/debugger/script_debugger_remote.cpp

@@ -37,7 +37,10 @@
 #include "core/os/os.h"
 #include "core/project_settings.h"
 #include "scene/main/node.h"
+#include "scene/main/scene_tree.h"
+#include "scene/main/viewport.h"
 #include "scene/resources/packed_scene.h"
+#include "servers/visual_server.h"
 
 void ScriptDebuggerRemote::_send_video_memory() {
 
@@ -150,7 +153,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue,
 	if (mouse_mode != Input::MOUSE_MODE_VISIBLE)
 		Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
 
+	uint64_t loop_begin_usec = 0;
+	uint64_t loop_time_sec = 0;
 	while (true) {
+		loop_begin_usec = OS::get_singleton()->get_ticks_usec();
 
 		_get_output();
 
@@ -279,9 +285,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue,
 				break;
 			} else if (command == "request_scene_tree") {
 
-				if (request_scene_tree)
-					request_scene_tree(request_scene_tree_ud);
-
+#ifdef DEBUG_ENABLED
+				if (scene_tree)
+					scene_tree->_debugger_request_tree();
+#endif
 			} else if (command == "request_video_mem") {
 
 				_send_video_memory();
@@ -293,6 +300,40 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue,
 
 				_set_object_property(cmd[1], cmd[2], cmd[3]);
 
+			} else if (command == "override_camera_2D:set") {
+				bool enforce = cmd[1];
+
+				if (scene_tree) {
+					scene_tree->get_root()->enable_canvas_transform_override(enforce);
+				}
+			} else if (command == "override_camera_2D:transform") {
+				Transform2D transform = cmd[1];
+
+				if (scene_tree) {
+					scene_tree->get_root()->set_canvas_transform_override(transform);
+				}
+			} else if (command == "override_camera_3D:set") {
+				bool enable = cmd[1];
+
+				if (scene_tree) {
+					scene_tree->get_root()->enable_camera_override(enable);
+				}
+			} else if (command == "override_camera_3D:transform") {
+				Transform transform = cmd[1];
+				bool is_perspective = cmd[2];
+				float size_or_fov = cmd[3];
+				float near = cmd[4];
+				float far = cmd[5];
+
+				if (scene_tree) {
+					if (is_perspective) {
+						scene_tree->get_root()->set_camera_override_perspective(size_or_fov, near, far);
+					} else {
+						scene_tree->get_root()->set_camera_override_orthogonal(size_or_fov, near, far);
+					}
+					scene_tree->get_root()->set_camera_override_transform(transform);
+				}
+
 			} else if (command == "reload_scripts") {
 				reload_all_scripts = true;
 			} else if (command == "breakpoint") {
@@ -315,6 +356,13 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue,
 			OS::get_singleton()->delay_usec(10000);
 			OS::get_singleton()->process_and_drop_events();
 		}
+
+		// This is for the camera override to stay live even when the game is paused from the editor
+		loop_time_sec = (OS::get_singleton()->get_ticks_usec() - loop_begin_usec) / 1000000.0f;
+		VisualServer::get_singleton()->sync();
+		if (VisualServer::get_singleton()->has_changed()) {
+			VisualServer::get_singleton()->draw(true, loop_time_sec * Engine::get_singleton()->get_time_scale());
+		}
 	}
 
 	packet_peer_stream->put_var("debug_exit");
@@ -446,93 +494,75 @@ void ScriptDebuggerRemote::_err_handler(void *ud, const char *p_func, const char
 
 bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) {
 
+#ifdef DEBUG_ENABLED
+
 	String cmdstr = p_command[0];
-	if (!live_edit_funcs || !cmdstr.begins_with("live_"))
+	if (!scene_tree || !cmdstr.begins_with("live_"))
 		return false;
 
-	//print_line(Variant(cmd).get_construct_string());
 	if (cmdstr == "live_set_root") {
 
-		if (!live_edit_funcs->root_func)
-			return true;
-		//print_line("root: "+Variant(cmd).get_construct_string());
-		live_edit_funcs->root_func(live_edit_funcs->udata, p_command[1], p_command[2]);
+		scene_tree->_live_edit_root_func(p_command[1], p_command[2]);
 
 	} else if (cmdstr == "live_node_path") {
 
-		if (!live_edit_funcs->node_path_func)
-			return true;
-		//print_line("path: "+Variant(cmd).get_construct_string());
-
-		live_edit_funcs->node_path_func(live_edit_funcs->udata, p_command[1], p_command[2]);
+		scene_tree->_live_edit_node_path_func(p_command[1], p_command[2]);
 
 	} else if (cmdstr == "live_res_path") {
 
-		if (!live_edit_funcs->res_path_func)
-			return true;
-		live_edit_funcs->res_path_func(live_edit_funcs->udata, p_command[1], p_command[2]);
+		scene_tree->_live_edit_res_path_func(p_command[1], p_command[2]);
 
 	} else if (cmdstr == "live_node_prop_res") {
-		if (!live_edit_funcs->node_set_res_func)
-			return true;
 
-		live_edit_funcs->node_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_node_set_res_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_node_prop") {
 
-		if (!live_edit_funcs->node_set_func)
-			return true;
-		live_edit_funcs->node_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_node_set_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_res_prop_res") {
 
-		if (!live_edit_funcs->res_set_res_func)
-			return true;
-		live_edit_funcs->res_set_res_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_res_set_res_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_res_prop") {
 
-		if (!live_edit_funcs->res_set_func)
-			return true;
-		live_edit_funcs->res_set_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_res_set_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_node_call") {
 
-		if (!live_edit_funcs->node_call_func)
-			return true;
-		live_edit_funcs->node_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]);
+		scene_tree->_live_edit_node_call_func(p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]);
 
 	} else if (cmdstr == "live_res_call") {
 
-		if (!live_edit_funcs->res_call_func)
-			return true;
-		live_edit_funcs->res_call_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]);
+		scene_tree->_live_edit_res_call_func(p_command[1], p_command[2], p_command[3], p_command[4], p_command[5], p_command[6], p_command[7]);
 
 	} else if (cmdstr == "live_create_node") {
 
-		live_edit_funcs->tree_create_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_create_node_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_instance_node") {
 
-		live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_instance_node_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_remove_node") {
 
-		live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata, p_command[1]);
+		scene_tree->_live_edit_remove_node_func(p_command[1]);
 
 	} else if (cmdstr == "live_remove_and_keep_node") {
 
-		live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata, p_command[1], p_command[2]);
+		scene_tree->_live_edit_remove_and_keep_node_func(p_command[1], p_command[2]);
+
 	} else if (cmdstr == "live_restore_node") {
 
-		live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3]);
+		scene_tree->_live_edit_restore_node_func(p_command[1], p_command[2], p_command[3]);
 
 	} else if (cmdstr == "live_duplicate_node") {
 
-		live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata, p_command[1], p_command[2]);
+		scene_tree->_live_edit_duplicate_node_func(p_command[1], p_command[2]);
+
 	} else if (cmdstr == "live_reparent_node") {
 
-		live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata, p_command[1], p_command[2], p_command[3], p_command[4]);
+		scene_tree->_live_edit_reparent_node_func(p_command[1], p_command[2], p_command[3], p_command[4]);
 
 	} else {
 
@@ -540,6 +570,10 @@ bool ScriptDebuggerRemote::_parse_live_edit(const Array &p_command) {
 	}
 
 	return true;
+#else
+
+	return false;
+#endif
 }
 
 void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) {
@@ -732,8 +766,10 @@ void ScriptDebuggerRemote::_poll_events() {
 				debug(get_break_language());
 		} else if (command == "request_scene_tree") {
 
-			if (request_scene_tree)
-				request_scene_tree(request_scene_tree_ud);
+#ifdef DEBUG_ENABLED
+			if (scene_tree)
+				scene_tree->_debugger_request_tree();
+#endif
 		} else if (command == "request_video_mem") {
 
 			_send_video_memory();
@@ -777,6 +813,40 @@ void ScriptDebuggerRemote::_poll_events() {
 
 			multiplayer->profiling_end();
 			profiling_network = false;
+		} else if (command == "override_camera_2D:set") {
+			bool enforce = cmd[1];
+
+			if (scene_tree) {
+				scene_tree->get_root()->enable_canvas_transform_override(enforce);
+			}
+		} else if (command == "override_camera_2D:transform") {
+			Transform2D transform = cmd[1];
+
+			if (scene_tree) {
+				scene_tree->get_root()->set_canvas_transform_override(transform);
+			}
+		} else if (command == "override_camera_3D:set") {
+			bool enable = cmd[1];
+
+			if (scene_tree) {
+				scene_tree->get_root()->enable_camera_override(enable);
+			}
+		} else if (command == "override_camera_3D:transform") {
+			Transform transform = cmd[1];
+			bool is_perspective = cmd[2];
+			float size_or_fov = cmd[3];
+			float near = cmd[4];
+			float far = cmd[5];
+
+			if (scene_tree) {
+				if (is_perspective) {
+					scene_tree->get_root()->set_camera_override_perspective(size_or_fov, near, far);
+				} else {
+					scene_tree->get_root()->set_camera_override_orthogonal(size_or_fov, near, far);
+				}
+				scene_tree->get_root()->set_camera_override_transform(transform);
+			}
+
 		} else if (command == "reload_scripts") {
 			reload_all_scripts = true;
 		} else if (command == "breakpoint") {
@@ -1106,17 +1176,6 @@ void ScriptDebuggerRemote::request_quit() {
 	requested_quit = true;
 }
 
-void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {
-
-	request_scene_tree = p_func;
-	request_scene_tree_ud = p_udata;
-}
-
-void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
-
-	live_edit_funcs = p_funcs;
-}
-
 void ScriptDebuggerRemote::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
 	multiplayer = p_multiplayer;
 }
@@ -1195,8 +1254,7 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() :
 		msec_count(0),
 		locking(false),
 		poll_every(0),
-		request_scene_tree(NULL),
-		live_edit_funcs(NULL) {
+		scene_tree(NULL) {
 
 	packet_peer_stream->set_stream_peer(tcp_client);
 	packet_peer_stream->set_output_buffer_max_size(1024 * 1024 * 8); //8mb should be way more than enough

+ 6 - 6
core/script_debugger_remote.h → scene/debugger/script_debugger_remote.h

@@ -37,6 +37,8 @@
 #include "core/os/os.h"
 #include "core/script_language.h"
 
+class SceneTree;
+
 class ScriptDebuggerRemote : public ScriptDebugger {
 
 	struct Message {
@@ -116,16 +118,14 @@ class ScriptDebuggerRemote : public ScriptDebugger {
 	void _poll_events();
 	uint32_t poll_every;
 
-	bool _parse_live_edit(const Array &p_command);
+	SceneTree *scene_tree;
 
-	RequestSceneTreeMessageFunc request_scene_tree;
-	void *request_scene_tree_ud;
+	bool _parse_live_edit(const Array &p_command);
 
 	void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value);
 
 	void _send_object_id(ObjectID p_id);
 	void _send_video_memory();
-	LiveEditFuncs *live_edit_funcs;
 
 	Ref<MultiplayerAPI> multiplayer;
 
@@ -176,8 +176,6 @@ public:
 	virtual void send_message(const String &p_message, const Array &p_args);
 	virtual void send_error(const String &p_func, const String &p_file, int p_line, const String &p_err, const String &p_descr, ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> &p_stack_info);
 
-	virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
-	virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
 	virtual void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
 
 	virtual bool is_profiling() const;
@@ -189,6 +187,8 @@ public:
 
 	virtual void set_skip_breakpoints(bool p_skip_breakpoints);
 
+	void set_scene_tree(SceneTree *p_scene_tree) { scene_tree = p_scene_tree; };
+
 	ScriptDebuggerRemote();
 	~ScriptDebuggerRemote();
 };

+ 25 - 45
scene/main/scene_tree.cpp

@@ -40,6 +40,7 @@
 #include "core/project_settings.h"
 #include "main/input_default.h"
 #include "node.h"
+#include "scene/debugger/script_debugger_remote.h"
 #include "scene/resources/dynamic_font.h"
 #include "scene/resources/material.h"
 #include "scene/resources/mesh.h"
@@ -1094,27 +1095,6 @@ void SceneTree::get_nodes_in_group(const StringName &p_group, List<Node *> *p_li
 	}
 }
 
-static void _fill_array(Node *p_node, Array &array, int p_level) {
-
-	array.push_back(p_node->get_child_count());
-	array.push_back(p_node->get_name());
-	array.push_back(p_node->get_class());
-	array.push_back(p_node->get_instance_id());
-	for (int i = 0; i < p_node->get_child_count(); i++) {
-
-		_fill_array(p_node->get_child(i), array, p_level + 1);
-	}
-}
-
-void SceneTree::_debugger_request_tree(void *self) {
-
-	SceneTree *sml = (SceneTree *)self;
-
-	Array arr;
-	_fill_array(sml->root, arr, 0);
-	ScriptDebugger::get_singleton()->send_message("scene_tree", arr);
-}
-
 void SceneTree::_flush_delete_queue() {
 
 	_THREAD_SAFE_METHOD_
@@ -1337,6 +1317,25 @@ void SceneTree::add_current_scene(Node *p_current) {
 }
 #ifdef DEBUG_ENABLED
 
+static void _fill_array(Node *p_node, Array &array, int p_level) {
+
+	array.push_back(p_node->get_child_count());
+	array.push_back(p_node->get_name());
+	array.push_back(p_node->get_class());
+	array.push_back(p_node->get_instance_id());
+	for (int i = 0; i < p_node->get_child_count(); i++) {
+
+		_fill_array(p_node->get_child(i), array, p_level + 1);
+	}
+}
+
+void SceneTree::_debugger_request_tree() {
+
+	Array arr;
+	_fill_array(root, arr, 0);
+	ScriptDebugger::get_singleton()->send_message("scene_tree", arr);
+}
+
 void SceneTree::_live_edit_node_path_func(const NodePath &p_path, int p_id) {
 
 	live_edit_node_path_cache[p_id] = p_path;
@@ -2117,7 +2116,11 @@ SceneTree::SceneTree() {
 	_update_root_rect();
 
 	if (ScriptDebugger::get_singleton()) {
-		ScriptDebugger::get_singleton()->set_request_scene_tree_message_func(_debugger_request_tree, this);
+		if (ScriptDebugger::get_singleton()->is_remote()) {
+			ScriptDebuggerRemote *remote_debugger = static_cast<ScriptDebuggerRemote *>(ScriptDebugger::get_singleton());
+
+			remote_debugger->set_scene_tree(this);
+		}
 		ScriptDebugger::get_singleton()->set_multiplayer(multiplayer);
 	}
 
@@ -2129,29 +2132,6 @@ SceneTree::SceneTree() {
 
 #ifdef DEBUG_ENABLED
 
-	live_edit_funcs.udata = this;
-	live_edit_funcs.node_path_func = _live_edit_node_path_funcs;
-	live_edit_funcs.res_path_func = _live_edit_res_path_funcs;
-	live_edit_funcs.node_set_func = _live_edit_node_set_funcs;
-	live_edit_funcs.node_set_res_func = _live_edit_node_set_res_funcs;
-	live_edit_funcs.node_call_func = _live_edit_node_call_funcs;
-	live_edit_funcs.res_set_func = _live_edit_res_set_funcs;
-	live_edit_funcs.res_set_res_func = _live_edit_res_set_res_funcs;
-	live_edit_funcs.res_call_func = _live_edit_res_call_funcs;
-	live_edit_funcs.root_func = _live_edit_root_funcs;
-
-	live_edit_funcs.tree_create_node_func = _live_edit_create_node_funcs;
-	live_edit_funcs.tree_instance_node_func = _live_edit_instance_node_funcs;
-	live_edit_funcs.tree_remove_node_func = _live_edit_remove_node_funcs;
-	live_edit_funcs.tree_remove_and_keep_node_func = _live_edit_remove_and_keep_node_funcs;
-	live_edit_funcs.tree_restore_node_func = _live_edit_restore_node_funcs;
-	live_edit_funcs.tree_duplicate_node_func = _live_edit_duplicate_node_funcs;
-	live_edit_funcs.tree_reparent_node_func = _live_edit_reparent_node_funcs;
-
-	if (ScriptDebugger::get_singleton()) {
-		ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs);
-	}
-
 	live_edit_root = NodePath("/root");
 
 #endif

+ 2 - 21
scene/main/scene_tree.h

@@ -211,7 +211,6 @@ private:
 	Variant _call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
 	Variant _call_group(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
 
-	static void _debugger_request_tree(void *self);
 	void _flush_delete_queue();
 	//optimization
 	friend class CanvasItem;
@@ -220,6 +219,7 @@ private:
 
 	SelfList<Node>::List xform_change_list;
 
+	friend class ScriptDebuggerRemote;
 #ifdef DEBUG_ENABLED
 
 	Map<int, NodePath> live_edit_node_path_cache;
@@ -231,7 +231,7 @@ private:
 	Map<String, Set<Node *> > live_scene_edit_cache;
 	Map<Node *, Map<ObjectID, Node *> > live_edit_remove_list;
 
-	ScriptDebugger::LiveEditFuncs live_edit_funcs;
+	void _debugger_request_tree();
 
 	void _live_edit_node_path_func(const NodePath &p_path, int p_id);
 	void _live_edit_res_path_func(const String &p_path, int p_id);
@@ -252,25 +252,6 @@ private:
 	void _live_edit_duplicate_node_func(const NodePath &p_at, const String &p_new_name);
 	void _live_edit_reparent_node_func(const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos);
 
-	static void _live_edit_node_path_funcs(void *self, const NodePath &p_path, int p_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_path_func(p_path, p_id); }
-	static void _live_edit_res_path_funcs(void *self, const String &p_path, int p_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_path_func(p_path, p_id); }
-
-	static void _live_edit_node_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_set_func(p_id, p_prop, p_value); }
-	static void _live_edit_node_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_set_res_func(p_id, p_prop, p_value); }
-	static void _live_edit_node_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree *>(self)->_live_edit_node_call_func(p_id, p_method, VARIANT_ARG_PASS); }
-	static void _live_edit_res_set_funcs(void *self, int p_id, const StringName &p_prop, const Variant &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_set_func(p_id, p_prop, p_value); }
-	static void _live_edit_res_set_res_funcs(void *self, int p_id, const StringName &p_prop, const String &p_value) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_set_res_func(p_id, p_prop, p_value); }
-	static void _live_edit_res_call_funcs(void *self, int p_id, const StringName &p_method, VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree *>(self)->_live_edit_res_call_func(p_id, p_method, VARIANT_ARG_PASS); }
-	static void _live_edit_root_funcs(void *self, const NodePath &p_scene_path, const String &p_scene_from) { reinterpret_cast<SceneTree *>(self)->_live_edit_root_func(p_scene_path, p_scene_from); }
-
-	static void _live_edit_create_node_funcs(void *self, const NodePath &p_parent, const String &p_type, const String &p_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_create_node_func(p_parent, p_type, p_name); }
-	static void _live_edit_instance_node_funcs(void *self, const NodePath &p_parent, const String &p_path, const String &p_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_instance_node_func(p_parent, p_path, p_name); }
-	static void _live_edit_remove_node_funcs(void *self, const NodePath &p_at) { reinterpret_cast<SceneTree *>(self)->_live_edit_remove_node_func(p_at); }
-	static void _live_edit_remove_and_keep_node_funcs(void *self, const NodePath &p_at, ObjectID p_keep_id) { reinterpret_cast<SceneTree *>(self)->_live_edit_remove_and_keep_node_func(p_at, p_keep_id); }
-	static void _live_edit_restore_node_funcs(void *self, ObjectID p_id, const NodePath &p_at, int p_at_pos) { reinterpret_cast<SceneTree *>(self)->_live_edit_restore_node_func(p_id, p_at, p_at_pos); }
-	static void _live_edit_duplicate_node_funcs(void *self, const NodePath &p_at, const String &p_new_name) { reinterpret_cast<SceneTree *>(self)->_live_edit_duplicate_node_func(p_at, p_new_name); }
-	static void _live_edit_reparent_node_funcs(void *self, const NodePath &p_at, const NodePath &p_new_place, const String &p_new_name, int p_at_pos) { reinterpret_cast<SceneTree *>(self)->_live_edit_reparent_node_func(p_at, p_new_place, p_new_name, p_at_pos); }
-
 #endif
 
 	enum {

+ 116 - 6
scene/main/viewport.cpp

@@ -779,10 +779,45 @@ bool Viewport::is_audio_listener_2d() const {
 	return audio_listener_2d;
 }
 
+void Viewport::enable_canvas_transform_override(bool p_enable) {
+	if (override_canvas_transform == p_enable) {
+		return;
+	}
+
+	override_canvas_transform = p_enable;
+	if (p_enable) {
+		VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+	} else {
+		VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+	}
+}
+
+bool Viewport::is_canvas_transform_override_enbled() const {
+	return override_canvas_transform;
+}
+
+void Viewport::set_canvas_transform_override(const Transform2D &p_transform) {
+	if (canvas_transform_override == p_transform) {
+		return;
+	}
+
+	canvas_transform_override = p_transform;
+	if (override_canvas_transform) {
+		VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform_override);
+	}
+}
+
+Transform2D Viewport::get_canvas_transform_override() const {
+	return canvas_transform_override;
+}
+
 void Viewport::set_canvas_transform(const Transform2D &p_transform) {
 
 	canvas_transform = p_transform;
-	VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+
+	if (!override_canvas_transform) {
+		VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, find_world_2d()->get_canvas(), canvas_transform);
+	}
 }
 
 Transform2D Viewport::get_canvas_transform() const {
@@ -890,10 +925,12 @@ void Viewport::_camera_set(Camera *p_camera) {
 		camera->notification(Camera::NOTIFICATION_LOST_CURRENT);
 	}
 	camera = p_camera;
-	if (camera)
-		VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
-	else
-		VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+	if (!camera_override) {
+		if (camera)
+			VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+		else
+			VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+	}
 
 	if (camera) {
 		camera->notification(Camera::NOTIFICATION_BECAME_CURRENT);
@@ -1108,10 +1145,82 @@ Listener *Viewport::get_listener() const {
 }
 
 Camera *Viewport::get_camera() const {
-
 	return camera;
 }
 
+void Viewport::enable_camera_override(bool p_enable) {
+
+#ifndef _3D_DISABLED
+	if (p_enable == camera_override) {
+		return;
+	}
+
+	if (p_enable) {
+		camera_override.rid = VisualServer::get_singleton()->camera_create();
+	} else {
+		VisualServer::get_singleton()->free(camera_override.rid);
+		camera_override.rid = RID();
+	}
+
+	if (p_enable) {
+		VisualServer::get_singleton()->viewport_attach_camera(viewport, camera_override.rid);
+	} else if (camera) {
+		VisualServer::get_singleton()->viewport_attach_camera(viewport, camera->get_camera());
+	} else {
+		VisualServer::get_singleton()->viewport_attach_camera(viewport, RID());
+	}
+#endif
+}
+
+bool Viewport::is_camera_override_enabled() const {
+	return camera_override;
+}
+
+void Viewport::set_camera_override_transform(const Transform &p_transform) {
+	if (camera_override) {
+		camera_override.transform = p_transform;
+		VisualServer::get_singleton()->camera_set_transform(camera_override.rid, p_transform);
+	}
+}
+
+Transform Viewport::get_camera_override_transform() const {
+	if (camera_override) {
+		return camera_override.transform;
+	}
+
+	return Transform();
+}
+
+void Viewport::set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) {
+	if (camera_override) {
+		if (camera_override.fov == p_fovy_degrees && camera_override.z_near == p_z_near &&
+				camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_PERSPECTIVE)
+			return;
+
+		camera_override.fov = p_fovy_degrees;
+		camera_override.z_near = p_z_near;
+		camera_override.z_far = p_z_far;
+		camera_override.projection = CameraOverrideData::PROJECTION_PERSPECTIVE;
+
+		VisualServer::get_singleton()->camera_set_perspective(camera_override.rid, camera_override.fov, camera_override.z_near, camera_override.z_far);
+	}
+}
+
+void Viewport::set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far) {
+	if (camera_override) {
+		if (camera_override.size == p_size && camera_override.z_near == p_z_near &&
+				camera_override.z_far == p_z_far && camera_override.projection == CameraOverrideData::PROJECTION_ORTHOGONAL)
+			return;
+
+		camera_override.size = p_size;
+		camera_override.z_near = p_z_near;
+		camera_override.z_far = p_z_far;
+		camera_override.projection = CameraOverrideData::PROJECTION_ORTHOGONAL;
+
+		VisualServer::get_singleton()->camera_set_orthogonal(camera_override.rid, camera_override.size, camera_override.z_near, camera_override.z_far);
+	}
+}
+
 Transform2D Viewport::get_final_transform() const {
 
 	return stretch_transform * global_canvas_transform;
@@ -3180,6 +3289,7 @@ Viewport::Viewport() {
 	parent = NULL;
 	listener = NULL;
 	camera = NULL;
+	override_canvas_transform = false;
 	canvas_layers.insert(NULL); // This eases picking code (interpreted as the canvas of the Viewport)
 	arvr = false;
 	size_override = false;

+ 36 - 0
scene/main/viewport.h

@@ -160,6 +160,24 @@ private:
 
 	bool arvr;
 
+	struct CameraOverrideData {
+		Transform transform;
+		enum Projection {
+			PROJECTION_PERSPECTIVE,
+			PROJECTION_ORTHOGONAL
+		};
+		Projection projection;
+		float fov;
+		float size;
+		float z_near;
+		float z_far;
+		RID rid;
+
+		operator bool() const {
+			return rid != RID();
+		}
+	} camera_override;
+
 	Camera *camera;
 	Set<Camera *> cameras;
 	Set<CanvasLayer *> canvas_layers;
@@ -173,6 +191,9 @@ private:
 	bool audio_listener_2d;
 	RID internal_listener_2d;
 
+	bool override_canvas_transform;
+
+	Transform2D canvas_transform_override;
 	Transform2D canvas_transform;
 	Transform2D global_canvas_transform;
 	Transform2D stretch_transform;
@@ -394,6 +415,15 @@ public:
 	Listener *get_listener() const;
 	Camera *get_camera() const;
 
+	void enable_camera_override(bool p_enable);
+	bool is_camera_override_enabled() const;
+
+	void set_camera_override_transform(const Transform &p_transform);
+	Transform get_camera_override_transform() const;
+
+	void set_camera_override_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
+	void set_camera_override_orthogonal(float p_size, float p_z_near, float p_z_far);
+
 	void set_use_arvr(bool p_use_arvr);
 	bool use_arvr();
 
@@ -418,6 +448,12 @@ public:
 	Ref<World2D> get_world_2d() const;
 	Ref<World2D> find_world_2d() const;
 
+	void enable_canvas_transform_override(bool p_enable);
+	bool is_canvas_transform_override_enbled() const;
+
+	void set_canvas_transform_override(const Transform2D &p_transform);
+	Transform2D get_canvas_transform_override() const;
+
 	void set_canvas_transform(const Transform2D &p_transform);
 	Transform2D get_canvas_transform() const;
 

+ 1 - 1
servers/register_server_types.cpp

@@ -56,12 +56,12 @@
 #include "audio_server.h"
 #include "camera/camera_feed.h"
 #include "camera_server.h"
-#include "core/script_debugger_remote.h"
 #include "physics/physics_server_sw.h"
 #include "physics_2d/physics_2d_server_sw.h"
 #include "physics_2d/physics_2d_server_wrap_mt.h"
 #include "physics_2d_server.h"
 #include "physics_server.h"
+#include "scene/debugger/script_debugger_remote.h"
 #include "visual/shader_types.h"
 #include "visual_server.h"