You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-05 12:10:55 +00:00
Live edit WORK IN PROGRESS
1) press the heart while the game is running 2) select a scene to live edit from the opened scenes 3) edit/add/remove nodes or resources, change their properties, etc. 4) watch changes reflected in running game, in all places this scene is edited 5) It's not perfect obviously, but the aim of it is to try to reflect your changes as best as possible in the running game.
This commit is contained in:
@@ -241,6 +241,8 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
|
||||
lv[level]=it;
|
||||
}
|
||||
|
||||
le_clear->set_disabled(false);
|
||||
le_set->set_disabled(false);
|
||||
|
||||
} else if (p_msg=="stack_dump") {
|
||||
|
||||
@@ -443,6 +445,8 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
||||
tb->set_hover_texture( get_icon("CloseHover","EditorIcons"));
|
||||
tb->set_pressed_texture( get_icon("Close","EditorIcons"));
|
||||
scene_tree_refresh->set_icon( get_icon("Reload","EditorIcons"));
|
||||
le_set->connect("pressed",this,"_live_edit_set");
|
||||
le_clear->connect("pressed",this,"_live_edit_clear");
|
||||
|
||||
} break;
|
||||
case NOTIFICATION_PROCESS: {
|
||||
@@ -468,6 +472,12 @@ void ScriptEditorDebugger::_notification(int p_what) {
|
||||
emit_signal("show_debugger",true);
|
||||
reason->set_text("Child Process Connected");
|
||||
reason->set_tooltip("Child Process Connected");
|
||||
scene_tree->clear();
|
||||
le_set->set_disabled(true);
|
||||
le_clear->set_disabled(false);
|
||||
//live_edit_root->set_text("/root");
|
||||
|
||||
update_live_edit_root();
|
||||
|
||||
} else {
|
||||
|
||||
@@ -613,6 +623,10 @@ void ScriptEditorDebugger::stop(){
|
||||
log_forced_visible=false;
|
||||
}
|
||||
|
||||
node_path_cache.clear();
|
||||
res_path_cache.clear();
|
||||
le_clear->set_disabled(false);
|
||||
le_set->set_disabled(true);
|
||||
|
||||
|
||||
hide();
|
||||
@@ -664,6 +678,335 @@ String ScriptEditorDebugger::get_var_value(const String& p_var) const {
|
||||
return variables->get_var_value(p_var);
|
||||
}
|
||||
|
||||
int ScriptEditorDebugger::_get_node_path_cache(const NodePath& p_path) {
|
||||
|
||||
const int *r = node_path_cache.getptr(p_path);
|
||||
if (r)
|
||||
return *r;
|
||||
|
||||
last_path_id++;
|
||||
|
||||
node_path_cache[p_path]=last_path_id;
|
||||
Array msg;
|
||||
msg.push_back("live_node_path");
|
||||
msg.push_back(p_path);
|
||||
msg.push_back(last_path_id);
|
||||
ppeer->put_var(msg);
|
||||
|
||||
|
||||
return last_path_id;
|
||||
}
|
||||
|
||||
int ScriptEditorDebugger::_get_res_path_cache(const String& p_path) {
|
||||
|
||||
Map<String,int>::Element *E=res_path_cache.find(p_path);
|
||||
|
||||
if (E)
|
||||
return E->get();
|
||||
|
||||
last_path_id++;
|
||||
|
||||
res_path_cache[p_path]=last_path_id;
|
||||
Array msg;
|
||||
msg.push_back("live_res_path");
|
||||
msg.push_back(p_path);
|
||||
msg.push_back(last_path_id);
|
||||
ppeer->put_var(msg);
|
||||
|
||||
|
||||
return last_path_id;
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_method_changed(Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE) {
|
||||
|
||||
if (!p_base || !live_debug || !connection.is_valid() || !editor->get_edited_scene())
|
||||
return;
|
||||
|
||||
Node *node = p_base->cast_to<Node>();
|
||||
|
||||
VARIANT_ARGPTRS
|
||||
|
||||
for(int i=0;i<VARIANT_ARG_MAX;i++) {
|
||||
//no pointers, sorry
|
||||
if (argptr[i] && (argptr[i]->get_type()==Variant::OBJECT || argptr[i]->get_type()==Variant::_RID))
|
||||
return;
|
||||
}
|
||||
|
||||
if (node) {
|
||||
|
||||
NodePath path = editor->get_edited_scene()->get_path_to(node);
|
||||
int pathid = _get_node_path_cache(path);
|
||||
|
||||
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_node_call");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_name);
|
||||
for(int i=0;i<VARIANT_ARG_MAX;i++) {
|
||||
//no pointers, sorry
|
||||
msg.push_back(*argptr[i]);
|
||||
}
|
||||
ppeer->put_var(msg);
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
Resource *res = p_base->cast_to<Resource>();
|
||||
|
||||
if (res && res->get_path()!=String()) {
|
||||
|
||||
String respath = res->get_path();
|
||||
int pathid = _get_res_path_cache(respath);
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_res_call");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_name);
|
||||
for(int i=0;i<VARIANT_ARG_MAX;i++) {
|
||||
//no pointers, sorry
|
||||
msg.push_back(*argptr[i]);
|
||||
}
|
||||
ppeer->put_var(msg);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//print_line("method");
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_property_changed(Object*p_base,const StringName& p_property,const Variant& p_value){
|
||||
|
||||
if (!p_base || !live_debug || !connection.is_valid() || !editor->get_edited_scene())
|
||||
return;
|
||||
|
||||
Node *node = p_base->cast_to<Node>();
|
||||
|
||||
if (node) {
|
||||
|
||||
NodePath path = editor->get_edited_scene()->get_path_to(node);
|
||||
int pathid = _get_node_path_cache(path);
|
||||
|
||||
|
||||
if (p_value.is_ref()) {
|
||||
Ref<Resource> res = p_value;
|
||||
if (res.is_valid() && res->get_path()!=String()) {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_node_prop_res");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_property);
|
||||
msg.push_back(res->get_path());
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
} else {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_node_prop");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_property);
|
||||
msg.push_back(p_value);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
Resource *res = p_base->cast_to<Resource>();
|
||||
|
||||
if (res && res->get_path()!=String()) {
|
||||
|
||||
String respath = res->get_path();
|
||||
int pathid = _get_res_path_cache(respath);
|
||||
|
||||
|
||||
if (p_value.is_ref()) {
|
||||
Ref<Resource> res = p_value;
|
||||
if (res.is_valid() && res->get_path()!=String()) {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_res_prop_res");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_property);
|
||||
msg.push_back(res->get_path());
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
} else {
|
||||
|
||||
Array msg;
|
||||
msg.push_back("live_res_prop");
|
||||
msg.push_back(pathid);
|
||||
msg.push_back(p_property);
|
||||
msg.push_back(p_value);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
//print_line("prop");
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_method_changeds(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE) {
|
||||
|
||||
ScriptEditorDebugger *sed = (ScriptEditorDebugger*)p_ud;
|
||||
sed->_method_changed(p_base,p_name,VARIANT_ARG_PASS);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_property_changeds(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value){
|
||||
|
||||
ScriptEditorDebugger *sed = (ScriptEditorDebugger*)p_ud;
|
||||
sed->_property_changed(p_base,p_property,p_value);
|
||||
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::set_live_debugging(bool p_enable) {
|
||||
|
||||
live_debug=p_enable;
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_live_edit_set() {
|
||||
|
||||
if (!connection.is_valid())
|
||||
return;
|
||||
|
||||
TreeItem* ti = scene_tree->get_selected();
|
||||
if (!ti)
|
||||
return;
|
||||
String path;
|
||||
|
||||
while(ti) {
|
||||
String lp=ti->get_text(0);
|
||||
path="/"+lp+path;
|
||||
ti=ti->get_parent();
|
||||
|
||||
}
|
||||
|
||||
NodePath np = path;
|
||||
|
||||
editor->get_editor_data().set_edited_scene_live_edit_root(np);
|
||||
|
||||
update_live_edit_root();
|
||||
|
||||
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::_live_edit_clear() {
|
||||
|
||||
NodePath np = NodePath("/root");
|
||||
editor->get_editor_data().set_edited_scene_live_edit_root(np);
|
||||
|
||||
update_live_edit_root();
|
||||
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::update_live_edit_root() {
|
||||
|
||||
NodePath np = editor->get_editor_data().get_edited_scene_live_edit_root();
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_set_root");
|
||||
msg.push_back(np);
|
||||
if (editor->get_edited_scene())
|
||||
msg.push_back(editor->get_edited_scene()->get_filename());
|
||||
else
|
||||
msg.push_back("");
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
live_edit_root->set_text(np);
|
||||
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::live_debug_create_node(const NodePath& p_parent,const String& p_type,const String& p_name) {
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_create_node");
|
||||
msg.push_back(p_parent);
|
||||
msg.push_back(p_type);
|
||||
msg.push_back(p_name);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEditorDebugger::live_debug_instance_node(const NodePath& p_parent,const String& p_path,const String& p_name){
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_instance_node");
|
||||
msg.push_back(p_parent);
|
||||
msg.push_back(p_path);
|
||||
msg.push_back(p_name);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptEditorDebugger::live_debug_remove_node(const NodePath& p_at){
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_remove_node");
|
||||
msg.push_back(p_at);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptEditorDebugger::live_debug_remove_and_keep_node(const NodePath& p_at,ObjectID p_keep_id) {
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_remove_and_keep_mode");
|
||||
msg.push_back(p_at);
|
||||
msg.push_back(p_keep_id);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptEditorDebugger::live_debug_restore_node(ObjectID p_id, const NodePath& p_at, int p_at_pos){
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_restore_node");
|
||||
msg.push_back(p_id);
|
||||
msg.push_back(p_at);
|
||||
msg.push_back(p_at_pos);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptEditorDebugger::live_debug_duplicate_node(const NodePath& p_at,const String& p_new_name){
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_duplicate_node");
|
||||
msg.push_back(p_at);
|
||||
msg.push_back(p_new_name);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
void ScriptEditorDebugger::live_debug_reparent_node(const NodePath& p_at, const NodePath& p_new_place, const String &p_new_name){
|
||||
|
||||
if (connection.is_valid()) {
|
||||
Array msg;
|
||||
msg.push_back("live_reparent_node");
|
||||
msg.push_back(p_at);
|
||||
msg.push_back(p_new_place);
|
||||
msg.push_back(p_new_name);
|
||||
ppeer->put_var(msg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ScriptEditorDebugger::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_stack_dump_frame_selected"),&ScriptEditorDebugger::_stack_dump_frame_selected);
|
||||
@@ -676,6 +1019,16 @@ void ScriptEditorDebugger::_bind_methods() {
|
||||
ObjectTypeDB::bind_method(_MD("_performance_draw"),&ScriptEditorDebugger::_performance_draw);
|
||||
ObjectTypeDB::bind_method(_MD("_performance_select"),&ScriptEditorDebugger::_performance_select);
|
||||
ObjectTypeDB::bind_method(_MD("_scene_tree_request"),&ScriptEditorDebugger::_scene_tree_request);
|
||||
ObjectTypeDB::bind_method(_MD("_live_edit_set"),&ScriptEditorDebugger::_live_edit_set);
|
||||
ObjectTypeDB::bind_method(_MD("_live_edit_clear"),&ScriptEditorDebugger::_live_edit_clear);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_create_node"),&ScriptEditorDebugger::live_debug_create_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_instance_node"),&ScriptEditorDebugger::live_debug_instance_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_remove_node"),&ScriptEditorDebugger::live_debug_remove_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_remove_and_keep_node"),&ScriptEditorDebugger::live_debug_remove_and_keep_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_restore_node"),&ScriptEditorDebugger::live_debug_restore_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_duplicate_node"),&ScriptEditorDebugger::live_debug_duplicate_node);
|
||||
ObjectTypeDB::bind_method(_MD("live_debug_reparent_node"),&ScriptEditorDebugger::live_debug_reparent_node);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("goto_script_line"));
|
||||
ADD_SIGNAL(MethodInfo("breaked",PropertyInfo(Variant::BOOL,"reallydid")));
|
||||
@@ -843,6 +1196,26 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
|
||||
info_left->add_margin_child("Clicked Control:",clicked_ctrl);
|
||||
clicked_ctrl_type = memnew( LineEdit );
|
||||
info_left->add_margin_child("Clicked Control Type:",clicked_ctrl_type);
|
||||
|
||||
live_edit_root = memnew( LineEdit );
|
||||
|
||||
{
|
||||
HBoxContainer *lehb = memnew( HBoxContainer );
|
||||
Label *l = memnew( Label("Live Edit Root:") );
|
||||
lehb->add_child(l);
|
||||
l->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
le_set = memnew( Button("Set From Tree") );
|
||||
lehb->add_child(le_set);
|
||||
le_clear = memnew( Button("Clear") );
|
||||
lehb->add_child(le_clear);
|
||||
info_left->add_child(lehb);
|
||||
MarginContainer *mc = memnew( MarginContainer );
|
||||
mc->add_child(live_edit_root);
|
||||
info_left->add_child(mc);
|
||||
le_set->set_disabled(true);
|
||||
le_clear->set_disabled(true);
|
||||
}
|
||||
|
||||
VBoxContainer *info_right = memnew(VBoxContainer);
|
||||
info_right->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
info->add_child(info_right);
|
||||
@@ -868,6 +1241,11 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
|
||||
hide();
|
||||
log_forced_visible=false;
|
||||
|
||||
p_editor->get_undo_redo()->set_method_notify_callback(_method_changeds,this);
|
||||
p_editor->get_undo_redo()->set_property_notify_callback(_property_changeds,this);
|
||||
live_debug=false;
|
||||
last_path_id=false;
|
||||
|
||||
}
|
||||
|
||||
ScriptEditorDebugger::~ScriptEditorDebugger() {
|
||||
|
||||
Reference in New Issue
Block a user