Ability to reload scripts on running game

This commit is contained in:
Juan Linietsky
2016-06-01 20:22:02 -03:00
parent 45752eaae4
commit 9e745b920f
12 changed files with 247 additions and 18 deletions

View File

@@ -1414,8 +1414,13 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class) {
Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDParser::ClassNode *p_class, bool p_keep_state) {
Map<StringName,Ref<GDScript> > old_subclasses;
if (p_keep_state) {
old_subclasses=p_script->subclasses;
}
p_script->native=Ref<GDNativeClass>();
p_script->base=Ref<GDScript>();
@@ -1429,6 +1434,7 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
p_script->member_indices.clear();
p_script->member_info.clear();
p_script->initializer=NULL;
p_script->subclasses.clear();
p_script->_owner=p_owner;
p_script->tool=p_class->tool;
@@ -1662,9 +1668,15 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
for(int i=0;i<p_class->subclasses.size();i++) {
StringName name = p_class->subclasses[i]->name;
Ref<GDScript> subclass = memnew( GDScript );
Ref<GDScript> subclass;
Error err = _parse_class(subclass.ptr(),p_script,p_class->subclasses[i]);
if (old_subclasses.has(name)) {
subclass=old_subclasses[name];
} else {
subclass.instance();
}
Error err = _parse_class(subclass.ptr(),p_script,p_class->subclasses[i],p_keep_state);
if (err)
return err;
@@ -1755,13 +1767,65 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
}
}
//validate instances if keeping state
if (p_keep_state) {
print_line("RELOAD KEEP "+p_script->path);
for (Set<Object*>::Element *E=p_script->instances.front();E;) {
Set<Object*>::Element *N = E->next();
ScriptInstance *si = E->get()->get_script_instance();
if (si->is_placeholder()) {
PlaceHolderScriptInstance *psi = static_cast<PlaceHolderScriptInstance*>(si);
if (p_script->is_tool()) {
//re-create as an instance
p_script->placeholders.erase(psi); //remove placeholder
GDInstance* instance = memnew( GDInstance );
instance->base_ref=E->get()->cast_to<Reference>();
instance->members.resize(p_script->member_indices.size());
instance->script=Ref<GDScript>(p_script);
instance->owner=E->get();
//needed for hot reloading
for(Map<StringName,GDScript::MemberInfo>::Element *E=p_script->member_indices.front();E;E=E->next()) {
instance->member_indices_cache[E->key()]=E->get().index;
}
instance->owner->set_script_instance(instance);
/* STEP 2, INITIALIZE AND CONSRTUCT */
Variant::CallError ce;
p_script->initializer->call(instance,NULL,0,ce);
if (ce.error!=Variant::CallError::CALL_OK) {
//well, tough luck, not goinna do anything here
}
}
} else {
print_line("RELOAD MEMBERS");
GDInstance *gi = static_cast<GDInstance*>(si);
gi->reload_members();
}
E=N;
}
}
#endif
p_script->valid=true;
return OK;
}
Error GDCompiler::compile(const GDParser *p_parser,GDScript *p_script) {
Error GDCompiler::compile(const GDParser *p_parser,GDScript *p_script,bool p_keep_state) {
err_line=-1;
err_column=-1;
@@ -1772,9 +1836,7 @@ Error GDCompiler::compile(const GDParser *p_parser,GDScript *p_script) {
source=p_script->get_path();
Error err = _parse_class(p_script,NULL,static_cast<const GDParser::ClassNode*>(root));
Error err = _parse_class(p_script,NULL,static_cast<const GDParser::ClassNode*>(root),p_keep_state);
if (err)
return err;