Global class names (and GDScript support for it)
This commit is contained in:
parent
f6ce73f724
commit
a3f1ee5c57
|
@ -515,7 +515,11 @@ Error ProjectSettings::_load_settings_text(const String p_path) {
|
|||
}
|
||||
} else {
|
||||
// config_version is checked and dropped
|
||||
set(section + "/" + assign, value);
|
||||
if (section == String()) {
|
||||
set(assign, value);
|
||||
} else {
|
||||
set(section + "/" + assign, value);
|
||||
}
|
||||
}
|
||||
} else if (next_tag.name != String()) {
|
||||
section = next_tag.name;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
/*************************************************************************/
|
||||
|
||||
#include "script_language.h"
|
||||
#include "project_settings.h"
|
||||
|
||||
ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
|
||||
int ScriptServer::_language_count = 0;
|
||||
|
@ -103,6 +104,20 @@ void ScriptServer::unregister_language(ScriptLanguage *p_language) {
|
|||
|
||||
void ScriptServer::init_languages() {
|
||||
|
||||
{ //load global classes
|
||||
global_classes_clear();
|
||||
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
|
||||
Array script_classes = ProjectSettings::get_singleton()->get("_global_script_classes");
|
||||
|
||||
for (int i = 0; i < script_classes.size(); i++) {
|
||||
Dictionary c = script_classes[i];
|
||||
if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base"))
|
||||
continue;
|
||||
add_global_class(c["class"], c["base"], c["language"], c["path"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _language_count; i++) {
|
||||
_languages[i]->init();
|
||||
}
|
||||
|
@ -113,6 +128,7 @@ void ScriptServer::finish_languages() {
|
|||
for (int i = 0; i < _language_count; i++) {
|
||||
_languages[i]->finish();
|
||||
}
|
||||
global_classes_clear();
|
||||
}
|
||||
|
||||
void ScriptServer::set_reload_scripts_on_save(bool p_enable) {
|
||||
|
@ -139,6 +155,67 @@ void ScriptServer::thread_exit() {
|
|||
}
|
||||
}
|
||||
|
||||
HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
|
||||
|
||||
void ScriptServer::global_classes_clear() {
|
||||
global_classes.clear();
|
||||
}
|
||||
|
||||
void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
|
||||
GlobalScriptClass g;
|
||||
g.language = p_language;
|
||||
g.path = p_path;
|
||||
g.base = p_base;
|
||||
global_classes[p_class] = g;
|
||||
}
|
||||
void ScriptServer::remove_global_class(const StringName &p_class) {
|
||||
global_classes.erase(p_class);
|
||||
}
|
||||
bool ScriptServer::is_global_class(const StringName &p_class) {
|
||||
return global_classes.has(p_class);
|
||||
}
|
||||
StringName ScriptServer::get_global_class_language(const StringName &p_class) {
|
||||
ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
|
||||
return global_classes[p_class].language;
|
||||
}
|
||||
String ScriptServer::get_global_class_path(const String &p_class) {
|
||||
ERR_FAIL_COND_V(!global_classes.has(p_class), String());
|
||||
return global_classes[p_class].path;
|
||||
}
|
||||
|
||||
StringName ScriptServer::get_global_class_base(const String &p_class) {
|
||||
ERR_FAIL_COND_V(!global_classes.has(p_class), String());
|
||||
return global_classes[p_class].base;
|
||||
}
|
||||
void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
|
||||
const StringName *K = NULL;
|
||||
List<StringName> classes;
|
||||
while ((K = global_classes.next(K))) {
|
||||
classes.push_back(*K);
|
||||
}
|
||||
classes.sort_custom<StringName::AlphCompare>();
|
||||
for (List<StringName>::Element *E = classes.front(); E; E = E->next()) {
|
||||
r_global_classes->push_back(E->get());
|
||||
}
|
||||
}
|
||||
void ScriptServer::save_global_classes() {
|
||||
List<StringName> gc;
|
||||
get_global_class_list(&gc);
|
||||
Array gcarr;
|
||||
for (List<StringName>::Element *E = gc.front(); E; E = E->next()) {
|
||||
Dictionary d;
|
||||
d["class"] = E->get();
|
||||
d["language"] = global_classes[E->get()].language;
|
||||
d["path"] = global_classes[E->get()].path;
|
||||
d["base"] = global_classes[E->get()].base;
|
||||
gcarr.push_back(d);
|
||||
}
|
||||
|
||||
ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
|
||||
ProjectSettings::get_singleton()->save();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
void ScriptInstance::get_property_state(List<Pair<StringName, Variant> > &state) {
|
||||
|
||||
List<PropertyInfo> pinfo;
|
||||
|
|
|
@ -54,6 +54,14 @@ class ScriptServer {
|
|||
static bool scripting_enabled;
|
||||
static bool reload_scripts_on_save;
|
||||
|
||||
struct GlobalScriptClass {
|
||||
StringName language;
|
||||
String path;
|
||||
String base;
|
||||
};
|
||||
|
||||
static HashMap<StringName, GlobalScriptClass> global_classes;
|
||||
|
||||
public:
|
||||
static ScriptEditRequestFunction edit_request_func;
|
||||
|
||||
|
@ -70,6 +78,16 @@ public:
|
|||
static void thread_enter();
|
||||
static void thread_exit();
|
||||
|
||||
static void global_classes_clear();
|
||||
static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path);
|
||||
static void remove_global_class(const StringName &p_class);
|
||||
static bool is_global_class(const StringName &p_class);
|
||||
static StringName get_global_class_language(const StringName &p_class);
|
||||
static String get_global_class_path(const String &p_class);
|
||||
static StringName get_global_class_base(const String &p_class);
|
||||
static void get_global_class_list(List<StringName> *r_global_classes);
|
||||
static void save_global_classes();
|
||||
|
||||
static void init_languages();
|
||||
static void finish_languages();
|
||||
};
|
||||
|
@ -285,7 +303,10 @@ public:
|
|||
|
||||
virtual void frame();
|
||||
|
||||
virtual ~ScriptLanguage(){};
|
||||
virtual bool handles_global_class_type(const String &p_type) const { return false; }
|
||||
virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const { return String(); }
|
||||
|
||||
virtual ~ScriptLanguage() {}
|
||||
};
|
||||
|
||||
extern uint8_t script_encryption_key[32];
|
||||
|
|
|
@ -243,6 +243,18 @@ void CreateDialog::_update_search() {
|
|||
_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
|
||||
*/
|
||||
|
||||
List<StringName> global_classes;
|
||||
ScriptServer::get_global_class_list(&global_classes);
|
||||
|
||||
Map<String, List<String> > global_class_map;
|
||||
for (List<StringName>::Element *E = global_classes.front(); E; E = E->next()) {
|
||||
String base = ScriptServer::get_global_class_base(E->get());
|
||||
if (!global_class_map.has(base)) {
|
||||
global_class_map[base] = List<String>();
|
||||
}
|
||||
global_class_map[base].push_back(E->get());
|
||||
}
|
||||
|
||||
HashMap<String, TreeItem *> types;
|
||||
|
||||
TreeItem *root = search_options->create_item();
|
||||
|
@ -293,6 +305,32 @@ void CreateDialog::_update_search() {
|
|||
add_type(I->get(), types, root, &to_select);
|
||||
}
|
||||
|
||||
if (global_class_map.has(type) && ClassDB::is_parent_class(type, base_type)) {
|
||||
for (List<String>::Element *J = global_class_map[type].front(); J; J = J->next()) {
|
||||
bool show = search_box->get_text().is_subsequence_ofi(J->get());
|
||||
|
||||
if (!show)
|
||||
continue;
|
||||
|
||||
if (!types.has(type))
|
||||
add_type(type, types, root, &to_select);
|
||||
|
||||
TreeItem *ti;
|
||||
if (types.has(type))
|
||||
ti = types[type];
|
||||
else
|
||||
ti = search_options->get_root();
|
||||
|
||||
TreeItem *item = search_options->create_item(ti);
|
||||
item->set_metadata(0, J->get());
|
||||
item->set_text(0, J->get() + " (" + ScriptServer::get_global_class_path(J->get()).get_file() + ")");
|
||||
item->set_icon(0, _get_editor_icon(type));
|
||||
if (!to_select || J->get() == search_box->get_text()) {
|
||||
to_select = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) {
|
||||
//there are custom types based on this... cool.
|
||||
|
||||
|
@ -444,6 +482,17 @@ Object *CreateDialog::instance_selected() {
|
|||
custom = md;
|
||||
|
||||
if (custom != String()) {
|
||||
|
||||
if (ScriptServer::is_global_class(custom)) {
|
||||
RES script = ResourceLoader::load(ScriptServer::get_global_class_path(custom));
|
||||
ERR_FAIL_COND_V(!script.is_valid(), NULL);
|
||||
|
||||
Object *obj = ClassDB::instance(ScriptServer::get_global_class_base(custom));
|
||||
ERR_FAIL_COND_V(!obj, NULL);
|
||||
|
||||
obj->set_script(script.get_ref_ptr());
|
||||
return obj;
|
||||
}
|
||||
return EditorNode::get_editor_data().instance_custom_type(selected->get_text(0), custom);
|
||||
} else {
|
||||
return ClassDB::instance(selected->get_text(0));
|
||||
|
|
|
@ -125,6 +125,14 @@ bool EditorFileSystemDirectory::get_file_import_is_valid(int p_idx) const {
|
|||
return files[p_idx]->import_valid;
|
||||
}
|
||||
|
||||
String EditorFileSystemDirectory::get_file_script_class_name(int p_idx) const {
|
||||
return files[p_idx]->script_class_name;
|
||||
}
|
||||
|
||||
String EditorFileSystemDirectory::get_file_script_class_extends(int p_idx) const {
|
||||
return files[p_idx]->script_class_extends;
|
||||
}
|
||||
|
||||
StringName EditorFileSystemDirectory::get_file_type(int p_idx) const {
|
||||
|
||||
ERR_FAIL_INDEX_V(p_idx, files.size(), "");
|
||||
|
@ -149,6 +157,8 @@ void EditorFileSystemDirectory::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_file", "idx"), &EditorFileSystemDirectory::get_file);
|
||||
ClassDB::bind_method(D_METHOD("get_file_path", "idx"), &EditorFileSystemDirectory::get_file_path);
|
||||
ClassDB::bind_method(D_METHOD("get_file_type", "idx"), &EditorFileSystemDirectory::get_file_type);
|
||||
ClassDB::bind_method(D_METHOD("get_file_script_class_name", "idx"), &EditorFileSystemDirectory::get_file_script_class_name);
|
||||
ClassDB::bind_method(D_METHOD("get_file_script_class_extends", "idx"), &EditorFileSystemDirectory::get_file_script_class_extends);
|
||||
ClassDB::bind_method(D_METHOD("get_file_import_is_valid", "idx"), &EditorFileSystemDirectory::get_file_import_is_valid);
|
||||
ClassDB::bind_method(D_METHOD("get_name"), &EditorFileSystemDirectory::get_name);
|
||||
ClassDB::bind_method(D_METHOD("get_path"), &EditorFileSystemDirectory::get_path);
|
||||
|
@ -189,7 +199,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
|
||||
String project = ProjectSettings::get_singleton()->get_resource_path();
|
||||
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3");
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache4");
|
||||
FileAccess *f = FileAccess::open(fscache, FileAccess::READ);
|
||||
|
||||
if (f) {
|
||||
|
@ -209,7 +219,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
|
||||
} else {
|
||||
Vector<String> split = l.split("::");
|
||||
ERR_CONTINUE(split.size() != 6);
|
||||
ERR_CONTINUE(split.size() != 7);
|
||||
String name = split[0];
|
||||
String file;
|
||||
|
||||
|
@ -221,8 +231,10 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
fc.modification_time = split[2].to_int64();
|
||||
fc.import_modification_time = split[3].to_int64();
|
||||
fc.import_valid = split[4].to_int64() != 0;
|
||||
fc.script_class_name = split[5].get_slice("<>", 0);
|
||||
fc.script_class_extends = split[5].get_slice("<>", 1);
|
||||
|
||||
String deps = split[5].strip_edges();
|
||||
String deps = split[6].strip_edges();
|
||||
if (deps.length()) {
|
||||
Vector<String> dp = deps.split("<>");
|
||||
for (int i = 0; i < dp.size(); i++) {
|
||||
|
@ -239,7 +251,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
memdelete(f);
|
||||
}
|
||||
|
||||
String update_cache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3");
|
||||
String update_cache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
|
||||
|
||||
if (FileAccess::exists(update_cache)) {
|
||||
{
|
||||
|
@ -287,7 +299,7 @@ void EditorFileSystem::_scan_filesystem() {
|
|||
}
|
||||
|
||||
void EditorFileSystem::_save_filesystem_cache() {
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache3");
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_cache4");
|
||||
|
||||
FileAccess *f = FileAccess::open(fscache, FileAccess::WRITE);
|
||||
if (f == NULL) {
|
||||
|
@ -563,6 +575,7 @@ void EditorFileSystem::scan() {
|
|||
scanning = false;
|
||||
emit_signal("filesystem_changed");
|
||||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
_queue_update_script_classes();
|
||||
|
||||
} else {
|
||||
|
||||
|
@ -706,6 +719,9 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
fi->modified_time = fc->modification_time;
|
||||
fi->import_modified_time = fc->import_modification_time;
|
||||
fi->import_valid = fc->import_valid;
|
||||
fi->script_class_name = fc->script_class_name;
|
||||
fi->script_class_extends = fc->script_class_extends;
|
||||
|
||||
if (fc->type == String()) {
|
||||
fi->type = ResourceLoader::get_resource_type(path);
|
||||
//there is also the chance that file type changed due to reimport, must probably check this somehow here (or kind of note it for next time in another file?)
|
||||
|
@ -715,6 +731,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
} else {
|
||||
|
||||
fi->type = ResourceFormatImporter::get_singleton()->get_resource_type(path);
|
||||
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
|
||||
fi->modified_time = 0;
|
||||
fi->import_modified_time = 0;
|
||||
fi->import_valid = ResourceLoader::is_import_valid(path);
|
||||
|
@ -734,9 +751,12 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, DirAccess
|
|||
fi->deps = fc->deps;
|
||||
fi->import_modified_time = 0;
|
||||
fi->import_valid = true;
|
||||
fi->script_class_name = fc->script_class_name;
|
||||
fi->script_class_extends = fc->script_class_extends;
|
||||
} else {
|
||||
//new or modified time
|
||||
fi->type = ResourceLoader::get_resource_type(path);
|
||||
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
|
||||
fi->deps = _get_dependencies(path);
|
||||
fi->modified_time = mt;
|
||||
fi->import_modified_time = 0;
|
||||
|
@ -835,6 +855,7 @@ void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir, const
|
|||
fi->modified_time = FileAccess::get_modified_time(path);
|
||||
fi->import_modified_time = 0;
|
||||
fi->type = ResourceLoader::get_resource_type(path);
|
||||
fi->script_class_name = _get_global_script_class(fi->type, path, &fi->script_class_extends);
|
||||
fi->import_valid = ResourceLoader::is_import_valid(path);
|
||||
|
||||
{
|
||||
|
@ -1044,6 +1065,7 @@ void EditorFileSystem::_notification(int p_what) {
|
|||
if (_update_scan_actions())
|
||||
emit_signal("filesystem_changed");
|
||||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
_queue_update_script_classes();
|
||||
}
|
||||
} else if (!scanning) {
|
||||
|
||||
|
@ -1059,6 +1081,7 @@ void EditorFileSystem::_notification(int p_what) {
|
|||
_update_scan_actions();
|
||||
emit_signal("filesystem_changed");
|
||||
emit_signal("sources_changed", sources_changed.size() > 0);
|
||||
_queue_update_script_classes();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -1087,7 +1110,7 @@ void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory *p_dir,
|
|||
|
||||
for (int i = 0; i < p_dir->files.size(); i++) {
|
||||
|
||||
String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid);
|
||||
String s = p_dir->files[i]->file + "::" + p_dir->files[i]->type + "::" + itos(p_dir->files[i]->modified_time) + "::" + itos(p_dir->files[i]->import_modified_time) + "::" + itos(p_dir->files[i]->import_valid) + "::" + p_dir->files[i]->script_class_name + "<>" + p_dir->files[i]->script_class_extends;
|
||||
s += "::";
|
||||
for (int j = 0; j < p_dir->files[i]->deps.size(); j++) {
|
||||
|
||||
|
@ -1268,7 +1291,7 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem_path(const String &p
|
|||
|
||||
void EditorFileSystem::_save_late_updated_files() {
|
||||
//files that already existed, and were modified, need re-scanning for dependencies upon project restart. This is done via saving this special file
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update3");
|
||||
String fscache = EditorSettings::get_singleton()->get_project_settings_dir().plus_file("filesystem_update4");
|
||||
FileAccessRef f = FileAccess::open(fscache, FileAccess::WRITE);
|
||||
for (Set<String>::Element *E = late_update_files.front(); E; E = E->next()) {
|
||||
f->store_line(E->get());
|
||||
|
@ -1293,6 +1316,67 @@ Vector<String> EditorFileSystem::_get_dependencies(const String &p_path) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
String EditorFileSystem::_get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const {
|
||||
|
||||
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
|
||||
if (ScriptServer::get_language(i)->handles_global_class_type(p_type)) {
|
||||
String global_name;
|
||||
String extends;
|
||||
|
||||
global_name = ScriptServer::get_language(i)->get_global_class_name(p_path, &extends);
|
||||
*r_extends = extends;
|
||||
return global_name;
|
||||
}
|
||||
}
|
||||
*r_extends = String();
|
||||
return String();
|
||||
}
|
||||
|
||||
void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
|
||||
int filecount = p_dir->files.size();
|
||||
const EditorFileSystemDirectory::FileInfo *const *files = p_dir->files.ptr();
|
||||
for (int i = 0; i < filecount; i++) {
|
||||
if (files[i]->script_class_name == String()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String lang;
|
||||
for (int j = 0; j < ScriptServer::get_language_count(); j++) {
|
||||
if (ScriptServer::get_language(j)->handles_global_class_type(files[i]->type)) {
|
||||
lang = ScriptServer::get_language(j)->get_name();
|
||||
}
|
||||
}
|
||||
|
||||
ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i));
|
||||
}
|
||||
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
|
||||
_scan_script_classes(p_dir->get_subdir(i));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileSystem::update_script_classes() {
|
||||
|
||||
if (!update_script_classes_queued)
|
||||
return;
|
||||
|
||||
update_script_classes_queued = false;
|
||||
ScriptServer::global_classes_clear();
|
||||
if (get_filesystem()) {
|
||||
_scan_script_classes(get_filesystem());
|
||||
}
|
||||
|
||||
ScriptServer::save_global_classes();
|
||||
}
|
||||
|
||||
void EditorFileSystem::_queue_update_script_classes() {
|
||||
if (update_script_classes_queued) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_script_classes_queued = true;
|
||||
call_deferred("update_script_classes");
|
||||
}
|
||||
|
||||
void EditorFileSystem::update_file(const String &p_file) {
|
||||
|
||||
EditorFileSystemDirectory *fs = NULL;
|
||||
|
@ -1311,7 +1395,9 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
memdelete(fs->files[cpos]);
|
||||
fs->files.remove(cpos);
|
||||
}
|
||||
|
||||
call_deferred("emit_signal", "filesystem_changed"); //update later
|
||||
_queue_update_script_classes();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1351,6 +1437,7 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
}
|
||||
|
||||
fs->files[cpos]->type = type;
|
||||
fs->files[cpos]->script_class_name = _get_global_script_class(type, p_file, &fs->files[cpos]->script_class_extends);
|
||||
fs->files[cpos]->modified_time = FileAccess::get_modified_time(p_file);
|
||||
fs->files[cpos]->deps = _get_dependencies(p_file);
|
||||
fs->files[cpos]->import_valid = ResourceLoader::is_import_valid(p_file);
|
||||
|
@ -1359,6 +1446,7 @@ void EditorFileSystem::update_file(const String &p_file) {
|
|||
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
|
||||
|
||||
call_deferred("emit_signal", "filesystem_changed"); //update later
|
||||
_queue_update_script_classes();
|
||||
}
|
||||
|
||||
void EditorFileSystem::_reimport_file(const String &p_file) {
|
||||
|
@ -1611,6 +1699,7 @@ void EditorFileSystem::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("update_file", "path"), &EditorFileSystem::update_file);
|
||||
ClassDB::bind_method(D_METHOD("get_filesystem_path", "path"), &EditorFileSystem::get_filesystem_path);
|
||||
ClassDB::bind_method(D_METHOD("get_file_type", "path"), &EditorFileSystem::get_file_type);
|
||||
ClassDB::bind_method(D_METHOD("update_script_classes"), &EditorFileSystem::update_script_classes);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("filesystem_changed"));
|
||||
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
|
||||
|
@ -1664,6 +1753,7 @@ EditorFileSystem::EditorFileSystem() {
|
|||
memdelete(da);
|
||||
|
||||
scan_total = 0;
|
||||
update_script_classes_queued = false;
|
||||
}
|
||||
|
||||
EditorFileSystem::~EditorFileSystem() {
|
||||
|
|
|
@ -58,6 +58,8 @@ class EditorFileSystemDirectory : public Object {
|
|||
bool import_valid;
|
||||
Vector<String> deps;
|
||||
bool verified; //used for checking changes
|
||||
String script_class_name;
|
||||
String script_class_extends;
|
||||
};
|
||||
|
||||
struct FileInfoSort {
|
||||
|
@ -86,6 +88,8 @@ public:
|
|||
StringName get_file_type(int p_idx) const;
|
||||
Vector<String> get_file_deps(int p_idx) const;
|
||||
bool get_file_import_is_valid(int p_idx) const;
|
||||
String get_file_script_class_name(int p_idx) const; //used for scripts
|
||||
String get_file_script_class_extends(int p_idx) const; //used for scripts
|
||||
|
||||
EditorFileSystemDirectory *get_parent();
|
||||
|
||||
|
@ -157,6 +161,8 @@ class EditorFileSystem : public Node {
|
|||
uint64_t import_modification_time;
|
||||
Vector<String> deps;
|
||||
bool import_valid;
|
||||
String script_class_name;
|
||||
String script_class_extends;
|
||||
};
|
||||
|
||||
HashMap<String, FileCache> file_cache;
|
||||
|
@ -215,6 +221,12 @@ class EditorFileSystem : public Node {
|
|||
}
|
||||
};
|
||||
|
||||
void _scan_script_classes(EditorFileSystemDirectory *p_dir);
|
||||
volatile bool update_script_classes_queued;
|
||||
void _queue_update_script_classes();
|
||||
|
||||
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends) const;
|
||||
|
||||
protected:
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
|
@ -237,6 +249,8 @@ public:
|
|||
|
||||
void reimport_files(const Vector<String> &p_files);
|
||||
|
||||
void update_script_classes();
|
||||
|
||||
EditorFileSystem();
|
||||
~EditorFileSystem();
|
||||
};
|
||||
|
|
|
@ -1872,6 +1872,7 @@ void ScriptEditor::save_all_scripts() {
|
|||
}
|
||||
|
||||
_update_script_names();
|
||||
EditorFileSystem::get_singleton()->update_script_classes();
|
||||
}
|
||||
|
||||
void ScriptEditor::apply_scripts() const {
|
||||
|
|
|
@ -1739,6 +1739,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
|
|||
"assert",
|
||||
"breakpoint",
|
||||
"class",
|
||||
"class_name",
|
||||
"extends",
|
||||
"is",
|
||||
"func",
|
||||
|
@ -1788,6 +1789,50 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
|
|||
}
|
||||
}
|
||||
|
||||
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
|
||||
|
||||
return p_type == "GDScript";
|
||||
}
|
||||
|
||||
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type) const {
|
||||
|
||||
PoolVector<uint8_t> sourcef;
|
||||
Error err;
|
||||
FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
|
||||
if (err) {
|
||||
return String();
|
||||
}
|
||||
|
||||
int len = f->get_len();
|
||||
sourcef.resize(len + 1);
|
||||
PoolVector<uint8_t>::Write w = sourcef.write();
|
||||
int r = f->get_buffer(w.ptr(), len);
|
||||
f->close();
|
||||
memdelete(f);
|
||||
ERR_FAIL_COND_V(r != len, String());
|
||||
w[len] = 0;
|
||||
|
||||
String s;
|
||||
if (s.parse_utf8((const char *)w.ptr())) {
|
||||
return String();
|
||||
}
|
||||
|
||||
GDScriptParser parser;
|
||||
|
||||
parser.parse(s, p_path.get_base_dir(), true, p_path);
|
||||
|
||||
if (parser.get_parse_tree() && parser.get_parse_tree()->type == GDScriptParser::Node::TYPE_CLASS) {
|
||||
|
||||
const GDScriptParser::ClassNode *c = static_cast<const GDScriptParser::ClassNode *>(parser.get_parse_tree());
|
||||
if (r_base_type && c->extends_used && c->extends_class.size() == 1) {
|
||||
*r_base_type = c->extends_class[0]; //todo, should work much better
|
||||
}
|
||||
return c->name;
|
||||
}
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
GDScriptLanguage::GDScriptLanguage() {
|
||||
|
||||
calls = 0;
|
||||
|
|
|
@ -439,6 +439,11 @@ public:
|
|||
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
|
||||
/* GLOBAL CLASSES */
|
||||
|
||||
virtual bool handles_global_class_type(const String &p_type) const;
|
||||
virtual String get_global_class_name(const String &p_path, String *r_base_type = NULL) const;
|
||||
|
||||
GDScriptLanguage();
|
||||
~GDScriptLanguage();
|
||||
};
|
||||
|
|
|
@ -278,6 +278,41 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|||
return idx | (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS); //argument (stack root)
|
||||
}
|
||||
|
||||
/* TRY GLOBAL CLASSES */
|
||||
|
||||
if (ScriptServer::is_global_class(identifier)) {
|
||||
|
||||
const GDScriptParser::ClassNode *class_node = codegen.class_node;
|
||||
while (class_node->owner) {
|
||||
class_node = class_node->owner;
|
||||
}
|
||||
|
||||
if (class_node->name == identifier) {
|
||||
_set_error("Using own name in class file is not allowed (creates a cyclic reference)", p_expression);
|
||||
return -1;
|
||||
}
|
||||
|
||||
RES res = ResourceLoader::load(ScriptServer::get_global_class_path(identifier));
|
||||
if (res.is_null()) {
|
||||
_set_error("Can't load global class " + String(identifier) + ", cyclic reference?", p_expression);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Variant key = res;
|
||||
int idx;
|
||||
|
||||
if (!codegen.constant_map.has(key)) {
|
||||
|
||||
idx = codegen.constant_map.size();
|
||||
codegen.constant_map[key] = idx;
|
||||
|
||||
} else {
|
||||
idx = codegen.constant_map[key];
|
||||
}
|
||||
|
||||
return idx | (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS); //make it a local constant (faster access)
|
||||
}
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(identifier)) {
|
||||
|
||||
|
|
|
@ -3111,6 +3111,28 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
return;
|
||||
}
|
||||
|
||||
} break;
|
||||
case GDScriptTokenizer::TK_PR_CLASS_NAME: {
|
||||
|
||||
if (p_class->owner) {
|
||||
_set_error("'class_name' is only valid for the main class namespace.");
|
||||
return;
|
||||
}
|
||||
if (tokenizer->get_token(1) != GDScriptTokenizer::TK_IDENTIFIER) {
|
||||
|
||||
_set_error("'class_name' syntax: 'class_name <UniqueName>'");
|
||||
return;
|
||||
}
|
||||
|
||||
p_class->name = tokenizer->get_token_identifier(1);
|
||||
|
||||
if (self_path != String() && ScriptServer::is_global_class(p_class->name) && ScriptServer::get_global_class_path(p_class->name) != self_path) {
|
||||
_set_error("Unique global class '" + p_class->name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name));
|
||||
return;
|
||||
}
|
||||
|
||||
tokenizer->advance(2);
|
||||
|
||||
} break;
|
||||
case GDScriptTokenizer::TK_PR_TOOL: {
|
||||
|
||||
|
@ -3138,6 +3160,11 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
name = tokenizer->get_token_identifier(1);
|
||||
tokenizer->advance(2);
|
||||
|
||||
if (ScriptServer::is_global_class(name)) {
|
||||
_set_error("Can't override name of unique global class '" + name + "' already exists at path: " + ScriptServer::get_global_class_path(p_class->name));
|
||||
return;
|
||||
}
|
||||
|
||||
ClassNode *newclass = alloc_node<ClassNode>();
|
||||
newclass->initializer = alloc_node<BlockNode>();
|
||||
newclass->initializer->parent_class = newclass;
|
||||
|
|
|
@ -91,6 +91,7 @@ const char *GDScriptTokenizer::token_names[TK_MAX] = {
|
|||
"match",
|
||||
"func",
|
||||
"class",
|
||||
"class_name",
|
||||
"extends",
|
||||
"is",
|
||||
"onready",
|
||||
|
@ -187,6 +188,7 @@ static const _kws _keyword_list[] = {
|
|||
//func
|
||||
{ GDScriptTokenizer::TK_PR_FUNCTION, "func" },
|
||||
{ GDScriptTokenizer::TK_PR_CLASS, "class" },
|
||||
{ GDScriptTokenizer::TK_PR_CLASS_NAME, "class_name" },
|
||||
{ GDScriptTokenizer::TK_PR_EXTENDS, "extends" },
|
||||
{ GDScriptTokenizer::TK_PR_IS, "is" },
|
||||
{ GDScriptTokenizer::TK_PR_ONREADY, "onready" },
|
||||
|
@ -1137,7 +1139,7 @@ void GDScriptTokenizerText::advance(int p_amount) {
|
|||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define BYTECODE_VERSION 12
|
||||
#define BYTECODE_VERSION 13
|
||||
|
||||
Error GDScriptTokenizerBuffer::set_code_buffer(const Vector<uint8_t> &p_buffer) {
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ public:
|
|||
TK_CF_MATCH,
|
||||
TK_PR_FUNCTION,
|
||||
TK_PR_CLASS,
|
||||
TK_PR_CLASS_NAME,
|
||||
TK_PR_EXTENDS,
|
||||
TK_PR_IS,
|
||||
TK_PR_ONREADY,
|
||||
|
|
Loading…
Reference in New Issue