123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- .. _doc_runtime_loading_and_saving:
- Runtime file loading and saving
- ===============================
- .. seealso::
- See :ref:`doc_saving_games` for information on saving and loading game progression.
- Sometimes, :ref:`exporting packs, patches, and mods <doc_exporting_pcks>` is not
- ideal when you want players to be able to load user-generated content in your
- project. It requires users to generate a PCK or ZIP file through the Godot
- editor, which contains resources imported by Godot.
- Example use cases for runtime file loading and saving include:
- - Loading texture packs designed for the game.
- - Loading user-provided audio tracks and playing them back in an in-game radio station.
- - Loading custom levels or 3D models that can be designed with any 3D DCC that
- can export to glTF (including glTF scenes saved by Godot at runtime).
- - Using user-provided fonts for menus and HUD.
- - Saving/loading a file format that can contain multiple files but can still
- easily be read by other applications (ZIP).
- - Loading files created by another game or program, or even game data files from
- another game not made with Godot.
- Runtime file loading can be combined with :ref:`HTTP requests <doc_http_request_class>`
- to load resources from the Internet directly.
- .. warning::
- Do **not** use this runtime loading approach to load resources that are part
- of the project, as it's less efficient and doesn't allow benefiting from
- Godot's resource handling functionality (such as translation remaps). See
- :ref:`doc_import_process` for details.
- .. seealso::
- You can see how saving and loading works in action using the
- `Run-time File Saving and Loading (Serialization) demo project <https://github.com/godotengine/godot-demo-projects/blob/master/loading/runtime_save_load>`__.
- Plain text and binary files
- ---------------------------
- Godot's :ref:`class_FileAccess` class provides methods to access files on the
- filesystem for reading and writing:
- .. tabs::
- .. code-tab:: gdscript
- func save_file(content):
- var file = FileAccess.open("/path/to/file.txt", FileAccess.WRITE)
- file.store_string(content)
- func load_file():
- var file = FileAccess.open("/path/to/file.txt", FileAccess.READ)
- var content = file.get_as_text()
- return content
- .. code-tab:: csharp
- private void SaveFile(string content)
- {
- using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Write);
- file.StoreString(content);
- }
- private string LoadFile()
- {
- using var file = FileAccess.Open("/Path/To/File.txt", FileAccess.ModeFlags.Read);
- string content = file.GetAsText();
- return content;
- }
- To handle custom binary formats (such as loading file formats not supported by
- Godot), :ref:`class_FileAccess` provides several methods to read/write integers,
- floats, strings and more. These FileAccess methods have names that start with
- ``get_`` and ``store_``.
- If you need more control over reading binary files or need to read binary
- streams that are not part of a file, :ref:`class_PackedByteArray` provides
- several helper methods to decode/encode series of bytes to integers, floats,
- strings and more. These PackedByteArray methods have names that start with
- ``decode_`` and ``encode_``. See also :ref:`doc_binary_serialization_api`.
- .. _doc_runtime_file_loading_and_saving_images:
- Images
- ------
- Image's :ref:`Image.load_from_file <class_Image_method_load_from_file>` static method
- handles everything, from format detection based on file extension to reading the
- file from disk.
- If you need error handling or more control (such as changing the scale an SVG is
- loaded at), use one of the following methods depending on the file format:
- - :ref:`Image.load_jpg_from_buffer <class_Image_method_load_jpg_from_buffer>`
- - :ref:`Image.load_ktx_from_buffer <class_Image_method_load_ktx_from_buffer>`
- - :ref:`Image.load_png_from_buffer <class_Image_method_load_png_from_buffer>`
- - :ref:`Image.load_svg_from_buffer <class_Image_method_load_svg_from_buffer>`
- or :ref:`Image.load_svg_from_string <class_Image_method_load_svg_from_string>`
- - :ref:`Image.load_tga_from_buffer <class_Image_method_load_tga_from_buffer>`
- - :ref:`Image.load_webp_from_buffer <class_Image_method_load_webp_from_buffer>`
- Several image formats can also be saved by Godot at runtime using the following
- methods:
- - :ref:`Image.save_png <class_Image_method_save_png>`
- or :ref:`Image.save_png_to_buffer <class_Image_method_save_png_to_buffer>`
- - :ref:`Image.save_webp <class_Image_method_save_webp>`
- or :ref:`Image.save_webp_to_buffer <class_Image_method_save_webp_to_buffer>`
- - :ref:`Image.save_jpg <class_Image_method_save_jpg>`
- or :ref:`Image.save_jpg_to_buffer <class_Image_method_save_jpg_to_buffer>`
- - :ref:`Image.save_exr <class_Image_method_save_exr>`
- or :ref:`Image.save_exr_to_buffer <class_Image_method_save_exr_to_buffer>`
- *(only available in editor builds, cannot be used in exported projects)*
- The methods with the ``to_buffer`` suffix save the image to a PackedByteArray
- instead of the filesystem. This is useful to send the image over the network or
- into a ZIP archive without having to write it on the filesystem. This can
- increase performance by reducing I/O utilization.
- .. note::
- If displaying the loaded image on a 3D surface, make sure to call
- :ref:`Image.generate_mipmaps <class_Image_method_generate_mipmaps>`
- so that the texture doesn't look grainy when viewed at a distance.
- This is also useful in 2D when following instructions on
- :ref:`reducing aliasing when downsampling <doc_multiple_resolutions_reducing_aliasing_on_downsampling>`.
- Example of loading an image and displaying it in a :ref:`class_TextureRect` node
- (which requires conversion to :ref:`class_ImageTexture`):
- .. tabs::
- .. code-tab:: gdscript
- # Load an image of any format supported by Godot from the filesystem.
- var image = Image.load_from_file(path)
- # Optionally, generate mipmaps if displaying the texture on a 3D surface
- # so that the texture doesn't look grainy when viewed at a distance.
- #image.generate_mipmaps()
- $TextureRect.texture = ImageTexture.create_from_image(image)
- # Save the loaded Image to a PNG image.
- image.save_png("/path/to/file.png")
- # Save the converted ImageTexture to a PNG image.
- $TextureRect.texture.get_image().save_png("/path/to/file.png")
- .. code-tab:: csharp
- // Load an image of any format supported by Godot from the filesystem.
- var image = Image.LoadFromFile(path);
- // Optionally, generate mipmaps if displaying the texture on a 3D surface
- // so that the texture doesn't look grainy when viewed at a distance.
- // image.GenerateMipmaps();
- GetNode<TextureRect>("TextureRect").Texture = ImageTexture.CreateFromImage(image);
- // Save the loaded Image to a PNG image.
- image.SavePng("/Path/To/File.png");
- // Save the converted ImageTexture to a PNG image.
- GetNode<TextureRect>("TextureRect").Texture.GetImage().SavePng("/Path/To/File.png");
- .. _doc_runtime_file_loading_and_saving_audio_video_files:
- Audio/video files
- -----------------
- Godot supports loading Ogg Vorbis audio at runtime. Note that not *all* files
- with an ``.ogg`` extension may be Ogg Vorbis files. Some may be Ogg Theora
- videos, or contain Opus audio within an Ogg container. These files will **not**
- load correctly as audio files in Godot.
- Example of loading an Ogg Vorbis audio file in an :ref:`class_AudioStreamPlayer` node:
- .. tabs::
- .. code-tab:: gdscript
- $AudioStreamPlayer.stream = AudioStreamOggVorbis.load_from_file(path)
- .. code-tab:: csharp
- GetNode<AudioStreamPlayer>("AudioStreamPlayer").Stream = AudioStreamOggVorbis.LoadFromFile(path);
- Example of loading an Ogg Theora video file in a :ref:`class_VideoStreamPlayer` node:
- .. tabs::
- .. code-tab:: gdscript
- var video_stream_theora = VideoStreamTheora.new()
- # File extension is ignored, so it is possible to load Ogg Theora videos
- # that have an `.ogg` extension this way.
- video_stream_theora.file = "/path/to/file.ogv"
- $VideoStreamPlayer.stream = video_stream_theora
- # VideoStreamPlayer's Autoplay property won't work if the stream is empty
- # before this property is set, so call `play()` after setting `stream`.
- $VideoStreamPlayer.play()
- .. code-tab:: csharp
- var videoStreamTheora = new VideoStreamTheora();
- // File extension is ignored, so it is possible to load Ogg Theora videos
- // that have an `.ogg` extension this way.
- videoStreamTheora.File = "/Path/To/File.ogv";
- GetNode<VideoStreamPlayer>("VideoStreamPlayer").Stream = videoStreamTheora;
- // VideoStreamPlayer's Autoplay property won't work if the stream is empty
- // before this property is set, so call `Play()` after setting `Stream`.
- GetNode<VideoStreamPlayer>("VideoStreamPlayer").Play();
- .. note::
- Godot doesn't support runtime loading of MP3 or WAV files yet. Until this is
- implemented, it's feasible to implement runtime WAV loading using a script
- since :ref:`class_AudioStreamWAV`'s ``data`` property is exposed to
- scripting.
- It's still possible to *save* WAV files using
- :ref:`AudioStreamWAV.save_to_wav <class_AudioStreamWAV_method_save_to_wav>`, which is useful
- for procedurally generated audio or microphone recordings.
- .. _doc_runtime_file_loading_and_saving_3d_scenes:
- 3D scenes
- ---------
- Godot has first-class support for glTF 2.0, both in the editor and exported
- projects. Using :ref:`class_gltfdocument` and :ref:`class_gltfstate` together,
- Godot can load and save glTF files in exported projects, in both text
- (``.gltf``) and binary (``.glb``) formats. The binary format should be preferred
- as it's faster to write and smaller, but the text format is easier to debug.
- Example of loading a glTF scene and appending its root node to the scene:
- .. tabs::
- .. code-tab:: gdscript
- # Load an existing glTF scene.
- # GLTFState is used by GLTFDocument to store the loaded scene's state.
- # GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
- # which means it supports glTF features such as lights and cameras.
- var gltf_document_load = GLTFDocument.new()
- var gltf_state_load = GLTFState.new()
- var error = gltf_document_load.append_from_file("/path/to/file.gltf", gltf_state_load)
- if error == OK:
- var gltf_scene_root_node = gltf_document_load.generate_scene(gltf_state_load)
- add_child(gltf_scene_root_node)
- else:
- show_error("Couldn't load glTF scene (error code: %s)." % error_string(error))
- # Save a new glTF scene.
- var gltf_document_save := GLTFDocument.new()
- var gltf_state_save := GLTFState.new()
- gltf_document_save.append_from_scene(gltf_scene_root_node, gltf_state_save)
- # The file extension in the output `path` (`.gltf` or `.glb`) determines
- # whether the output uses text or binary format.
- # `GLTFDocument.generate_buffer()` is also available for saving to memory.
- gltf_document_save.write_to_filesystem(gltf_state_save, path)
- .. code-tab:: csharp
- // Load an existing glTF scene.
- // GLTFState is used by GLTFDocument to store the loaded scene's state.
- // GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
- // which means it supports glTF features such as lights and cameras.
- var gltfDocumentLoad = new GltfDocument();
- var gltfStateLoad = new GltfState();
- var error = gltfDocumentLoad.AppendFromFile("/Path/To/File.gltf", gltfStateLoad);
- if (error == Error.Ok)
- {
- var gltfSceneRootNode = gltfDocumentLoad.GenerateScene(gltfStateLoad);
- AddChild(gltfSceneRootNode);
- }
- else
- {
- GD.PrintErr($"Couldn't load glTF scene (error code: {error}).");
- }
- // Save a new glTF scene.
- var gltfDocumentSave = new GltfDocument();
- var gltfStateSave = new GltfState();
- gltfDocumentSave.AppendFromScene(gltfSceneRootNode, gltfStateSave);
- // The file extension in the output `path` (`.gltf` or `.glb`) determines
- // whether the output uses text or binary format.
- // `GltfDocument.GenerateBuffer()` is also available for saving to memory.
- gltfDocumentSave.WriteToFilesystem(gltfStateSave, path);
- .. note::
- When loading a glTF scene, a *base path* must be set so that external
- resources like textures can be loaded correctly. When loading from a file,
- the base path is automatically set to the folder containing the file. When
- loading from a buffer, this base path must be manually set as there is no
- way for Godot to infer this path.
- To set the base path, set
- :ref:`GLTFState.base_path <class_GLTFState_property_base_path>` on your
- GLTFState instance *before* calling
- :ref:`GLTFDocument.append_from_buffer <class_GLTFDocument_method_append_from_buffer>`
- or :ref:`GLTFDocument.append_from_file <class_GLTFDocument_method_append_from_file>`.
- .. _doc_runtime_file_loading_and_saving_fonts:
- Fonts
- -----
- :ref:`FontFile.load_dynamic_font <class_FontFile_method_load_bitmap_font>` supports the following
- font file formats: TTF, OTF, WOFF, WOFF2, PFB, PFM
- On the other hand, :ref:`FontFile.load_bitmap_font <class_FontFile_method_load_bitmap_font>` supports
- the `BMFont <https://www.angelcode.com/products/bmfont/>`__ format (``.fnt`` or ``.font``).
- Additionally, it is possible to load any font that is installed on the system using
- Godot's support for :ref:`doc_using_fonts_system_fonts`.
- Example of loading a font file automatically according to its file extension,
- then adding it as a theme override to a :ref:`class_Label` node:
- .. tabs::
- .. code-tab:: gdscript
- var path = "/path/to/font.ttf"
- var path_lower = path.to_lower()
- var font_file = FontFile.new()
- if (
- path_lower.ends_with(".ttf")
- or path_lower.ends_with(".otf")
- or path_lower.ends_with(".woff")
- or path_lower.ends_with(".woff2")
- or path_lower.ends_with(".pfb")
- or path_lower.ends_with(".pfm")
- ):
- font_file.load_dynamic_font(path)
- elif path_lower.ends_with(".fnt") or path_lower.ends_with(".font"):
- font_file.load_bitmap_font(path)
- else:
- push_error("Invalid font file format.")
- if not font_file.data.is_empty():
- # If font was loaded successfully, add it as a theme override.
- $Label.add_theme_font_override("font", font_file)
- .. code-tab:: csharp
- string path = "/Path/To/Font.ttf";
- var fontFile = new FontFile();
- if (
- path.EndsWith(".ttf", StringComparison.OrdinalIgnoreCase)
- || path.EndsWith(".otf", StringComparison.OrdinalIgnoreCase)
- || path.EndsWith(".woff", StringComparison.OrdinalIgnoreCase)
- || path.EndsWith(".woff2", StringComparison.OrdinalIgnoreCase)
- || path.EndsWith(".pfb", StringComparison.OrdinalIgnoreCase)
- || path.EndsWith(".pfm", StringComparison.OrdinalIgnoreCase)
- )
- {
- fontFile.LoadDynamicFont(path);
- }
- else if (path.EndsWith(".fnt", StringComparison.OrdinalIgnoreCase) || path.EndsWith(".font", StringComparison.OrdinalIgnoreCase))
- {
- fontFile.LoadBitmapFont(path);
- }
- else
- {
- GD.PrintErr("Invalid font file format.");
- }
- if (!fontFile.Data.IsEmpty())
- {
- // If font was loaded successfully, add it as a theme override.
- GetNode<Label>("Label").AddThemeFontOverride("font", fontFile);
- }
- ZIP archives
- ------------
- Godot supports reading and writing ZIP archives using the :ref:`class_zipreader`
- and :ref:`class_zippacker` classes. This supports any ZIP file, including files
- generated by Godot's "Export PCK/ZIP" functionality (although these will contain
- imported Godot resources rather than the original project files).
- .. note::
- Use :ref:`ProjectSettings.load_resource_pack <class_ProjectSettings_method_load_resource_pack>`
- to load PCK or ZIP files exported by Godot as
- :ref:`additional data packs <doc_exporting_pcks>`. That approach is preferred
- for DLCs, as it makes interacting with additional data packs seamless (virtual filesystem).
- This ZIP archive support can be combined with runtime image, 3D scene and audio
- loading to provide a seamless modding experience without requiring users to go
- through the Godot editor to generate PCK/ZIP files.
- Example that lists files in a ZIP archive in an :ref:`class_ItemList` node,
- then writes contents read from it to a new ZIP archive (essentially duplicating the archive):
- .. tabs::
- .. code-tab:: gdscript
- # Load an existing ZIP archive.
- var zip_reader = ZIPReader.new()
- zip_reader.open(path)
- var files = zip_reader.get_files()
- # The list of files isn't sorted by default. Sort it for more consistent processing.
- files.sort()
- for file in files:
- $ItemList.add_item(file, null)
- # Make folders disabled in the list.
- $ItemList.set_item_disabled(-1, file.ends_with("/"))
- # Save a new ZIP archive.
- var zip_packer = ZIPPacker.new()
- var error = zip_packer.open(path)
- if error != OK:
- push_error("Couldn't open path for saving ZIP archive (error code: %s)." % error_string(error))
- return
- # Reuse the above ZIPReader instance to read files from an existing ZIP archive.
- for file in zip_reader.get_files():
- zip_packer.start_file(file)
- zip_packer.write_file(zip_reader.read_file(file))
- zip_packer.close_file()
- zip_packer.close()
- .. code-tab:: csharp
- // Load an existing ZIP archive.
- var zipReader = new ZipReader();
- zipReader.Open(path);
- string[] files = zipReader.GetFiles();
- // The list of files isn't sorted by default. Sort it for more consistent processing.
- Array.Sort(files);
- foreach (string file in files)
- {
- GetNode<ItemList>("ItemList").AddItem(file);
- // Make folders disabled in the list.
- GetNode<ItemList>("ItemList").SetItemDisabled(-1, file.EndsWith('/'));
- }
- // Save a new ZIP archive.
- var zipPacker = new ZipPacker();
- var error = zipPacker.Open(path);
- if (error != Error.Ok)
- {
- GD.PrintErr($"Couldn't open path for saving ZIP archive (error code: {error}).");
- return;
- }
- // Reuse the above ZIPReader instance to read files from an existing ZIP archive.
- foreach (string file in zipReader.GetFiles())
- {
- zipPacker.StartFile(file);
- zipPacker.WriteFile(zipReader.ReadFile(file));
- zipPacker.CloseFile();
- }
- zipPacker.Close();
|