custom_resource_format_loaders.rst 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. .. _doc_custom_resource_format_loaders:
  2. Custom resource format loaders
  3. ==============================
  4. Introduction
  5. ------------
  6. ResourceFormatLoader is a factory interface for loading file assets.
  7. Resources are primary containers. When load is called on the same file
  8. path again, the previous loaded Resource will be referenced. Naturally,
  9. loaded resources must be stateless.
  10. This guide assumes the reader knows how to create C++ modules and Godot
  11. data types. If not, refer to this guide :ref:`doc_custom_modules_in_c++`.
  12. References
  13. ~~~~~~~~~~
  14. - :ref:`ResourceLoader<class_resourceloader>`
  15. - `core/io/resource_loader.cpp <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.cpp#L258>`__
  16. What for?
  17. ---------
  18. - Adding new support for many file formats
  19. - Audio formats
  20. - Video formats
  21. - Machine learning models
  22. What not?
  23. ---------
  24. - Raster images
  25. ImageFormatLoader should be used to load images.
  26. References
  27. ~~~~~~~~~~
  28. - `core/io/image_loader.h <https://github.com/godotengine/godot/blob/master/core/io/image_loader.h>`__
  29. Creating a ResourceFormatLoader
  30. -------------------------------
  31. Each file format consist of a data container and a ``ResourceFormatLoader``.
  32. ResourceFormatLoaders are usually simple classes which return all the
  33. necessary metadata for supporting new extensions in Godot. The
  34. class must the return the format name and the extension string.
  35. In addition, ResourceFormatLoaders must convert file paths into
  36. resources with the ``load`` function. To load a resource, ``load`` must
  37. read and handle data serialization.
  38. .. code:: cpp
  39. #ifndef MY_JSON_LOADER_H
  40. #define MY_JSON_LOADER_H
  41. #include "core/io/resource_loader.h"
  42. class ResourceFormatLoaderMyJson : public ResourceFormatLoader {
  43. public:
  44. virtual RES load(const String &p_path, const String &p_original_path, Error *r_error = NULL);
  45. virtual void get_recognized_extensions(List<String> *p_extensions) const;
  46. virtual bool handles_type(const String &p_type) const;
  47. virtual String get_resource_type(const String &p_path) const;
  48. ResourceFormatLoaderMyJson();
  49. virtual ~ResourceFormatLoaderMyJson() {}
  50. };
  51. #endif // MY_JSON_LOADER_H
  52. .. code:: cpp
  53. #include "my_json_loader.h"
  54. #include "my_json.h"
  55. ResourceFormatLoaderMyJson::ResourceFormatLoaderMyJson() {
  56. }
  57. RES ResourceFormatLoaderMyJson::load(const String &p_path, const String &p_original_path, Error *r_error) {
  58. MyJson *my = memnew(MyJson);
  59. if (r_error)
  60. *r_error = OK;
  61. Error err = my->set_file(p_path);
  62. return Ref<MyJson>(my);
  63. }
  64. void ResourceFormatLoaderMyJson::get_recognized_extensions(List<String> *p_extensions) const {
  65. p_extensions->push_back("mjson");
  66. }
  67. String ResourceFormatLoaderMyJson::get_resource_type(const String &p_path) const {
  68. if (p_path.get_extension().to_lower() == "mjson")
  69. return "MyJson";
  70. return "";
  71. }
  72. bool ResourceFormatLoaderMyJson::handles_type(const String &p_type) const {
  73. return (p_type == "MyJson");
  74. }
  75. Creating custom data types
  76. --------------------------
  77. Godot may not have a proper substitute within its :ref:`doc_core_types`
  78. or managed resources. Godot needs a new registered data type to
  79. understand additional binary formats such as machine learning models.
  80. Here is an example of how to create a custom datatype
  81. .. code:: cpp
  82. #ifndef MY_JSON_H
  83. #define MY_JSON_H
  84. #include "core/dictionary.h"
  85. #include "core/io/json.h"
  86. #include "core/reference.h"
  87. #include "core/variant.h"
  88. #include "core/variant_parser.h"
  89. class MyJson : public Resource {
  90. GDCLASS(MyJson, Resource);
  91. protected:
  92. static void _bind_methods() {
  93. ClassDB::bind_method(D_METHOD("to_string"), &MyJson::to_string);
  94. }
  95. private:
  96. Dictionary dict;
  97. public:
  98. Error set_file(const String &p_path) {
  99. Error error_file;
  100. FileAccess *file = FileAccess::open(p_path, FileAccess::READ, &error_file);
  101. String buf = String("");
  102. while (!file->eof_reached()) {
  103. buf += file->get_line();
  104. }
  105. String err_string;
  106. int err_line;
  107. JSON cmd;
  108. Variant ret;
  109. Error err = cmd.parse(buf, ret, err_string, err_line);
  110. dict = Dictionary(ret);
  111. file->close();
  112. return OK;
  113. }
  114. String to_string() const {
  115. return String(*this);
  116. }
  117. operator String() const {
  118. JSON a;
  119. return a.print(dict);
  120. }
  121. MyJson() {};
  122. ~MyJson() {};
  123. };
  124. #endif // MY_JSON_H
  125. Considerations
  126. ~~~~~~~~~~~~~~
  127. Some libraries may not define certain common routines such as IO handling.
  128. Therefore, Godot call translations are required.
  129. For example, here is the code for translating ``FileAccess``
  130. calls into ``std::istream``.
  131. .. code:: cpp
  132. #include <istream>
  133. #include <streambuf>
  134. class GodotFileInStreamBuf : public std::streambuf {
  135. public:
  136. GodotFileInStreamBuf(FileAccess *fa) {
  137. _file = fa;
  138. }
  139. int underflow() {
  140. if (_file->eof_reached()) {
  141. return EOF;
  142. } else {
  143. size_t pos = _file->get_position();
  144. uint8_t ret = _file->get_8();
  145. _file->seek(pos); // required since get_8() advances the read head
  146. return ret;
  147. }
  148. }
  149. int uflow() {
  150. return _file->eof_reached() ? EOF : _file->get_8();
  151. }
  152. private:
  153. FileAccess *_file;
  154. };
  155. References
  156. ~~~~~~~~~~
  157. - `istream <http://www.cplusplus.com/reference/istream/istream/>`__
  158. - `streambuf <http://www.cplusplus.com/reference/streambuf/streambuf/?kw=streambuf>`__
  159. - `core/io/fileaccess.h <https://github.com/godotengine/godot/blob/master/core/os/file_access.h>`__
  160. Registering the new file format
  161. -------------------------------
  162. Godot registers ``ResourcesFormatLoader`` with a ``ResourceLoader``
  163. handler. The handler selects the proper loader automatically
  164. when ``load`` is called.
  165. .. code:: cpp
  166. /* register_types.cpp */
  167. #include "register_types.h"
  168. #include "core/class_db.h"
  169. #include "my_json_loader.h"
  170. #include "my_json.h"
  171. static ResourceFormatLoaderMyJson *my_json_loader = NULL;
  172. void register_my_json_types() {
  173. my_json_loader = memnew(ResourceFormatLoaderMyJson);
  174. ResourceLoader::add_resource_format_loader(my_json_loader);
  175. ClassDB::register_class<MyJson>();
  176. }
  177. void unregister_my_json_types() {
  178. memdelete(my_json_loader);
  179. }
  180. References
  181. ~~~~~~~~~~
  182. - `core/io/resource_loader.cpp <https://github.com/godotengine/godot/blob/master/core/io/resource_loader.cpp#L280>`__
  183. Loading it on GDScript
  184. ----------------------
  185. .. code::
  186. {
  187. "savefilename" : "demo.mjson",
  188. "demo": [
  189. "welcome",
  190. "to",
  191. "godot",
  192. "resource",
  193. "loaders"
  194. ]
  195. }
  196. .. code::
  197. extends Node
  198. func _ready():
  199. var myjson = load("res://demo.mjson")
  200. print(myjson.to_string())