diff --git a/development/cpp/custom_resource_format_loaders.rst b/development/cpp/custom_resource_format_loaders.rst index 1d70c1154..e17277f0f 100644 --- a/development/cpp/custom_resource_format_loaders.rst +++ b/development/cpp/custom_resource_format_loaders.rst @@ -57,55 +57,100 @@ read and handle data serialization. .. code-block:: cpp - #ifndef MY_JSON_LOADER_H - #define MY_JSON_LOADER_H + /* resource_loader_json.h */ - #include "core/io/resource_loader.h" + #ifndef RESOURCE_LOADER_JSON_H + #define RESOURCE_LOADER_JSON_H - class ResourceFormatLoaderMyJson : public ResourceFormatLoader { - public: - virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL); - virtual void get_recognized_extensions(List *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + #include "core/io/resource_loader.h" - ResourceFormatLoaderMyJson(); - virtual ~ResourceFormatLoaderMyJson() {} - }; - #endif // MY_JSON_LOADER_H + class ResourceFormatLoaderJson : public ResourceFormatLoader { + GDCLASS(ResourceFormatLoaderJson, ResourceFormatLoader) + public: + virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL); + virtual void get_recognized_extensions(List *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; + }; + #endif // RESOURCE_LOADER_JSON_H .. code-block:: cpp - #include "my_json_loader.h" - #include "my_json.h" + /* resource_loader_json.cpp */ - ResourceFormatLoaderMyJson::ResourceFormatLoaderMyJson() { - } - - RES ResourceFormatLoaderMyJson::load(const String &p_path, const String &p_original_path, Error *r_error) { - MyJson *my = memnew(MyJson); - if (r_error) - *r_error = OK; - Error err = my->set_file(p_path); - return Ref(my); - } - - void ResourceFormatLoaderMyJson::get_recognized_extensions(List *p_extensions) const { - p_extensions->push_back("mjson"); - } - - String ResourceFormatLoaderMyJson::get_resource_type(const String &p_path) const { - - if (p_path.get_extension().to_lower() == "mjson") - return "MyJson"; - return ""; - } - - bool ResourceFormatLoaderMyJson::handles_type(const String &p_type) const { - return (p_type == "MyJson"); - } + #include "resource_loader_json.h" + #include "resource_json.h" + RES ResourceFormatLoaderJson::load(const String &p_path, const String &p_original_path, Error *r_error) { + Ref json = memnew(JsonResource); + if (r_error) + *r_error = OK; + Error err = json->load_file(p_path); + return json; + } + + void ResourceFormatLoaderJson::get_recognized_extensions(List *p_extensions) const { + if (!p_extensions->find("json")) + p_extensions->push_back("json"); + } + + String ResourceFormatLoaderJson::get_resource_type(const String &p_path) const { + return "Resource"; + } + + bool ResourceFormatLoaderJson::handles_type(const String &p_type) const { + return (ClassDB::is_parent_class(p_type, "Resource")); + } + +Creating a ResourceFormatSaver +------------------------------ + +If you'd like to be able to edit and save a resource, you can implement a ResourceFormatSaver: + + +.. code:: cpp + + /* resource_saver_json.h */ + + #ifndef RESOURCE_SAVER_JSON_H + #define RESOURCE_SAVER_JSON_H + + #include "core/io/resource_saver.h" + + class ResourceFormatSaverJson : public ResourceFormatSaver { + GDCLASS(ResourceFormatSaverJson, ResourceFormatSaver) + public: + virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0); + virtual bool recognize(const RES &p_resource) const; + virtual void get_recognized_extensions(const RES &p_resource, List *p_extensions) const; + }; + #endif // RESOURCE_SAVER_JSON_H + +.. code:: cpp + + /* resource_saver_json.cpp */ + + #include "resource_saver_json.h" + #include "resource_json.h" + #include "scene\resources\resource_format_text.h" + + + Error ResourceFormatSaverJson::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { + Ref json = memnew(JsonResource); + Error error = json->save_file(p_path, p_resource); + return error; + } + + bool ResourceFormatSaverJson::recognize(const RES &p_resource) const { + return Object::cast_to(*p_resource) != NULL; + } + + void ResourceFormatSaverJson::get_recognized_extensions(const RES &p_resource, List *p_extensions) const { + if (Object::cast_to(*p_resource)) + p_extensions->push_back("json"); + } + Creating custom data types -------------------------- @@ -117,58 +162,95 @@ Here is an example of how to create a custom datatype .. code-block:: cpp - #ifndef MY_JSON_H - #define MY_JSON_H + /* resource_json.h */ - #include "core/dictionary.h" - #include "core/io/json.h" - #include "core/reference.h" - #include "core/variant.h" - #include "core/variant_parser.h" + #ifndef RESOURCE_JSON_H + #define RESOURCE_JSON_H - class MyJson : public Resource { - GDCLASS(MyJson, Resource); + #include "core/io/json.h" + #include "core/variant_parser.h" - protected: - static void _bind_methods() { - ClassDB::bind_method(D_METHOD("to_string"), &MyJson::to_string); - } + class JsonResource : public Resource { + GDCLASS(JsonResource, Resource); - private: - Dictionary dict; + protected: + static void _bind_methods() { + ClassDB::bind_method(D_METHOD("set_dict", "dict"), &JsonResource::set_dict); + ClassDB::bind_method(D_METHOD("get_dict"), &JsonResource::get_dict); - public: - Error set_file(const String &p_path) { - Error error_file; - FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error_file); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "content", PROPERTY_HINT_NONE, ""), "set_dict", "get_dict"); + } - String buf = String(""); - while (!file->eof_reached()) { - buf += file->get_line(); - } - String err_string; - int err_line; - JSON cmd; - Variant ret; - Error err = cmd.parse(buf, ret, err_string, err_line); - dict = Dictionary(ret); - file->close(); - return OK; - } + private: + Dictionary content; - String to_string() const { - return String(*this); - } + public: + Error load_file(const String &p_path); + Error save_file(const String &p_path, const RES &p_resource); - operator String() const { - JSON a; - return a.print(dict); - } + void set_dict(const Dictionary &p_dict); + Dictionary get_dict(); + }; + #endif // RESOURCE_JSON_H - MyJson() {}; - ~MyJson() {}; - }; - #endif // MY_JSON_H +.. code:: cpp + + /* resource_json.cpp */ + + #include "resource_json.h" + + Error JsonResource::load_file(const String &p_path) { + Error error; + FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error); + if (!error == OK) { + if (file) + file->close(); + return error; + } + + String json_string = String(""); + while (!file->eof_reached()) + json_string += file->get_line(); + file->close(); + + String error_string; + int error_line; + JSON json; + Variant result; + error = json.parse(json_string, result, error_string, error_line); + if (!error == OK) { + file->close(); + return error; + } + + content = Dictionary(result); + return OK; + } + + Error JsonResource::save_file(const String &p_path, const RES &p_resource) { + Error error; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &error); + if (!error == OK) { + if (file) + file->close(); + return error; + } + + Ref json_ref = p_resource.get_ref_ptr(); + JSON json; + + file->store_string(json.print(json_ref->get_dict(), " ")); + file->close(); + return Error::OK; + } + + void JsonResource::set_dict(const Dictionary &p_dict) { + content = p_dict; + } + + Dictionary JsonResource::get_dict() { + return content; + } Considerations ~~~~~~~~~~~~~~ @@ -181,32 +263,32 @@ calls into ``std::istream``. .. code-block:: cpp - #include - #include + #include + #include - class GodotFileInStreamBuf : public std::streambuf { + class GodotFileInStreamBuf : public std::streambuf { - public: - GodotFileInStreamBuf(FileAccess *fa) { - _file = fa; - } - int underflow() { - if (_file->eof_reached()) { - return EOF; - } else { - size_t pos = _file->get_position(); - uint8_t ret = _file->get_8(); - _file->seek(pos); // required since get_8() advances the read head - return ret; - } - } - int uflow() { - return _file->eof_reached() ? EOF : _file->get_8(); - } + public: + GodotFileInStreamBuf(FileAccess *fa) { + _file = fa; + } + int underflow() { + if (_file->eof_reached()) { + return EOF; + } else { + size_t pos = _file->get_position(); + uint8_t ret = _file->get_8(); + _file->seek(pos); // required since get_8() advances the read head + return ret; + } + } + int uflow() { + return _file->eof_reached() ? EOF : _file->get_8(); + } - private: - FileAccess *_file; - }; + private: + FileAccess *_file; + }; References @@ -225,23 +307,42 @@ when ``load`` is called. .. code-block:: cpp - /* register_types.cpp */ - #include "register_types.h" - #include "core/class_db.h" + /* register_types.h */ - #include "my_json_loader.h" - #include "my_json.h" + void register_json_types(); + void unregister_json_types(); - static ResourceFormatLoaderMyJson *my_json_loader = NULL; - void register_my_json_types() { - my_json_loader = memnew(ResourceFormatLoaderMyJson); - ResourceLoader::add_resource_format_loader(my_json_loader); - ClassDB::register_class(); - } +.. code:: cpp - void unregister_my_json_types() { - memdelete(my_json_loader); - } + /* register_types.cpp */ + + #include "register_types.h" + #include "core/class_db.h" + + #include "resource_loader_json.h" + #include "resource_saver_json.h" + #include "resource_json.h" + + static Ref json_loader; + static Ref json_saver; + + void register_json_types() { + ClassDB::register_class(); + + json_loader.instance(); + ResourceLoader::add_resource_format_loader(json_loader); + + json_saver.instance(); + ResourceSaver::add_resource_format_saver(json_saver); + } + + void unregister_json_types() { + ResourceLoader::remove_resource_format_loader(json_loader); + json_loader.unref(); + + ResourceSaver::remove_resource_format_saver(json_saver); + json_saver.unref(); + } References ~~~~~~~~~~ @@ -253,8 +354,9 @@ Loading it on GDScript .. code-block:: json + /* example .json file */ { - "savefilename" : "demo.mjson", + "savefilename" : "demo.json", "demo": [ "welcome", "to", @@ -268,6 +370,7 @@ Loading it on GDScript extends Node + onready var json_resource = load("res://demo.json") + func _ready(): - var myjson = load("res://demo.mjson") - print(myjson.to_string()) + print(json_resource.get_dict())