runtime_file_loading_and_saving.rst 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. .. _doc_runtime_loading_and_saving:
  2. Runtime file loading and saving
  3. ===============================
  4. .. seealso::
  5. See :ref:`doc_saving_games` for information on saving and loading game progression.
  6. Sometimes, :ref:`exporting packs, patches, and mods <doc_exporting_pcks>` is not
  7. ideal when you want players to be able to load user-generated content in your
  8. project. It requires users to generate a PCK or ZIP file through the Godot
  9. editor, which contains resources imported by Godot.
  10. Example use cases for runtime file loading and saving include:
  11. - Loading texture packs designed for the game.
  12. - Loading user-provided audio tracks and playing them back in an in-game radio station.
  13. - Loading custom levels or 3D models that can be designed with any 3D DCC that
  14. can export to glTF or FBX (including glTF scenes saved by Godot at runtime).
  15. - Using user-provided fonts for menus and HUD.
  16. - Saving/loading a file format that can contain multiple files but can still
  17. easily be read by other applications (ZIP).
  18. - Loading files created by another game or program, or even game data files from
  19. another game not made with Godot.
  20. Runtime file loading can be combined with :ref:`HTTP requests <doc_http_request_class>`
  21. to load resources from the Internet directly.
  22. .. warning::
  23. Do **not** use this runtime loading approach to load resources that are part
  24. of the project, as it's less efficient and doesn't allow benefiting from
  25. Godot's resource handling functionality (such as translation remaps). See
  26. :ref:`doc_import_process` for details.
  27. .. seealso::
  28. You can see how saving and loading works in action using the
  29. `Run-time File Saving and Loading (Serialization) demo project <https://github.com/godotengine/godot-demo-projects/blob/master/loading/runtime_save_load>`__.
  30. Plain text and binary files
  31. ---------------------------
  32. Godot's :ref:`class_FileAccess` class provides methods to access files on the
  33. filesystem for reading and writing:
  34. .. tabs::
  35. .. code-tab:: gdscript
  36. func save_file(content):
  37. var file = FileAccess.open("/path/to/file.txt", FileAccess.WRITE)
  38. file.store_string(content)
  39. func load_file():
  40. var file = FileAccess.open("/path/to/file.txt", FileAccess.READ)
  41. var content = file.get_as_text()
  42. return content
  43. .. code-tab:: csharp
  44. private void SaveFile(string content)
  45. {
  46. using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Write);
  47. file.StoreString(content);
  48. }
  49. private string LoadFile()
  50. {
  51. using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Read);
  52. string content = file.GetAsText();
  53. return content;
  54. }
  55. To handle custom binary formats (such as loading file formats not supported by
  56. Godot), :ref:`class_FileAccess` provides several methods to read/write integers,
  57. floats, strings and more. These FileAccess methods have names that start with
  58. ``get_`` and ``store_``.
  59. If you need more control over reading binary files or need to read binary
  60. streams that are not part of a file, :ref:`class_PackedByteArray` provides
  61. several helper methods to decode/encode series of bytes to integers, floats,
  62. strings and more. These PackedByteArray methods have names that start with
  63. ``decode_`` and ``encode_``. See also :ref:`doc_binary_serialization_api`.
  64. .. _doc_runtime_file_loading_and_saving_images:
  65. Images
  66. ------
  67. Image's :ref:`Image.load_from_file <class_Image_method_load_from_file>` static method
  68. handles everything, from format detection based on file extension to reading the
  69. file from disk.
  70. If you need error handling or more control (such as changing the scale an SVG is
  71. loaded at), use one of the following methods depending on the file format:
  72. - :ref:`Image.load_jpg_from_buffer <class_Image_method_load_jpg_from_buffer>`
  73. - :ref:`Image.load_ktx_from_buffer <class_Image_method_load_ktx_from_buffer>`
  74. - :ref:`Image.load_png_from_buffer <class_Image_method_load_png_from_buffer>`
  75. - :ref:`Image.load_svg_from_buffer <class_Image_method_load_svg_from_buffer>`
  76. or :ref:`Image.load_svg_from_string <class_Image_method_load_svg_from_string>`
  77. - :ref:`Image.load_tga_from_buffer <class_Image_method_load_tga_from_buffer>`
  78. - :ref:`Image.load_webp_from_buffer <class_Image_method_load_webp_from_buffer>`
  79. Several image formats can also be saved by Godot at runtime using the following
  80. methods:
  81. - :ref:`Image.save_png <class_Image_method_save_png>`
  82. or :ref:`Image.save_png_to_buffer <class_Image_method_save_png_to_buffer>`
  83. - :ref:`Image.save_webp <class_Image_method_save_webp>`
  84. or :ref:`Image.save_webp_to_buffer <class_Image_method_save_webp_to_buffer>`
  85. - :ref:`Image.save_jpg <class_Image_method_save_jpg>`
  86. or :ref:`Image.save_jpg_to_buffer <class_Image_method_save_jpg_to_buffer>`
  87. - :ref:`Image.save_exr <class_Image_method_save_exr>`
  88. or :ref:`Image.save_exr_to_buffer <class_Image_method_save_exr_to_buffer>`
  89. *(only available in editor builds, cannot be used in exported projects)*
  90. The methods with the ``to_buffer`` suffix save the image to a PackedByteArray
  91. instead of the filesystem. This is useful to send the image over the network or
  92. into a ZIP archive without having to write it on the filesystem. This can
  93. increase performance by reducing I/O utilization.
  94. .. note::
  95. If displaying the loaded image on a 3D surface, make sure to call
  96. :ref:`Image.generate_mipmaps <class_Image_method_generate_mipmaps>`
  97. so that the texture doesn't look grainy when viewed at a distance.
  98. This is also useful in 2D when following instructions on
  99. :ref:`reducing aliasing when downsampling <doc_multiple_resolutions_reducing_aliasing_on_downsampling>`.
  100. Example of loading an image and displaying it in a :ref:`class_TextureRect` node
  101. (which requires conversion to :ref:`class_ImageTexture`):
  102. .. tabs::
  103. .. code-tab:: gdscript
  104. # Load an image of any format supported by Godot from the filesystem.
  105. var image = Image.load_from_file(path)
  106. # Optionally, generate mipmaps if displaying the texture on a 3D surface
  107. # so that the texture doesn't look grainy when viewed at a distance.
  108. #image.generate_mipmaps()
  109. $TextureRect.texture = ImageTexture.create_from_image(image)
  110. # Save the loaded Image to a PNG image.
  111. image.save_png("/path/to/file.png")
  112. # Save the converted ImageTexture to a PNG image.
  113. $TextureRect.texture.get_image().save_png("/path/to/file.png")
  114. .. code-tab:: csharp
  115. // Load an image of any format supported by Godot from the filesystem.
  116. var image = Image.LoadFromFile(path);
  117. // Optionally, generate mipmaps if displaying the texture on a 3D surface
  118. // so that the texture doesn't look grainy when viewed at a distance.
  119. // image.GenerateMipmaps();
  120. GetNode<TextureRect>("TextureRect").Texture = ImageTexture.CreateFromImage(image);
  121. // Save the loaded Image to a PNG image.
  122. image.SavePng("/Path/To/File.png");
  123. // Save the converted ImageTexture to a PNG image.
  124. GetNode<TextureRect>("TextureRect").Texture.GetImage().SavePng("/Path/To/File.png");
  125. .. _doc_runtime_file_loading_and_saving_audio_video_files:
  126. Audio/video files
  127. -----------------
  128. Godot supports loading Ogg Vorbis, MP3, and WAV audio at runtime. Note that not *all*
  129. files with a ``.ogg`` extension are Ogg Vorbis files. Some may be Ogg Theora
  130. videos, or contain Opus audio within an Ogg container. These files will **not**
  131. load correctly as audio files in Godot.
  132. Example of loading an Ogg Vorbis audio file in an :ref:`class_AudioStreamPlayer` node:
  133. .. tabs::
  134. .. code-tab:: gdscript
  135. $AudioStreamPlayer.stream = AudioStreamOggVorbis.load_from_file(path)
  136. .. code-tab:: csharp
  137. GetNode<AudioStreamPlayer>("AudioStreamPlayer").Stream = AudioStreamOggVorbis.LoadFromFile(path);
  138. Example of loading an Ogg Theora video file in a :ref:`class_VideoStreamPlayer` node:
  139. .. tabs::
  140. .. code-tab:: gdscript
  141. var video_stream_theora = VideoStreamTheora.new()
  142. # File extension is ignored, so it is possible to load Ogg Theora videos
  143. # that have a `.ogg` extension this way.
  144. video_stream_theora.file = "/path/to/file.ogv"
  145. $VideoStreamPlayer.stream = video_stream_theora
  146. # VideoStreamPlayer's Autoplay property won't work if the stream is empty
  147. # before this property is set, so call `play()` after setting `stream`.
  148. $VideoStreamPlayer.play()
  149. .. code-tab:: csharp
  150. var videoStreamTheora = new VideoStreamTheora();
  151. // File extension is ignored, so it is possible to load Ogg Theora videos
  152. // that have a `.ogg` extension this way.
  153. videoStreamTheora.File = "/Path/To/File.ogv";
  154. GetNode<VideoStreamPlayer>("VideoStreamPlayer").Stream = videoStreamTheora;
  155. // VideoStreamPlayer's Autoplay property won't work if the stream is empty
  156. // before this property is set, so call `Play()` after setting `Stream`.
  157. GetNode<VideoStreamPlayer>("VideoStreamPlayer").Play();
  158. .. _doc_runtime_file_loading_and_saving_3d_scenes:
  159. 3D scenes
  160. ---------
  161. Godot has first-class support for glTF 2.0, both in the editor and exported
  162. projects. Using :ref:`class_gltfdocument` and :ref:`class_gltfstate` together,
  163. Godot can load and save glTF files in exported projects, in both text
  164. (``.gltf``) and binary (``.glb``) formats. The binary format should be preferred
  165. as it's faster to write and smaller, but the text format is easier to debug.
  166. Since Godot 4.3, FBX scenes can also be loaded (but not saved) at runtime using the
  167. :ref:`class_fbxdocument` and :ref:`class_fbxstate` classes. The code to do so
  168. is the same as glTF, but you will need to replace all instances of
  169. ``GLTFDocument`` and ``GLTFState`` with ``FBXDocument`` and ``FBXState`` in the
  170. code samples below. There are `known issues <https://github.com/godotengine/godot/issues/96043>`__
  171. with runtime FBX loading, so using glTF instead is preferred for now.
  172. Example of loading a glTF scene and appending its root node to the scene:
  173. .. tabs::
  174. .. code-tab:: gdscript
  175. # Load an existing glTF scene.
  176. # GLTFState is used by GLTFDocument to store the loaded scene's state.
  177. # GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
  178. # which means it supports glTF features such as lights and cameras.
  179. var gltf_document_load = GLTFDocument.new()
  180. var gltf_state_load = GLTFState.new()
  181. var error = gltf_document_load.append_from_file("/path/to/file.gltf", gltf_state_load)
  182. if error == OK:
  183. var gltf_scene_root_node = gltf_document_load.generate_scene(gltf_state_load)
  184. add_child(gltf_scene_root_node)
  185. else:
  186. show_error("Couldn't load glTF scene (error code: %s)." % error_string(error))
  187. # Save a new glTF scene.
  188. var gltf_document_save := GLTFDocument.new()
  189. var gltf_state_save := GLTFState.new()
  190. gltf_document_save.append_from_scene(gltf_scene_root_node, gltf_state_save)
  191. # The file extension in the output `path` (`.gltf` or `.glb`) determines
  192. # whether the output uses text or binary format.
  193. # `GLTFDocument.generate_buffer()` is also available for saving to memory.
  194. gltf_document_save.write_to_filesystem(gltf_state_save, path)
  195. .. code-tab:: csharp
  196. // Load an existing glTF scene.
  197. // GLTFState is used by GLTFDocument to store the loaded scene's state.
  198. // GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
  199. // which means it supports glTF features such as lights and cameras.
  200. var gltfDocumentLoad = new GltfDocument();
  201. var gltfStateLoad = new GltfState();
  202. var error = gltfDocumentLoad.AppendFromFile("/Path/To/File.gltf", gltfStateLoad);
  203. if (error == Error.Ok)
  204. {
  205. var gltfSceneRootNode = gltfDocumentLoad.GenerateScene(gltfStateLoad);
  206. AddChild(gltfSceneRootNode);
  207. }
  208. else
  209. {
  210. GD.PrintErr($"Couldn't load glTF scene (error code: {error}).");
  211. }
  212. // Save a new glTF scene.
  213. var gltfDocumentSave = new GltfDocument();
  214. var gltfStateSave = new GltfState();
  215. gltfDocumentSave.AppendFromScene(gltfSceneRootNode, gltfStateSave);
  216. // The file extension in the output `path` (`.gltf` or `.glb`) determines
  217. // whether the output uses text or binary format.
  218. // `GltfDocument.GenerateBuffer()` is also available for saving to memory.
  219. gltfDocumentSave.WriteToFilesystem(gltfStateSave, path);
  220. .. note::
  221. When loading a glTF scene, a *base path* must be set so that external
  222. resources like textures can be loaded correctly. When loading from a file,
  223. the base path is automatically set to the folder containing the file. When
  224. loading from a buffer, this base path must be manually set as there is no
  225. way for Godot to infer this path.
  226. To set the base path, set
  227. :ref:`GLTFState.base_path <class_GLTFState_property_base_path>` on your
  228. GLTFState instance *before* calling
  229. :ref:`GLTFDocument.append_from_buffer <class_GLTFDocument_method_append_from_buffer>`
  230. or :ref:`GLTFDocument.append_from_file <class_GLTFDocument_method_append_from_file>`.
  231. .. _doc_runtime_file_loading_and_saving_fonts:
  232. Fonts
  233. -----
  234. :ref:`FontFile.load_dynamic_font <class_FontFile_method_load_bitmap_font>` supports the following
  235. font file formats: TTF, OTF, WOFF, WOFF2, PFB, PFM
  236. On the other hand, :ref:`FontFile.load_bitmap_font <class_FontFile_method_load_bitmap_font>` supports
  237. the `BMFont <https://www.angelcode.com/products/bmfont/>`__ format (``.fnt`` or ``.font``).
  238. Additionally, it is possible to load any font that is installed on the system using
  239. Godot's support for :ref:`doc_using_fonts_system_fonts`.
  240. Example of loading a font file automatically according to its file extension,
  241. then adding it as a theme override to a :ref:`class_Label` node:
  242. .. tabs::
  243. .. code-tab:: gdscript
  244. var path = "/path/to/font.ttf"
  245. var path_lower = path.to_lower()
  246. var font_file = FontFile.new()
  247. if (
  248. path_lower.ends_with(".ttf")
  249. or path_lower.ends_with(".otf")
  250. or path_lower.ends_with(".woff")
  251. or path_lower.ends_with(".woff2")
  252. or path_lower.ends_with(".pfb")
  253. or path_lower.ends_with(".pfm")
  254. ):
  255. font_file.load_dynamic_font(path)
  256. elif path_lower.ends_with(".fnt") or path_lower.ends_with(".font"):
  257. font_file.load_bitmap_font(path)
  258. else:
  259. push_error("Invalid font file format.")
  260. if not font_file.data.is_empty():
  261. # If font was loaded successfully, add it as a theme override.
  262. $Label.add_theme_font_override("font", font_file)
  263. .. code-tab:: csharp
  264. string path = "/Path/To/Font.ttf";
  265. var fontFile = new FontFile();
  266. if (
  267. path.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase)
  268. || path.EndsWith(".otf", StringComparison.OrdinalIgnoreCase)
  269. || path.EndsWith(".woff", StringComparison.OrdinalIgnoreCase)
  270. || path.EndsWith(".woff2", StringComparison.OrdinalIgnoreCase)
  271. || path.EndsWith(".pfb", StringComparison.OrdinalIgnoreCase)
  272. || path.EndsWith(".pfm", StringComparison.OrdinalIgnoreCase)
  273. )
  274. {
  275. fontFile.LoadDynamicFont(path);
  276. }
  277. else if (path.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".font", StringComparison.OrdinalIgnoreCase))
  278. {
  279. fontFile.LoadBitmapFont(path);
  280. }
  281. else
  282. {
  283. GD.PrintErr("Invalid font file format.");
  284. }
  285. if (!fontFile.Data.IsEmpty())
  286. {
  287. // If font was loaded successfully, add it as a theme override.
  288. GetNode<Label>("Label").AddThemeFontOverride("font", fontFile);
  289. }
  290. ZIP archives
  291. ------------
  292. Godot supports reading and writing ZIP archives using the :ref:`class_zipreader`
  293. and :ref:`class_zippacker` classes. This supports any ZIP file, including files
  294. generated by Godot's "Export PCK/ZIP" functionality (although these will contain
  295. imported Godot resources rather than the original project files).
  296. .. note::
  297. Use :ref:`ProjectSettings.load_resource_pack <class_ProjectSettings_method_load_resource_pack>`
  298. to load PCK or ZIP files exported by Godot as
  299. :ref:`additional data packs <doc_exporting_pcks>`. That approach is preferred
  300. for DLCs, as it makes interacting with additional data packs seamless (virtual filesystem).
  301. This ZIP archive support can be combined with runtime image, 3D scene and audio
  302. loading to provide a seamless modding experience without requiring users to go
  303. through the Godot editor to generate PCK/ZIP files.
  304. Example that lists files in a ZIP archive in an :ref:`class_ItemList` node,
  305. then writes contents read from it to a new ZIP archive (essentially duplicating the archive):
  306. .. tabs::
  307. .. code-tab:: gdscript
  308. # Load an existing ZIP archive.
  309. var zip_reader = ZIPReader.new()
  310. zip_reader.open(path)
  311. var files = zip_reader.get_files()
  312. # The list of files isn't sorted by default. Sort it for more consistent processing.
  313. files.sort()
  314. for file in files:
  315. $ItemList.add_item(file, null)
  316. # Make folders disabled in the list.
  317. $ItemList.set_item_disabled(-1, file.ends_with("/"))
  318. # Save a new ZIP archive.
  319. var zip_packer = ZIPPacker.new()
  320. var error = zip_packer.open(path)
  321. if error != OK:
  322. push_error("Couldn't open path for saving ZIP archive (error code: %s)." % error_string(error))
  323. return
  324. # Reuse the above ZIPReader instance to read files from an existing ZIP archive.
  325. for file in zip_reader.get_files():
  326. zip_packer.start_file(file)
  327. zip_packer.write_file(zip_reader.read_file(file))
  328. zip_packer.close_file()
  329. zip_packer.close()
  330. .. code-tab:: csharp
  331. // Load an existing ZIP archive.
  332. var zipReader = new ZipReader();
  333. zipReader.Open(path);
  334. string[] files = zipReader.GetFiles();
  335. // The list of files isn't sorted by default. Sort it for more consistent processing.
  336. Array.Sort(files);
  337. foreach (string file in files)
  338. {
  339. GetNode<ItemList>("ItemList").AddItem(file);
  340. // Make folders disabled in the list.
  341. GetNode<ItemList>("ItemList").SetItemDisabled(-1, file.EndsWith('/'));
  342. }
  343. // Save a new ZIP archive.
  344. var zipPacker = new ZipPacker();
  345. var error = zipPacker.Open(path);
  346. if (error != Error.Ok)
  347. {
  348. GD.PrintErr($"Couldn't open path for saving ZIP archive (error code: {error}).");
  349. return;
  350. }
  351. // Reuse the above ZIPReader instance to read files from an existing ZIP archive.
  352. foreach (string file in zipReader.GetFiles())
  353. {
  354. zipPacker.StartFile(file);
  355. zipPacker.WriteFile(zipReader.ReadFile(file));
  356. zipPacker.CloseFile();
  357. }
  358. zipPacker.Close();