diff options
author | Juan Linietsky <reduzio@gmail.com> | 2015-08-02 12:29:37 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2015-08-02 12:30:01 -0300 |
commit | 59961c99144523d7cc2881a4abe6d0a319a975df (patch) | |
tree | 556cd9053433a27bbbc34dfe0a3e9fe693957299 /scene | |
parent | 922356b903061cda7591090bf19e8346c3a78cf5 (diff) |
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.
Diffstat (limited to 'scene')
-rw-r--r-- | scene/2d/tile_map.cpp | 5 | ||||
-rw-r--r-- | scene/2d/tile_map.h | 2 | ||||
-rw-r--r-- | scene/main/node.cpp | 101 | ||||
-rw-r--r-- | scene/main/node.h | 5 | ||||
-rw-r--r-- | scene/main/scene_main_loop.cpp | 322 | ||||
-rw-r--r-- | scene/main/scene_main_loop.h | 51 |
6 files changed, 476 insertions, 10 deletions
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 2fca1e67e8..17f93f816f 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -579,6 +579,10 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) { call_deferred("_update_dirty_quadrants"); } +void TileMap::set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { + + set_cell(p_pos.x,p_pos.y,p_tile,p_flip_x,p_flip_y,p_transpose); +} void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { @@ -1106,6 +1110,7 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce); ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_cellv","pos","tile","flip_x","flip_y","transpose"),&TileMap::set_cellv,DEFVAL(false),DEFVAL(false),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell); ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped); ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 84ca65da4f..60534cce15 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -207,6 +207,8 @@ public: bool is_cell_y_flipped(int p_x,int p_y) const; bool is_cell_transposed(int p_x,int p_y) const; + void set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false); + Rect2 get_item_rect() const; void set_collision_layer(uint32_t p_layer); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 7e31bf8dd0..5e0faae0a2 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -196,6 +196,14 @@ void Node::_propagate_enter_tree() { } data.blocked--; + +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + data.tree->live_scene_edit_cache[data.filename].insert(this); + } +#endif // enter groups } @@ -205,6 +213,19 @@ void Node::_propagate_exit_tree() { //block while removing children +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + Map<String,Set<Node*> >::Element *E=data.tree->live_scene_edit_cache.find(data.filename); + if (E) { + E->get().erase(this); + if (E->get().size()==0) { + data.tree->live_scene_edit_cache.erase(E); + } + } + } +#endif data.blocked++; for (int i=data.children.size()-1;i>=0;i--) { @@ -552,6 +573,52 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) { } + +String Node::validate_child_name(const String& p_name) const { + + //this approach to autoset node names is human readable but very slow + //it's turned on while running in the editor + + String basename = p_name; + + if (basename==String()) { + + return String(); + } + + int val=1; + + for(;;) { + + String attempted = val > 1 ? (basename + " " +itos(val) ) : basename; + + bool found=false; + + for (int i=0;i<data.children.size();i++) { + + //if (data.children[i]==p_child) + // continue; + if (data.children[i]->get_name() == attempted) { + found=true; + break; + } + + } + + if (found) { + + val++; + continue; + } + + return attempted; + break; + } + + return basename; + +} + void Node::_validate_child_name(Node *p_child) { /* Make sure the name is unique */ @@ -1323,18 +1390,31 @@ int Node::get_position_in_parent() const { -Node *Node::duplicate() const { +Node *Node::duplicate(bool p_use_instancing) const { Node *node=NULL; - Object *obj = ObjectTypeDB::instance(get_type()); - ERR_FAIL_COND_V(!obj,NULL); - node = obj->cast_to<Node>(); - if (!node) - memdelete(obj); - ERR_FAIL_COND_V(!node,NULL); + bool instanced=false; + + if (p_use_instancing && get_filename()!=String()) { + + Ref<PackedScene> res = ResourceLoader::load(get_filename()); + ERR_FAIL_COND_V(res.is_null(),NULL); + node=res->instance(); + ERR_FAIL_COND_V(!node,NULL); + + instanced=true; + + } else { + Object *obj = ObjectTypeDB::instance(get_type()); + ERR_FAIL_COND_V(!obj,NULL); + node = obj->cast_to<Node>(); + if (!node) + memdelete(obj); + ERR_FAIL_COND_V(!node,NULL); + } if (get_filename()!="") { //an instance @@ -1360,7 +1440,10 @@ Node *Node::duplicate() const { if (get_child(i)->data.parent_owned) continue; - Node *dup = get_child(i)->duplicate(); + if (instanced && get_child(i)->data.owner==this) + continue; //part of instance + + Node *dup = get_child(i)->duplicate(p_use_instancing); if (!dup) { memdelete(node); @@ -1882,7 +1965,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tree:SceneTree"),&Node::get_tree); - ObjectTypeDB::bind_method(_MD("duplicate:Node"),&Node::duplicate); + ObjectTypeDB::bind_method(_MD("duplicate:Node","use_instancing"),&Node::duplicate,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("replace_by","node:Node","keep_data"),&Node::replace_by,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_viewport"),&Node::get_viewport); diff --git a/scene/main/node.h b/scene/main/node.h index be91c6e1bb..a6d5bfbd9f 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -255,8 +255,9 @@ public: int get_position_in_parent() const; - Node *duplicate() const; + Node *duplicate(bool p_use_instancing=false) const; Node *duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const; + //Node *clone_tree() const; // used by editors, to save what has changed only @@ -275,6 +276,8 @@ public: static void print_stray_nodes(); + String validate_child_name(const String& p_name) const; + void queue_delete(); //shitty hacks for speed diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 1664a9bea1..9a05d6d4d0 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -1044,7 +1044,300 @@ void SceneTree::add_current_scene(Node * p_current) { current_scene=p_current; root->add_child(p_current); } +#ifdef DEBUG_ENABLED +void SceneTree::_live_edit_node_path_func(const NodePath &p_path,int p_id) { + + live_edit_node_path_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_res_path_func(const String &p_path,int p_id) { + + live_edit_resource_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->set(p_prop,p_value); + } + +} + +void SceneTree::_live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_node_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->call(p_method,VARIANT_ARG_PASS); + } +} +void SceneTree::_live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->set(p_prop,p_value); +} +void SceneTree::_live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_res_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->call(p_method,VARIANT_ARG_PASS); +} + +void SceneTree::_live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) { + + live_edit_root=p_scene_path; + live_edit_scene=p_scene_from; +} + +void SceneTree::_live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name) { + + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + Object *o = ObjectTypeDB::instance(p_type); + if (!o) + continue; + Node *no=o->cast_to<Node>(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name){ + + Ref<PackedScene> ps = ResourceLoader::load(p_path); + print_line("instance node?"); + if (!ps.is_valid()) + return; + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + + + Node *no=ps->instance(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_remove_node_func(const NodePath& p_at){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;) { + + Set<Node*>::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + memdelete(n2); + + F=N; + + } +} +void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id){ + + +} +void SceneTree::_live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos){ + + +} +void SceneTree::_live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Node *dup = n2->duplicate(true); + + if (!dup) + continue; + + dup->set_name(p_new_name); + + n2->get_parent()->add_child(dup); + + } +} +void SceneTree::_live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *nfrom = n->get_node(p_at); + + if (!n->has_node(p_new_place)) + continue; + Node *nto = n->get_node(p_new_place); + + nfrom->get_parent()->remove_child(nfrom); + nfrom->set_name(p_new_name); + + nto->add_child(nfrom); + + } +} + + +#endif void SceneTree::_bind_methods() { @@ -1169,6 +1462,35 @@ SceneTree::SceneTree() { edited_scene_root=NULL; #endif +#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 } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index e49c150fbf..94d0abe50f 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -164,6 +164,57 @@ friend class Viewport; SelfList<Node>::List xform_change_list; +#ifdef DEBUG_ENABLED + + Map<int,NodePath> live_edit_node_path_cache; + Map<int,String> live_edit_resource_cache; + + NodePath live_edit_root; + String live_edit_scene; + + Map<String,Set<Node*> > live_scene_edit_cache; + + ScriptDebugger::LiveEditFuncs live_edit_funcs; + + 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) ; + + void _live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) ; + + void _live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name); + void _live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name); + void _live_edit_remove_node_func(const NodePath& p_at); + void _live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id); + void _live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos); + 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); + + 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) { reinterpret_cast<SceneTree*>(self)->_live_edit_reparent_node_func(p_at,p_new_place,p_new_name); } + +#endif protected: void _notification(int p_notification); |