diff options
author | Juan Linietsky <reduzio@gmail.com> | 2016-06-01 20:22:02 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2016-06-01 20:31:42 -0300 |
commit | 9e745b920fec25f1088ae0377a8d87a87136a5f7 (patch) | |
tree | 67c35840fb0eee8b380fafdbe46b696925d0f1fd /modules/gdscript/gd_script.cpp | |
parent | 45752eaae4a97b93c794651aa1b8dfec3c4f4d95 (diff) | |
download | redot-engine-9e745b920fec25f1088ae0377a8d87a87136a5f7.tar.gz |
Ability to reload scripts on running game
Diffstat (limited to 'modules/gdscript/gd_script.cpp')
-rw-r--r-- | modules/gdscript/gd_script.cpp | 125 |
1 files changed, 121 insertions, 4 deletions
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 7672faf620..dcd0641f76 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -101,6 +101,12 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj instance->members.resize(member_indices.size()); instance->script=Ref<GDScript>(this); instance->owner=p_owner; +#ifdef DEBUG_ENABLED + //needed for hot reloading + for(Map<StringName,MemberInfo>::Element *E=member_indices.front();E;E=E->next()) { + instance->member_indices_cache[E->key()]=E->get().index; + } +#endif instance->owner->set_script_instance(instance); /* STEP 2, INITIALIZE AND CONSRTUCT */ @@ -500,10 +506,10 @@ void GDScript::_set_subclass_path(Ref<GDScript>& p_sc,const String& p_path) { } } -Error GDScript::reload() { +Error GDScript::reload(bool p_keep_state) { - ERR_FAIL_COND_V(instances.size(),ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(!p_keep_state && instances.size(),ERR_ALREADY_IN_USE); String basedir=path; @@ -531,7 +537,7 @@ Error GDScript::reload() { bool can_run = ScriptServer::is_scripting_enabled() || parser.is_tool_script(); GDCompiler compiler; - err = compiler.compile(&parser,this); + err = compiler.compile(&parser,this,p_keep_state); if (err) { @@ -837,7 +843,7 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { } -GDScript::GDScript() { +GDScript::GDScript() : script_list(this) { _static_ref=this; @@ -851,12 +857,33 @@ GDScript::GDScript() { source_changed_cache=false; #endif +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->lock(); + } + GDScriptLanguage::get_singleton()->script_list.add(&script_list); + + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->unlock(); + } +#endif } GDScript::~GDScript() { for (Map<StringName,GDFunction*>::Element *E=member_functions.front();E;E=E->next()) { memdelete( E->get() ); } + +#ifdef DEBUG_ENABLED + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->lock(); + } + GDScriptLanguage::get_singleton()->script_list.remove(&script_list); + + if (GDScriptLanguage::get_singleton()->lock) { + GDScriptLanguage::get_singleton()->lock->unlock(); + } +#endif } @@ -1218,6 +1245,37 @@ ScriptLanguage *GDInstance::get_language() { return GDScriptLanguage::get_singleton(); } +void GDInstance::reload_members() { + +#ifdef DEBUG_ENABLED + + members.resize(script->member_indices.size()); //resize + + Vector<Variant> new_members; + new_members.resize(script->member_indices.size()); + + //pass the values to the new indices + for(Map<StringName,GDScript::MemberInfo>::Element *E=script->member_indices.front();E;E=E->next()) { + + if (member_indices_cache.has(E->key())) { + Variant value = members[member_indices_cache[E->key()]]; + new_members[E->get().index]=value; + } + + } + + //apply + members=new_members; + + //pass the values to the new indices + member_indices_cache.clear(); + for(Map<StringName,GDScript::MemberInfo>::Element *E=script->member_indices.front();E;E=E->next()) { + + member_indices_cache[E->key()]=E->get().index; + } + +#endif +} GDInstance::GDInstance() { owner=NULL; @@ -1441,6 +1499,65 @@ int GDScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr,int p_i } +struct GDScriptDepSort { + + //must support sorting so inheritance works properly (parent must be reloaded first) + bool operator()(const Ref<GDScript> &A, const Ref<GDScript>& B) const { + + if (A==B) + return false; //shouldn't happen but.. + const GDScript *I=B->get_base().ptr(); + while(I) { + if (I==A.ptr()) { + // A is a base of B + return true; + } + + I=I->get_base().ptr(); + } + + return false; //not a base + } +}; + +void GDScriptLanguage::reload_all_scripts() { + + + +#ifdef DEBUG_ENABLED + print_line("RELOAD ALL SCRIPTS"); + if (lock) { + lock->lock(); + } + + List<Ref<GDScript> > scripts; + + SelfList<GDScript> *elem=script_list.first(); + while(elem) { + if (elem->self()->get_path().is_resource_file()) { + print_line("FOUND: "+elem->self()->get_path()); + scripts.push_back(Ref<GDScript>(elem->self())); //cast to gdscript to avoid being erased by accident + } + elem=elem->next(); + } + + if (lock) { + lock->unlock(); + } + + //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()) { + + print_line("RELOADING: "+E->get()->get_path()); + E->get()->load_source_code(E->get()->get_path()); + E->get()->reload(true); + } +#endif +} + void GDScriptLanguage::frame() { // print_line("calls: "+itos(calls)); |