diff options
-rw-r--r-- | core/io/json.cpp | 86 | ||||
-rw-r--r-- | core/io/json.h | 20 | ||||
-rw-r--r-- | core/register_core_types.cpp | 14 | ||||
-rw-r--r-- | doc/classes/JSON.xml | 18 |
4 files changed, 127 insertions, 11 deletions
diff --git a/core/io/json.cpp b/core/io/json.cpp index 91500ff3d5..a685fcb718 100644 --- a/core/io/json.cpp +++ b/core/io/json.cpp @@ -497,6 +497,10 @@ Error JSON::_parse_object(Dictionary &object, const char32_t *p_str, int &index, return ERR_PARSE_ERROR; } +void JSON::set_data(const Variant &p_data) { + data = p_data; +} + Error JSON::_parse_string(const String &p_json, Variant &r_ret, String &r_err_str, int &r_err_line) { const char32_t *str = p_json.ptr(); int idx = 0; @@ -557,6 +561,88 @@ void JSON::_bind_methods() { ClassDB::bind_method(D_METHOD("parse", "json_string"), &JSON::parse); ClassDB::bind_method(D_METHOD("get_data"), &JSON::get_data); + ClassDB::bind_method(D_METHOD("set_data", "data"), &JSON::set_data); ClassDB::bind_method(D_METHOD("get_error_line"), &JSON::get_error_line); ClassDB::bind_method(D_METHOD("get_error_message"), &JSON::get_error_message); + + ADD_PROPERTY(PropertyInfo(Variant::NIL, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT), "set_data", "get_data"); // Ensures that it can be serialized as binary. +} + +//// + +//////////// + +Ref<Resource> ResourceFormatLoaderJSON::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } + + if (!FileAccess::exists(p_path)) { + *r_error = ERR_FILE_NOT_FOUND; + return Ref<Resource>(); + } + + Ref<JSON> json; + json.instantiate(); + + Error err = json->parse(FileAccess::get_file_as_string(p_path)); + if (err != OK) { + if (r_error) { + *r_error = err; + } + ERR_PRINT("Error parsing JSON file at '" + p_path + "', on line " + itos(json->get_error_line()) + ": " + json->get_error_message()); + return Ref<Resource>(); + } + + if (r_error) { + *r_error = OK; + } + + return json; +} + +void ResourceFormatLoaderJSON::get_recognized_extensions(List<String> *p_extensions) const { + p_extensions->push_back("json"); +} + +bool ResourceFormatLoaderJSON::handles_type(const String &p_type) const { + return (p_type == "JSON"); +} + +String ResourceFormatLoaderJSON::get_resource_type(const String &p_path) const { + String el = p_path.get_extension().to_lower(); + if (el == "json") { + return "JSON"; + } + return ""; +} + +Error ResourceFormatSaverJSON::save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags) { + Ref<JSON> json = p_resource; + ERR_FAIL_COND_V(json.is_null(), ERR_INVALID_PARAMETER); + + String source = JSON::stringify(json->get_data(), "\t", false, true); + + Error err; + Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + ERR_FAIL_COND_V_MSG(err, err, "Cannot save json '" + p_path + "'."); + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + return ERR_CANT_CREATE; + } + + return OK; +} + +void ResourceFormatSaverJSON::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const { + Ref<JSON> json = p_resource; + if (json.is_valid()) { + p_extensions->push_back("json"); + } +} + +bool ResourceFormatSaverJSON::recognize(const Ref<Resource> &p_resource) const { + return p_resource->get_class_name() == "JSON"; //only json, not inherited } diff --git a/core/io/json.h b/core/io/json.h index 840b1cc08a..208d4ad625 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -31,7 +31,9 @@ #ifndef JSON_H #define JSON_H -#include "core/object/ref_counted.h" +#include "core/io/resource.h" +#include "core/io/resource_loader.h" +#include "core/io/resource_saver.h" #include "core/variant/variant.h" class JSON : public RefCounted { @@ -86,8 +88,24 @@ public: static Variant parse_string(const String &p_json_string); inline Variant get_data() const { return data; } + void set_data(const Variant &p_data); inline int get_error_line() const { return err_line; } inline String get_error_message() const { return err_str; } }; +class ResourceFormatLoaderJSON : public ResourceFormatLoader { +public: + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + 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; +}; + +class ResourceFormatSaverJSON : public ResourceFormatSaver { +public: + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual bool recognize(const Ref<Resource> &p_resource) const; +}; + #endif // JSON_H diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp index 6650d9be23..6dfb0f82e0 100644 --- a/core/register_core_types.cpp +++ b/core/register_core_types.cpp @@ -87,6 +87,8 @@ static Ref<TranslationLoaderPO> resource_format_po; static Ref<ResourceFormatSaverCrypto> resource_format_saver_crypto; static Ref<ResourceFormatLoaderCrypto> resource_format_loader_crypto; static Ref<NativeExtensionResourceLoader> resource_loader_native_extension; +static Ref<ResourceFormatSaverJSON> resource_saver_json; +static Ref<ResourceFormatLoaderJSON> resource_loader_json; static core_bind::ResourceLoader *_resource_loader = nullptr; static core_bind::ResourceSaver *_resource_saver = nullptr; @@ -211,6 +213,12 @@ void register_core_types() { resource_format_loader_crypto.instantiate(); ResourceLoader::add_resource_format_loader(resource_format_loader_crypto); + resource_loader_json.instantiate(); + ResourceLoader::add_resource_format_loader(resource_loader_json); + + resource_saver_json.instantiate(); + ResourceSaver::add_resource_format_saver(resource_saver_json); + GDREGISTER_CLASS(MainLoop); GDREGISTER_CLASS(Translation); GDREGISTER_CLASS(OptimizedTranslation); @@ -387,6 +395,12 @@ void unregister_core_types() { ResourceLoader::remove_resource_format_loader(resource_format_loader_crypto); resource_format_loader_crypto.unref(); + ResourceSaver::remove_resource_format_saver(resource_saver_json); + resource_saver_json.unref(); + + ResourceLoader::remove_resource_format_loader(resource_loader_json); + resource_loader_json.unref(); + if (ip) { memdelete(ip); } diff --git a/doc/classes/JSON.xml b/doc/classes/JSON.xml index 46e46cc164..38ddca2727 100644 --- a/doc/classes/JSON.xml +++ b/doc/classes/JSON.xml @@ -6,7 +6,7 @@ <description> The [JSON] enables all data types to be converted to and from a JSON string. This useful for serializing data to save to a file or send over the network. [method stringify] is used to convert any data type into a JSON string. - [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [method get_data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. + [method parse] is used to convert any existing JSON data into a [Variant] that can be used within Godot. If successfully parsed, use [member data] to retrieve the [Variant], and use [code]typeof[/code] to check if the Variant's type is what you expect. JSON Objects are converted into a [Dictionary], but JSON data can be used to store [Array]s, numbers, [String]s and even just a boolean. [b]Example[/b] [codeblock] var data_to_send = ["a", "b", "c"] @@ -16,7 +16,7 @@ # Retrieve data var error = json.parse(json_string) if error == OK: - var data_received = json.get_data() + var data_received = json.data if typeof(data_received) == TYPE_ARRAY: print(data_received) # Prints array else: @@ -32,13 +32,6 @@ <tutorials> </tutorials> <methods> - <method name="get_data" qualifiers="const"> - <return type="Variant" /> - <description> - Returns the [Variant] containing the data of a successful [method parse]. - [b]Note:[/b] It will return [code]Null[/code] if the last call to parse was unsuccessful or [method parse] has not yet been called. - </description> - </method> <method name="get_error_line" qualifiers="const"> <return type="int" /> <description> @@ -56,7 +49,7 @@ <param index="0" name="json_string" type="String" /> <description> Attempts to parse the [param json_string] provided. - Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [method get_data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. + Returns an [enum Error]. If the parse was successful, it returns [code]OK[/code] and the result can be retrieved using [member data]. If unsuccessful, use [method get_error_line] and [method get_error_message] for identifying the source of the failure. Non-static variant of [method parse_string], if you want custom error handling. </description> </method> @@ -118,4 +111,9 @@ </description> </method> </methods> + <members> + <member name="data" type="Variant" setter="set_data" getter="get_data" default="null"> + Contains the parsed JSON data in [Variant] form. + </member> + </members> </class> |