Преглед изворни кода

-Ability to reload (and soft reload) tool scripts. Please test!

Juan Linietsky пре 9 година
родитељ
комит
f8f30662d9

+ 1 - 0
core/script_language.h

@@ -192,6 +192,7 @@ public:
 	virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
 
 	virtual void reload_all_scripts()=0;
+	virtual void reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload)=0;
 	/* LOADER FUNCTIONS */
 
 	virtual void get_recognized_extensions(List<String> *p_extensions) const=0;

+ 107 - 0
modules/gdscript/gd_script.cpp

@@ -1558,6 +1558,113 @@ void GDScriptLanguage::reload_all_scripts() {
 #endif
 }
 
+
+void GDScriptLanguage::reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload) {
+
+
+#ifdef DEBUG_ENABLED
+
+	if (lock) {
+		lock->lock();
+	}
+
+	List<Ref<GDScript> > scripts;
+
+	SelfList<GDScript> *elem=script_list.first();
+	while(elem) {
+		if (elem->self()->get_path().is_resource_file()) {
+
+			scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident
+		}
+		elem=elem->next();
+	}
+
+	if (lock) {
+		lock->unlock();
+	}
+
+	//when someone asks you why dynamically typed languages are easier to write....
+
+	Map< Ref<GDScript>, Map<ObjectID,List<Pair<StringName,Variant> > > > to_reload;
+
+	//as scripts are going to be reloaded, must proceed without locking here
+
+	scripts.sort_custom<GDScriptDepSort>(); //update in inheritance dependency order
+
+	for(List<Ref<GDScript> >::Element *E=scripts.front();E;E=E->next()) {
+
+		bool reload = E->get()==p_script || to_reload.has(E->get()->get_base());
+
+		if (!reload)
+			continue;
+
+		to_reload.insert(E->get(),Map<ObjectID,List<Pair<StringName,Variant> > >());
+
+		if (!p_soft_reload) {
+
+			//save state and remove script from instances
+			Map<ObjectID,List<Pair<StringName,Variant> > >& map = to_reload[E->get()];
+
+			while(E->get()->instances.front()) {
+				Object *obj = E->get()->instances.front()->get();
+				//save instance info
+				List<Pair<StringName,Variant> > state;
+				if (obj->get_script_instance()) {
+
+					obj->get_script_instance()->get_property_state(state);
+					map[obj->get_instance_ID()]=state;
+					obj->set_script(RefPtr());
+				}
+			}
+
+			//same thing for placeholders
+#ifdef TOOLS_ENABLED
+
+			while(E->get()->placeholders.size()) {
+
+				Object *obj = E->get()->placeholders.front()->get()->get_owner();
+				//save instance info
+				List<Pair<StringName,Variant> > state;
+				if (obj->get_script_instance()) {
+
+					obj->get_script_instance()->get_property_state(state);
+					map[obj->get_instance_ID()]=state;
+					obj->set_script(RefPtr());
+				}
+			}
+#endif
+
+		}
+	}
+
+	for(Map< Ref<GDScript>, Map<ObjectID,List<Pair<StringName,Variant> > > >::Element *E=to_reload.front();E;E=E->next()) {
+
+		Ref<GDScript> scr = E->key();
+		scr->reload(true);
+
+		//restore state if saved
+		for (Map<ObjectID,List<Pair<StringName,Variant> > >::Element *F=E->get().front();F;F=F->next()) {
+
+			Object *obj = ObjectDB::get_instance(F->key());
+			if (!obj)
+				continue;
+
+			obj->set_script(scr.get_ref_ptr());
+			if (!obj->get_script_instance())
+				continue;
+
+			for (List<Pair<StringName,Variant> >::Element *G=F->get().front();G;G=G->next()) {
+				obj->get_script_instance()->set(G->get().first,G->get().second);
+			}
+		}
+
+		//if instance states were saved, set them!
+	}
+
+
+#endif
+}
+
 void GDScriptLanguage::frame() {
 
 	//	print_line("calls: "+itos(calls));

+ 1 - 0
modules/gdscript/gd_script.h

@@ -389,6 +389,7 @@ public:
 	virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1);
 
 	virtual void reload_all_scripts();
+	virtual void reload_tool_script(const Ref<Script>& p_script,bool p_soft_reload);
 
 	virtual void frame();
 

+ 13 - 0
tools/editor/plugins/script_editor_plugin.cpp

@@ -1411,6 +1411,16 @@ void ScriptEditor::_menu_option(int p_option) {
 				te->set_text(text);
 
 
+			} break;
+			case FILE_TOOL_RELOAD:
+			case FILE_TOOL_RELOAD_SOFT: {
+
+				TextEdit *te = current->get_text_edit();
+				Ref<Script> scr = current->get_edited_script();
+				if (scr.is_null())
+					return;
+				scr->set_source_code(te->get_text());
+				scr->get_language()->reload_tool_script(scr,p_option==FILE_TOOL_RELOAD_SOFT);
 			} break;
 			case EDIT_TRIM_TRAILING_WHITESAPCE: {
 				_trim_trailing_whitespace(current->get_text_edit());
@@ -2602,6 +2612,9 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 	edit_menu->get_popup()->add_item(TTR("Trim Trailing Whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE, KEY_MASK_CTRL|KEY_MASK_ALT|KEY_T);
 	edit_menu->get_popup()->add_item(TTR("Auto Indent"),EDIT_AUTO_INDENT,KEY_MASK_CMD|KEY_I);
 	edit_menu->get_popup()->connect("item_pressed", this,"_menu_option");
+	edit_menu->get_popup()->add_separator();
+	edit_menu->get_popup()->add_item(TTR("Reload Tool Script"),FILE_TOOL_RELOAD,KEY_MASK_CMD|KEY_R);
+	edit_menu->get_popup()->add_item(TTR("Reload Tool Script (Soft)"),FILE_TOOL_RELOAD_SOFT,KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_R);
 
 
 	search_menu = memnew( MenuButton );

+ 2 - 0
tools/editor/plugins/script_editor_plugin.h

@@ -142,6 +142,8 @@ class ScriptEditor : public VBoxContainer {
 		EDIT_INDENT_RIGHT,
 		EDIT_INDENT_LEFT,
 		EDIT_CLONE_DOWN,
+		FILE_TOOL_RELOAD,
+		FILE_TOOL_RELOAD_SOFT,
 		SEARCH_FIND,
 		SEARCH_FIND_NEXT,
 		SEARCH_FIND_PREV,