Browse Source

-scenes are properly reloaded when a dependency changes, fixes #2896
(it's clevery done so local changes to scenes are kept even if unsaved)

Juan Linietsky 9 years ago
parent
commit
7f96f0603e

+ 1 - 1
core/resource.h

@@ -144,7 +144,7 @@ public:
 
 #ifdef TOOLS_ENABLED
 
-	void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
+	virtual void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
 	uint64_t get_last_modified_time() const { return last_modified_time; }
 
 #endif

+ 11 - 0
scene/resources/packed_scene.cpp

@@ -1537,6 +1537,7 @@ void SceneState::add_editable_instance(const NodePath& p_path){
 SceneState::SceneState() {
 
 	base_scene_idx=-1;
+	last_modified_time=0;
 }
 
 
@@ -1596,6 +1597,15 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
 	return s;
 }
 
+void PackedScene::recreate_state() {
+
+	state = Ref<SceneState>( memnew( SceneState ));
+	state->set_path(get_path());
+#ifdef TOOLS_ENABLED
+	state->set_last_modified_time(get_last_modified_time());
+#endif
+}
+
 Ref<SceneState> PackedScene::get_state() {
 
 	return state;
@@ -1607,6 +1617,7 @@ void PackedScene::set_path(const String& p_path,bool p_take_over) {
 	Resource::set_path(p_path,p_take_over);
 }
 
+
 void PackedScene::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack);

+ 10 - 0
scene/resources/packed_scene.h

@@ -99,6 +99,8 @@ class SceneState : public Reference {
 
 	String path;
 
+	uint64_t last_modified_time;
+
 	_FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
 
 	static bool disable_placeholders;
@@ -162,6 +164,9 @@ public:
 	void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds);
 	void add_editable_instance(const NodePath& p_path);
 
+	virtual void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
+	uint64_t get_last_modified_time() const { return last_modified_time; }
+
 
 	SceneState();
 };
@@ -189,8 +194,13 @@ public:
 	bool can_instance() const;
 	Node *instance(bool p_gen_edit_state=false) const;
 
+	void recreate_state();
+
 	virtual void set_path(const String& p_path,bool p_take_over=false);
+#ifdef TOOLS_ENABLED
+	virtual void set_last_modified_time(uint64_t p_time) { state->set_last_modified_time(p_time); }
 
+#endif
 	Ref<SceneState> get_state();
 
 	PackedScene();

+ 90 - 0
tools/editor/editor_data.cpp

@@ -31,6 +31,9 @@
 #include "editor_settings.h"
 #include "os/dir_access.h"
 #include "io/resource_loader.h"
+#include "scene/resources/packed_scene.h"
+#include "os/file_access.h"
+#include "editor_node.h"
 
 void EditorHistory::_cleanup_history() {
 
@@ -493,6 +496,93 @@ void EditorData::remove_scene(int p_idx){
 	edited_scene.remove(p_idx);
 
 }
+
+bool EditorData::_find_updated_instances(Node* p_root,Node *p_node,Set<String> &checked_paths) {
+
+	if (p_root!=p_node && p_node->get_owner()!=p_root && !p_root->is_editable_instance(p_node->get_owner()))
+		return false;
+
+	Ref<SceneState> ss;
+
+	if (p_node==p_root) {
+		ss=p_node->get_scene_inherited_state();
+	} else if (p_node->get_filename()!=String()){
+		ss=p_node->get_scene_instance_state();
+	}
+
+	if (ss.is_valid()) {
+		String path = ss->get_path();
+
+		if (!checked_paths.has(path)) {
+
+			uint64_t modified_time = FileAccess::get_modified_time(path);
+			if (modified_time!=ss->get_last_modified_time()) {
+				return true; //external scene changed
+			}
+
+			checked_paths.insert(path);
+		}
+
+	}
+
+	for(int i=0;i<p_node->get_child_count();i++) {
+
+		bool found = _find_updated_instances(p_root,p_node->get_child(i),checked_paths);
+		if (found)
+			return true;
+	}
+
+	return false;
+}
+
+
+bool EditorData::check_and_update_scene(int p_idx) {
+
+	ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),false);
+	if (!edited_scene[p_idx].root)
+		return false;
+
+	Set<String> checked_scenes;
+
+
+	bool must_reload = _find_updated_instances(edited_scene[p_idx].root,edited_scene[p_idx].root,checked_scenes);
+
+	if (must_reload) {
+		Ref<PackedScene> pscene;
+		pscene.instance();
+
+		EditorProgress ep("update_scene","Updating Scene",2);
+		ep.step("Storing local changes..",0);
+		//pack first, so it stores diffs to previous version of saved scene
+		Error err = pscene->pack(edited_scene[p_idx].root);
+		ERR_FAIL_COND_V(err!=OK,false);
+		ep.step("Updating scene..",1);
+		Node *new_scene = pscene->instance(true);
+		ERR_FAIL_COND_V(!new_scene,false);
+
+		//transfer selection
+		List<Node*> new_selection;
+		for (List<Node*>::Element *E=edited_scene[p_idx].selection.front();E;E=E->next()) {
+			NodePath p = edited_scene[p_idx].root->get_path_to(E->get());
+			Node *new_node = new_scene->get_node(p);
+			if (new_node)
+				new_selection.push_back(new_node);
+		}
+
+		new_scene->set_filename( edited_scene[p_idx].root->get_filename() );
+
+		memdelete(edited_scene[p_idx].root);
+		edited_scene[p_idx].root=new_scene;
+		edited_scene[p_idx].selection=new_selection;
+
+		return true;
+
+	}
+
+	return false;
+
+}
+
 int EditorData::get_edited_scene() const {
 
 	return current_edited_scene;

+ 3 - 0
tools/editor/editor_data.h

@@ -144,6 +144,8 @@ private:
 	Vector<EditedScene> edited_scene;
 	int current_edited_scene;
 
+	bool _find_updated_instances(Node* p_root,Node *p_node,Set<String> &checked_paths);
+
 public:
 
 	EditorPlugin* get_editor(Object *p_object);
@@ -193,6 +195,7 @@ public:
 	void clear_edited_scenes();
 	void set_edited_scene_live_edit_root(const NodePath& p_root);
 	NodePath get_edited_scene_live_edit_root();
+	bool check_and_update_scene(int p_idx);
 
 
 	void set_plugin_window_layout(Ref<ConfigFile> p_layout);

+ 1 - 0
tools/editor/editor_import_export.cpp

@@ -43,6 +43,7 @@
 #include "tools/editor/plugins/script_editor_plugin.h"
 #include "io/zip_io.h"
 
+
 String EditorImportPlugin::validate_source_path(const String& p_path) {
 
 	String gp = Globals::get_singleton()->globalize_path(p_path);

+ 28 - 1
tools/editor/editor_node.cpp

@@ -955,7 +955,23 @@ void EditorNode::_save_scene(String p_file) {
 
 
 	_set_scene_metadata();
-	Ref<PackedScene> sdata = memnew( PackedScene );
+
+
+	Ref<PackedScene> sdata;
+
+	if (ResourceCache::has(p_file)) {
+		// something may be referencing this resource and we are good with that.
+		// we must update it, but also let the previous scene state go, as
+		// old version still work for referencing changes in instanced or inherited scenes
+
+		sdata = Ref<PackedScene>( ResourceCache::get(p_file)->cast_to<PackedScene>() );
+		if (sdata.is_valid())
+			sdata->recreate_state();
+		else
+			sdata.instance();
+	} else {
+		sdata.instance();
+	}
 	Error err = sdata->pack(scene);
 
 
@@ -3414,8 +3430,18 @@ void EditorNode::set_current_version(uint64_t p_version) {
 bool EditorNode::is_changing_scene() const {
 	return changing_scene;
 }
+
+void EditorNode::_clear_undo_history() {
+
+	get_undo_redo()->clear_history();
+}
+
 void EditorNode::set_current_scene(int p_idx) {
 
+	if (editor_data.check_and_update_scene(p_idx)) {
+		call_deferred("_clear_undo_history");
+	}
+
 	changing_scene=true;
 	editor_data.save_edited_scene_state(editor_selection,&editor_history,_get_main_scene_state());
 
@@ -4113,6 +4139,7 @@ void EditorNode::_bind_methods() {
 
 	ObjectTypeDB::bind_method("_toggle_search_bar",&EditorNode::_toggle_search_bar);
 	ObjectTypeDB::bind_method("_clear_search_box",&EditorNode::_clear_search_box);
+	ObjectTypeDB::bind_method("_clear_undo_history",&EditorNode::_clear_undo_history);
 
 	ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
 	ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);

+ 1 - 0
tools/editor/editor_node.h

@@ -540,6 +540,7 @@ class EditorNode : public Node {
 
 	void _toggle_search_bar(bool p_pressed);
 	void _clear_search_box();
+	void _clear_undo_history();
 
 protected:
 	void _notification(int p_what);