Skip to content

Commit

Permalink
Add ScriptServer and export all custom resources.
Browse files Browse the repository at this point in the history
  • Loading branch information
willnationsdev authored and Atlinx committed Jul 8, 2023
1 parent 36c7bed commit 02d1f70
Show file tree
Hide file tree
Showing 44 changed files with 1,264 additions and 165 deletions.
84 changes: 84 additions & 0 deletions core/bind/core_bind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/project_settings.h"
#include "core/script_language.h"

/**
* Time constants borrowed from loc_time.h
Expand Down Expand Up @@ -3151,6 +3152,89 @@ _ClassDB::~_ClassDB() {
}
///////////////////////////////

bool _ScriptServer::_set(const StringName &p_name, const Variant &p_value) {
return false;
}

bool _ScriptServer::_get(const StringName &p_name, Variant &r_ret) const {
if (ScriptServer::is_global_class(p_name)) {
r_ret = ResourceLoader::load(ScriptServer::get_global_class_path(p_name), "Script");
return true;
}
return false;
}

void _ScriptServer::_get_property_list(List<PropertyInfo> *p_list) const {
ERR_FAIL_COND(!p_list);
List<StringName> names;
ScriptServer::get_global_class_list(&names);
for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
StringName n = E->get();
String class_name = String(n).get_file().get_extension();
p_list->push_back(PropertyInfo(Variant::OBJECT, class_name, PROPERTY_HINT_RESOURCE_TYPE, "Script", PROPERTY_USAGE_NETWORK, ResourceLoader::get_resource_type(ScriptServer::get_global_class_path(n))));
}
}

bool _ScriptServer::is_global_class(const StringName &p_class) const {
return ScriptServer::is_global_class(p_class);
}

String _ScriptServer::get_global_class_path(const String &p_class) const {
return ScriptServer::get_global_class_path(p_class);
}

StringName _ScriptServer::get_global_class_base(const String &p_class) const {
return ScriptServer::get_global_class_base(p_class);
}

StringName _ScriptServer::get_global_class_native_base(const String &p_class) const {
return ScriptServer::get_global_class_native_base(p_class);
}

StringName _ScriptServer::get_global_class_name(const String &p_path) const {
return ScriptServer::get_global_class_name(p_path);
}

Ref<Script> _ScriptServer::get_global_class_script(const StringName &p_class) const {
return ScriptServer::get_global_class_script(p_class);
}

Variant _ScriptServer::instantiate_global_class(const StringName &p_class) const {
return ScriptServer::instantiate_global_class(p_class);
}

Array _ScriptServer::get_global_class_list() const {
Array ret;
List<StringName> lst;
ScriptServer::get_global_class_list(&lst);
for (List<StringName>::Element *E = lst.front(); E; E = E->next()) {
ret.push_back(E->get());
}
return ret;
}

void _ScriptServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_global_class", "class"), &_ScriptServer::is_global_class);
ClassDB::bind_method(D_METHOD("get_global_class_path", "class"), &_ScriptServer::get_global_class_path);
ClassDB::bind_method(D_METHOD("get_global_class_base", "class"), &_ScriptServer::get_global_class_base);
ClassDB::bind_method(D_METHOD("get_global_class_native_base", "class"), &_ScriptServer::get_global_class_native_base);
ClassDB::bind_method(D_METHOD("get_global_class_name", "path"), &_ScriptServer::get_global_class_name);
ClassDB::bind_method(D_METHOD("get_global_class_script", "class"), &_ScriptServer::get_global_class_script);
ClassDB::bind_method(D_METHOD("instantiate_global_class", "class"), &_ScriptServer::instantiate_global_class);
ClassDB::bind_method(D_METHOD("get_global_class_list"), &_ScriptServer::get_global_class_list);
}

_ScriptServer::_ScriptServer() {
singleton = this;
}

_ScriptServer::~_ScriptServer() {
}

_ScriptServer *_ScriptServer::singleton = nullptr;

///////////////////////////////

void _Engine::set_iterations_per_second(int p_ips) {
Engine::get_singleton()->set_iterations_per_second(p_ips);
}
Expand Down
27 changes: 27 additions & 0 deletions core/bind/core_bind.h
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,33 @@ class _ClassDB : public Object {
~_ClassDB();
};

class _ScriptServer : public Object {
GDCLASS(_ScriptServer, Object);

protected:
static void _bind_methods();
static _ScriptServer *singleton;

bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;

public:
static _ScriptServer *get_singleton() { return singleton; }

bool is_global_class(const StringName &p_class) const;
String get_global_class_path(const String &p_class) const;
StringName get_global_class_base(const String &p_class) const;
StringName get_global_class_native_base(const String &p_class) const;
StringName get_global_class_name(const String &p_path) const;
Ref<Script> get_global_class_script(const StringName &p_class) const;
Variant instantiate_global_class(const StringName &p_class) const;
Array get_global_class_list() const;

_ScriptServer();
~_ScriptServer();
};

class _Engine : public Object {
GDCLASS(_Engine, Object);

Expand Down
8 changes: 7 additions & 1 deletion core/io/resource_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,14 @@ void ResourceFormatLoader::get_recognized_extensions_for_type(const String &p_ty
}

void ResourceLoader::get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) {
StringName native = ScriptServer::is_global_class(p_type) ? ScriptServer::get_global_class_native_base(p_type) : StringName(p_type);
for (int i = 0; i < loader_count; i++) {
loader[i]->get_recognized_extensions_for_type(p_type, p_extensions);
Ref<ResourceFormatLoader> current = loader[i];
if (!current->get_script().is_null()) {
current->get_recognized_extensions_for_type(p_type, p_extensions);
} else {
current->get_recognized_extensions_for_type(native, p_extensions);
}
}
}

Expand Down
6 changes: 6 additions & 0 deletions core/register_core_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#include "core/packed_data_container.h"
#include "core/path_remap.h"
#include "core/project_settings.h"
#include "core/script_language.h"
#include "core/translation.h"
#include "core/undo_redo.h"

Expand All @@ -88,6 +89,7 @@ static _Engine *_engine = nullptr;
static _ClassDB *_classdb = nullptr;
static _Marshalls *_marshalls = nullptr;
static _JSON *_json = nullptr;
static _ScriptServer *_script_server = nullptr;

static IP *ip = nullptr;

Expand Down Expand Up @@ -228,6 +230,7 @@ void register_core_types() {
_json = memnew(_JSON);

OS::get_singleton()->benchmark_end_measure("register_core_types");
_script_server = memnew(_ScriptServer);
}

void register_core_settings() {
Expand Down Expand Up @@ -257,6 +260,7 @@ void register_core_singletons() {
ClassDB::register_class<_JSON>();
ClassDB::register_class<Expression>();
ClassDB::register_class<Time>();
ClassDB::register_class<_ScriptServer>();

Engine::get_singleton()->add_singleton(Engine::Singleton("ProjectSettings", ProjectSettings::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("IP", IP::get_singleton()));
Expand All @@ -272,6 +276,7 @@ void register_core_singletons() {
Engine::get_singleton()->add_singleton(Engine::Singleton("InputMap", InputMap::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("JSON", _JSON::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("Time", Time::get_singleton()));
Engine::get_singleton()->add_singleton(Engine::Singleton("ScriptServer", _ScriptServer::get_singleton()));
}

void unregister_core_types() {
Expand All @@ -284,6 +289,7 @@ void unregister_core_types() {
memdelete(_classdb);
memdelete(_marshalls);
memdelete(_json);
memdelete(_script_server);

memdelete(_geometry);

Expand Down
67 changes: 62 additions & 5 deletions core/script_language.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include "script_language.h"

#include "core/core_string_names.h"
#include "core/io/resource_loader.h"
#include "core/project_settings.h"

ScriptLanguage *ScriptServer::_languages[MAX_LANGUAGES];
Expand Down Expand Up @@ -200,20 +201,28 @@ void ScriptServer::thread_exit() {
}

HashMap<StringName, ScriptServer::GlobalScriptClass> ScriptServer::global_classes;
HashMap<String, StringName> ScriptServer::global_class_paths;

void ScriptServer::global_classes_clear() {
global_classes.clear();
global_class_paths.clear();
}

void ScriptServer::add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path) {
ERR_FAIL_COND_MSG(p_class == p_base || (global_classes.has(p_base) && get_global_class_native_base(p_base) == p_class), "Cyclic inheritance in script class.");
ERR_FAIL_COND_MSG(p_class == StringName(), vformat("Attempted to register global script class at path '%s' without a class name.", p_path));
ERR_FAIL_COND_MSG(p_base == StringName(), vformat("Attempted to register global script class at path '%s' without a base name.", p_path));
ERR_FAIL_COND_MSG(p_language == StringName(), vformat("Attempted to register global script class at path '%s' without a language name.", p_path));
ERR_FAIL_COND_MSG(p_path.empty(), vformat("Attempted to register global script class named '%s' with an empty path.", p_class));
GlobalScriptClass g;
g.language = p_language;
g.path = p_path;
g.base = p_base;
global_classes[p_class] = g;
global_class_paths[p_path] = p_class;
}
void ScriptServer::remove_global_class(const StringName &p_class) {
global_class_paths.erase(global_classes[p_class].path);
global_classes.erase(p_class);
}
bool ScriptServer::is_global_class(const StringName &p_class) {
Expand All @@ -223,23 +232,71 @@ 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) {
String ScriptServer::get_global_class_path(const StringName &p_class) {
ERR_FAIL_COND_V(!global_classes.has(p_class), String());
return global_classes[p_class].path;
}
StringName ScriptServer::get_global_class_name(const String &p_path) {
if (global_class_paths.has(p_path)) {
return global_class_paths[p_path];
}
return StringName();
}

StringName ScriptServer::get_global_class_base(const String &p_class) {
ERR_FAIL_COND_V(!global_classes.has(p_class), String());
StringName ScriptServer::get_global_class_base(const StringName &p_class) {
ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
return global_classes[p_class].base;
}
StringName ScriptServer::get_global_class_native_base(const String &p_class) {
ERR_FAIL_COND_V(!global_classes.has(p_class), String());

StringName ScriptServer::get_global_class_native_base(const StringName &p_class) {
ERR_FAIL_COND_V(!global_classes.has(p_class), StringName());
String base = global_classes[p_class].base;
while (global_classes.has(base)) {
base = global_classes[base].base;
}
return base;
}

Ref<Script> ScriptServer::get_global_class_script(const StringName &p_class) {
ERR_FAIL_COND_V_MSG(!ScriptServer::is_global_class(p_class), Ref<Script>(), vformat("Class to load '%s' is not a script class.", p_class));
if (!ScriptServer::is_global_class(p_class)) {
return Ref<Script>();
}

String path = ScriptServer::get_global_class_path(p_class);
return ResourceLoader::load(path, "Script");
}

Variant ScriptServer::instantiate_global_class(const StringName &p_class) {
ERR_FAIL_COND_V_MSG(!global_classes.has(p_class), Variant(), vformat("Class to instantiate '%s' is not a script class.", p_class));
String native = get_global_class_native_base(p_class);
Object *o = ClassDB::instance(native);
ERR_FAIL_COND_V_MSG(!o, Variant(), vformat("Could not instantiate global script class '%s'. It extends native class '%s' which is not instantiable.", p_class, native));

REF ref;
Reference *r = Object::cast_to<Reference>(o);
if (r) {
ref = REF(r);
}

Variant ret;
if (ref.is_valid()) {
ret = ref;
} else {
ret = o;
}

Ref<Script> s = get_global_class_script(p_class);
ERR_FAIL_COND_V_MSG(s.is_null(), Variant(), vformat("Failed to load global script class '%s'.", p_class));

o->set_script(s.get_ref_ptr());

ScriptInstance *si = o->get_script_instance();
ERR_FAIL_COND_V_MSG(!si, Variant(), vformat("Failed to create script instance for global script class '%s'.", p_class));

return ret;
}

void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
const StringName *K = nullptr;
List<StringName> classes;
Expand Down
12 changes: 9 additions & 3 deletions core/script_language.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "core/resource.h"

class ScriptLanguage;
class Script;

typedef void (*ScriptEditRequestFunction)(const String &p_path);

Expand All @@ -59,6 +60,7 @@ class ScriptServer {
};

static HashMap<StringName, GlobalScriptClass> global_classes;
static HashMap<String, StringName> global_class_paths;

public:
static ScriptEditRequestFunction edit_request_func;
Expand All @@ -81,9 +83,12 @@ class ScriptServer {
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 StringName get_global_class_native_base(const String &p_class);
static String get_global_class_path(const StringName &p_class);
static StringName get_global_class_name(const String &p_path);
static StringName get_global_class_base(const StringName &p_class);
static StringName get_global_class_native_base(const StringName &p_class);
static Ref<Script> get_global_class_script(const StringName &p_class);
static Variant instantiate_global_class(const StringName &p_class);
static void get_global_class_list(List<StringName> *r_global_classes);
static void save_global_classes();

Expand Down Expand Up @@ -283,6 +288,7 @@ class ScriptLanguage {
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const = 0;
virtual Error open_in_external_editor(const Ref<Script> &p_script, int p_line, int p_col) { return ERR_UNAVAILABLE; }
virtual bool overrides_external_editor() { return false; }
virtual bool has_delayed_script_class_metadata() const { return false; }

virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_force, String &r_call_hint) { return ERR_UNAVAILABLE; }

Expand Down
3 changes: 3 additions & 0 deletions doc/classes/@GlobalScope.xml
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<member name="Time" type="Time" setter="" getter="">
The [Time] singleton.
</member>
<member name="ScriptServer" type="ScriptServer" setter="" getter="">
The [ScriptServer] singleton.
</member>
<member name="TranslationServer" type="TranslationServer" setter="" getter="">
The [TranslationServer] singleton.
</member>
Expand Down
18 changes: 18 additions & 0 deletions doc/classes/EditorInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,15 @@
[b]Warning:[/b] Removing and freeing this node will render the editor useless and may cause a crash.
</description>
</method>
<method name="get_class_icon">
<return type="Texture" />
<argument index="0" name="class" type="String" />
<argument index="1" name="fallback" type="String" />
<description>
Returns the editor icon bound to a class name or the [code]fallback[/code] class's icon if not found. The [code]fallback[/code] defaults to "Object". If still not found, returns [code]null[/code].
[b]Node:[/b] This includes icons from custom types (see [method EditorPlugin.add_custom_type]) and global script classes from [ScriptServer].
</description>
</method>
<method name="get_current_path" qualifiers="const">
<return type="String" />
<description>
Expand Down Expand Up @@ -88,6 +97,15 @@
[b]Warning:[/b] Removing and freeing this node will render a part of the editor useless and may cause a crash.
</description>
</method>
<method name="get_object_icon">
<return type="Texture" />
<argument index="0" name="object" type="Object" />
<argument index="1" name="fallback" type="String" />
<description>
Returns the editor icon bound to [Object] [code]object[/code] or the class [code]fallback[/code] if a type cannot be determined. If [code]object[/code] extends [Script], then return the editor icon bound to the scripted class, not the actual script. If still not found, return [code]null[/code].
[b]Note:[/b] if you need the editor icon for a script such as [GDScript], use [method get_class_icon].
</description>
</method>
<method name="get_open_scenes" qualifiers="const">
<return type="Array" />
<description>
Expand Down
Loading

0 comments on commit 02d1f70

Please sign in to comment.