123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- .. _doc_custom_resource_format_loaders:
- Custom resource format loaders
- ==============================
- Introduction
- ------------
- ResourceFormatLoader is a factory interface for loading file assets.
- Resources are primary containers. When load is called on the same file
- path again, the previous loaded Resource will be referenced. Naturally,
- loaded resources must be stateless.
- This guide assumes the reader knows how to create C++ modules and Godot
- data types. If not, refer to this guide :ref:`doc_custom_modules_in_c++`.
- References
- ~~~~~~~~~~
- - :ref:`ResourceLoader<class_resourceloader>`
- - `core/io/resource_loader.cpp <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.cpp#L258>`__
- What for?
- ---------
- - Adding new support for many file formats
- - Audio formats
- - Video formats
- - Machine learning models
- What not?
- ---------
- - Raster images
- ImageFormatLoader should be used to load images.
- References
- ~~~~~~~~~~
- - `core/io/image_loader.h <https://github.com/godotengine/godot/blob/master/core/io/image_loader.h>`__
- Creating a ResourceFormatLoader
- -------------------------------
- Each file format consist of a data container and a ``ResourceFormatLoader``.
- ResourceFormatLoaders are usually simple classes which return all the
- necessary metadata for supporting new extensions in Godot. The
- class must the return the format name and the extension string.
- In addition, ResourceFormatLoaders must convert file paths into
- resources with the ``load`` function. To load a resource, ``load`` must
- read and handle data serialization.
- .. code:: cpp
- #ifndef MY_JSON_LOADER_H
- #define MY_JSON_LOADER_H
- #include "core/io/resource_loader.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;
- ResourceFormatLoaderMyJson();
- virtual ~ResourceFormatLoaderMyJson() {}
- };
- #endif // MY_JSON_LOADER_H
- .. code:: cpp
- #include "my_json_loader.h"
- #include "my_json.h"
- 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<MyJson>(my);
- }
- void ResourceFormatLoaderMyJson::get_recognized_extensions(List<String> *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");
- }
- Creating custom data types
- --------------------------
- Godot may not have a proper substitute within its :ref:`doc_core_types`
- or managed resources. Godot needs a new registered data type to
- understand additional binary formats such as machine learning models.
- Here is an example of how to create a custom datatype
- .. code:: 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
- Considerations
- ~~~~~~~~~~~~~~
- Some libraries may not define certain common routines such as IO handling.
- Therefore, Godot call translations are required.
- For example, here is the code for translating ``FileAccess``
- calls into ``std::istream``.
- .. code:: 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;
- };
- References
- ~~~~~~~~~~
- - `istream <http://www.cplusplus.com/reference/istream/istream/>`__
- - `streambuf <http://www.cplusplus.com/reference/streambuf/streambuf/?kw=streambuf>`__
- - `core/io/fileaccess.h <https://github.com/godotengine/godot/blob/master/core/os/file_access.h>`__
- Registering the new file format
- -------------------------------
- Godot registers ``ResourcesFormatLoader`` with a ``ResourceLoader``
- handler. The handler selects the proper loader automatically
- when ``load`` is called.
- .. code:: cpp
- /* register_types.cpp */
- #include "register_types.h"
- #include "core/class_db.h"
- #include "my_json_loader.h"
- #include "my_json.h"
- 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 unregister_my_json_types() {
- memdelete(my_json_loader);
- }
- References
- ~~~~~~~~~~
- - `core/io/resource_loader.cpp <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.cpp#L280>`__
- Loading it on GDScript
- ----------------------
- .. code::
- {
- "savefilename" : "demo.mjson",
- "demo": [
- "welcome",
- "to",
- "godot",
- "resource",
- "loaders"
- ]
- }
- .. code::
- extends Node
- func _ready():
- var myjson = load("res://demo.mjson")
- print(myjson.to_string())
|