|
@@ -57,55 +57,100 @@ read and handle data serialization.
|
|
|
|
|
|
.. code-block:: cpp
|
|
.. 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<String> *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<String> *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
|
|
.. code-block:: cpp
|
|
|
|
|
|
- #include "my_json_loader.h"
|
|
|
|
- #include "my_json.h"
|
|
|
|
|
|
+ /* resource_loader_json.cpp */
|
|
|
|
|
|
- ResourceFormatLoaderMyJson::ResourceFormatLoaderMyJson() {
|
|
|
|
- }
|
|
|
|
|
|
+ #include "resource_loader_json.h"
|
|
|
|
+ #include "resource_json.h"
|
|
|
|
|
|
- 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<MyJson>(my);
|
|
|
|
- }
|
|
|
|
|
|
|
|
- void ResourceFormatLoaderMyJson::get_recognized_extensions(List<String> *p_extensions) const {
|
|
|
|
- p_extensions->push_back("mjson");
|
|
|
|
- }
|
|
|
|
|
|
+ RES ResourceFormatLoaderJson::load(const String &p_path, const String &p_original_path, Error *r_error) {
|
|
|
|
+ Ref<JsonResource> json = memnew(JsonResource);
|
|
|
|
+ if (r_error)
|
|
|
|
+ *r_error = OK;
|
|
|
|
+ Error err = json->load_file(p_path);
|
|
|
|
+ return json;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void ResourceFormatLoaderJson::get_recognized_extensions(List<String> *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
|
|
|
|
|
|
- String ResourceFormatLoaderMyJson::get_resource_type(const String &p_path) const {
|
|
|
|
|
|
+ #include "core/io/resource_saver.h"
|
|
|
|
|
|
- if (p_path.get_extension().to_lower() == "mjson")
|
|
|
|
- return "MyJson";
|
|
|
|
- return "";
|
|
|
|
- }
|
|
|
|
|
|
+ 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<String> *p_extensions) const;
|
|
|
|
+ };
|
|
|
|
+ #endif // RESOURCE_SAVER_JSON_H
|
|
|
|
+
|
|
|
|
+.. code:: cpp
|
|
|
|
|
|
- bool ResourceFormatLoaderMyJson::handles_type(const String &p_type) const {
|
|
|
|
- return (p_type == "MyJson");
|
|
|
|
- }
|
|
|
|
|
|
+ /* 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<JsonResource> 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<JsonResource>(*p_resource) != NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void ResourceFormatSaverJson::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
|
|
|
|
+ if (Object::cast_to<JsonResource>(*p_resource))
|
|
|
|
+ p_extensions->push_back("json");
|
|
|
|
+ }
|
|
|
|
+
|
|
Creating custom data types
|
|
Creating custom data types
|
|
--------------------------
|
|
--------------------------
|
|
|
|
|
|
@@ -117,58 +162,95 @@ Here is an example of how to create a custom datatype
|
|
|
|
|
|
.. code-block:: cpp
|
|
.. code-block:: cpp
|
|
|
|
|
|
- #ifndef MY_JSON_H
|
|
|
|
- #define MY_JSON_H
|
|
|
|
-
|
|
|
|
- #include "core/dictionary.h"
|
|
|
|
- #include "core/io/json.h"
|
|
|
|
- #include "core/reference.h"
|
|
|
|
- #include "core/variant.h"
|
|
|
|
- #include "core/variant_parser.h"
|
|
|
|
-
|
|
|
|
- class MyJson : public Resource {
|
|
|
|
- GDCLASS(MyJson, Resource);
|
|
|
|
-
|
|
|
|
- protected:
|
|
|
|
- static void _bind_methods() {
|
|
|
|
- ClassDB::bind_method(D_METHOD("to_string"), &MyJson::to_string);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private:
|
|
|
|
- Dictionary dict;
|
|
|
|
-
|
|
|
|
- public:
|
|
|
|
- Error set_file(const String &p_path) {
|
|
|
|
- Error error_file;
|
|
|
|
- FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error_file);
|
|
|
|
-
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- String to_string() const {
|
|
|
|
- return String(*this);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- operator String() const {
|
|
|
|
- JSON a;
|
|
|
|
- return a.print(dict);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- MyJson() {};
|
|
|
|
- ~MyJson() {};
|
|
|
|
- };
|
|
|
|
- #endif // MY_JSON_H
|
|
|
|
|
|
+ /* resource_json.h */
|
|
|
|
+
|
|
|
|
+ #ifndef RESOURCE_JSON_H
|
|
|
|
+ #define RESOURCE_JSON_H
|
|
|
|
+
|
|
|
|
+ #include "core/io/json.h"
|
|
|
|
+ #include "core/variant_parser.h"
|
|
|
|
+
|
|
|
|
+ class JsonResource : public Resource {
|
|
|
|
+ GDCLASS(JsonResource, Resource);
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "content", PROPERTY_HINT_NONE, ""), "set_dict", "get_dict");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ Dictionary content;
|
|
|
|
+
|
|
|
|
+ public:
|
|
|
|
+ Error load_file(const String &p_path);
|
|
|
|
+ Error save_file(const String &p_path, const RES &p_resource);
|
|
|
|
+
|
|
|
|
+ void set_dict(const Dictionary &p_dict);
|
|
|
|
+ Dictionary get_dict();
|
|
|
|
+ };
|
|
|
|
+ #endif // RESOURCE_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<JsonResource> 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
|
|
Considerations
|
|
~~~~~~~~~~~~~~
|
|
~~~~~~~~~~~~~~
|
|
@@ -181,32 +263,32 @@ calls into ``std::istream``.
|
|
|
|
|
|
.. code-block:: cpp
|
|
.. code-block:: cpp
|
|
|
|
|
|
- #include <istream>
|
|
|
|
- #include <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();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private:
|
|
|
|
- FileAccess *_file;
|
|
|
|
- };
|
|
|
|
|
|
+ #include <istream>
|
|
|
|
+ #include <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();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ FileAccess *_file;
|
|
|
|
+ };
|
|
|
|
|
|
|
|
|
|
References
|
|
References
|
|
@@ -225,23 +307,42 @@ when ``load`` is called.
|
|
|
|
|
|
.. code-block:: cpp
|
|
.. code-block:: cpp
|
|
|
|
|
|
- /* register_types.cpp */
|
|
|
|
- #include "register_types.h"
|
|
|
|
- #include "core/class_db.h"
|
|
|
|
|
|
+ /* register_types.h */
|
|
|
|
+
|
|
|
|
+ void register_json_types();
|
|
|
|
+ void unregister_json_types();
|
|
|
|
+
|
|
|
|
+.. code:: cpp
|
|
|
|
+
|
|
|
|
+ /* 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"
|
|
|
|
|
|
- #include "my_json_loader.h"
|
|
|
|
- #include "my_json.h"
|
|
|
|
|
|
+ static Ref<ResourceFormatLoaderJson> json_loader;
|
|
|
|
+ static Ref<ResourceFormatSaverJson> json_saver;
|
|
|
|
|
|
- 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<MyJson>();
|
|
|
|
- }
|
|
|
|
|
|
+ void register_json_types() {
|
|
|
|
+ ClassDB::register_class<JsonResource>();
|
|
|
|
|
|
- void unregister_my_json_types() {
|
|
|
|
- memdelete(my_json_loader);
|
|
|
|
- }
|
|
|
|
|
|
+ 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
|
|
References
|
|
~~~~~~~~~~
|
|
~~~~~~~~~~
|
|
@@ -253,8 +354,9 @@ Loading it on GDScript
|
|
|
|
|
|
.. code-block:: json
|
|
.. code-block:: json
|
|
|
|
|
|
|
|
+ /* example .json file */
|
|
{
|
|
{
|
|
- "savefilename" : "demo.mjson",
|
|
|
|
|
|
+ "savefilename" : "demo.json",
|
|
"demo": [
|
|
"demo": [
|
|
"welcome",
|
|
"welcome",
|
|
"to",
|
|
"to",
|
|
@@ -268,6 +370,7 @@ Loading it on GDScript
|
|
|
|
|
|
extends Node
|
|
extends Node
|
|
|
|
|
|
|
|
+ onready var json_resource = load("res://demo.json")
|
|
|
|
+
|
|
func _ready():
|
|
func _ready():
|
|
- var myjson = load("res://demo.mjson")
|
|
|
|
- print(myjson.to_string())
|
|
|
|
|
|
+ print(json_resource.get_dict())
|