Skip to content

Commit c712afa

Browse files
authored
Merge pull request godotengine#8363 from Calinou/add-runtime-file-loading-saving
Add a page on runtime file loading and saving
2 parents acb8eda + 3ebfc56 commit c712afa

File tree

4 files changed

+289
-2
lines changed

4 files changed

+289
-2
lines changed

about/list_of_features.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,8 @@ File formats
724724
- Can (de)serialize any Godot datatype, including Vector2/3, Color, ...
725725

726726
- Read XML files using :ref:`class_XMLParser`.
727-
- Read and write ZIP files using :ref:`class_ZIPReader` and :ref:`class_ZIPPacker`.
727+
- :ref:`Load and save images, audio/video, fonts and ZIP archives <doc_runtime_loading_and_saving>`
728+
in an exported project without having to go through Godot's import system.
728729
- Pack game data into a PCK file (custom format optimized for fast seeking),
729730
into a ZIP archive, or directly into the executable for single-file distribution.
730731
- :ref:`Export additional PCK files<doc_exporting_pcks>` that can be read

tutorials/io/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ File and data I/O
88
background_loading
99
data_paths
1010
saving_games
11+
runtime_file_loading_and_saving
1112
binary_serialization_api
Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,280 @@
1+
.. _doc_runtime_loading_and_saving:
2+
3+
Runtime file loading and saving
4+
===============================
5+
6+
.. seealso::
7+
8+
See :ref:`doc_saving_games` for information on saving and loading game progression.
9+
10+
Sometimes, :ref:`doc_exporting_pcks` is not ideal when you want players to be
11+
able to load user-generated content in your project. It requires users to
12+
generate a PCK or ZIP file through the Godot editor, which contains resources
13+
imported by Godot.
14+
15+
Example use cases for runtime file loading and saving include:
16+
17+
- Loading texture packs designed for the game.
18+
- Loading user-provided audio tracks and playing them back in an in-game radio station.
19+
- Loading custom levels or 3D models that can be designed with any 3D DCC that
20+
can export to glTF (including glTF scenes saved by Godot at runtime).
21+
- Using user-provided fonts for menus and HUD.
22+
- Saving/loading a file format that can contain multiple files but can still
23+
easily be read by other applications (ZIP).
24+
- Loading files created by another game or program, or even game data files from
25+
another game not made with Godot.
26+
27+
.. warning::
28+
29+
Do **not** use this runtime loading approach to load resources that are part
30+
of the project, as it's less efficient and doesn't allow benefiting from
31+
Godot's resource handling functionality (such as translation remaps). See
32+
:ref:`doc_import_process` for details.
33+
34+
.. seealso::
35+
36+
You can see how saving and loading works in action using the
37+
`Run-time File Saving and Loading (Serialization) demo project <https://github.com/godotengine/godot-demo-projects/blob/master/loading/runtime_save_load>`__.
38+
39+
Plain text and binary files
40+
---------------------------
41+
42+
Godot's :ref:`class_FileAccess` class provides methods to access files on the
43+
filesystem for reading and writing:
44+
45+
::
46+
47+
func save_file(content):
48+
var file = FileAccess.open("/path/to/file.txt", FileAccess.WRITE)
49+
file.store_string(content)
50+
51+
func load_file():
52+
var file = FileAccess.open("/path/to/file.txt", FileAccess.READ)
53+
var content = file.get_as_text()
54+
return content
55+
56+
To handle custom binary formats (such as loading file formats not supported by
57+
Godot), :ref:`class_FileAccess` provides several methods to read/write integers,
58+
floats, strings and more. These FileAccess methods have names that start with
59+
``get_`` and ``store_``.
60+
61+
If you need more control over reading binary files or need to read binary
62+
streams that are not part of a file, :ref:`class_PackedByteArray` provides
63+
several helper methods to decode/encode series of bytes to integers, floats,
64+
strings and more. These PackedByteArray methods have names that start with
65+
``decode_`` and ``encode_``. See also :ref:`doc_binary_serialization_api`.
66+
67+
Images
68+
------
69+
70+
Image's :ref:`load_from_file<class_Image_method_load_from_file>` static method
71+
handles everything, from format detection based on file extension to reading the
72+
file from disk.
73+
74+
If you need error handling or more control (such as changing the scale a SVG is
75+
loaded at), use one of the following methods depending on the file format:
76+
77+
- :ref:`load_jpg_from_buffer<class_Image_method_load_jpg_from_buffer>`
78+
- :ref:`load_ktx_from_buffer<class_Image_method_load_ktx_from_buffer>`
79+
- :ref:`load_png_from_buffer<class_Image_method_load_png_from_buffer>`
80+
- :ref:`load_svg_from_buffer<class_Image_method_load_svg_from_buffer>`
81+
or :ref:`load_svg_from_string<class_Image_method_load_svg_from_string>`
82+
- :ref:`load_tga_from_buffer<class_Image_method_load_tga_from_buffer>`
83+
- :ref:`load_webp_from_buffer<class_Image_method_load_webp_from_buffer>`
84+
85+
Several image formats can also be saved by Godot at runtime using the following
86+
methods:
87+
88+
- :ref:`save_png<class_Image_method_save_png>`
89+
or :ref:`save_png_to_buffer<class_Image_method_save_png_to_buffer>`
90+
- :ref:`save_webp<class_Image_method_save_webp>`
91+
or :ref:`save_webp_to_buffer<class_Image_method_save_webp_to_buffer>`
92+
- :ref:`save_jpg<class_Image_method_save_jpg>`
93+
or :ref:`save_jpg_to_buffer<class_Image_method_save_jpg_to_buffer>`
94+
- :ref:`save_exr<class_Image_method_save_exr>`
95+
or :ref:`save_exr_to_buffer<class_Image_method_save_exr_to_buffer>`
96+
*(only available in editor builds, cannot be used in exported projects)*
97+
98+
The methods with the ``to_buffer`` suffix save the image to a PackedByteArray
99+
instead of the filesystem. This is useful to send the image over the network or
100+
into a ZIP archive without having to write it on the filesystem. This can
101+
increase performance by reducing I/O utilization.
102+
103+
Example of loading an image and displaying it in a :ref:`class_TextureRect` node
104+
(which requires conversion to :ref:`class_ImageTexture`):
105+
106+
::
107+
108+
# Load an image of any format supported by Godot from the filesystem.
109+
var image = Image.load_from_file(path)
110+
$TextureRect.texture = ImageTexture.create_from_image(image)
111+
112+
# Save the loaded Image to a PNG image.
113+
image.save_png("/path/to/file.png")
114+
115+
# Save the converted ImageTexture to a PNG image.
116+
$TextureRect.texture.get_image().save_png("/path/to/file.png")
117+
118+
Audio/video files
119+
-----------------
120+
121+
Godot supports loading Ogg Vorbis audio at runtime. Note that not *all* files
122+
with an ``.ogg`` extension may be Ogg Vorbis files. Some may be Ogg Theora
123+
videos, or contain Opus audio within an Ogg container. These files will **not**
124+
load correctly as audio files in Godot.
125+
126+
Example of loading an Ogg Vorbis audio file in an :ref:`class_AudioStreamPlayer` node:
127+
128+
::
129+
130+
$AudioStreamPlayer.stream = AudioStreamOggVorbis.load_from_file(path)
131+
132+
Example of loading an Ogg Theora video file in a :ref:`class_VideoStreamPlayer` node:
133+
134+
::
135+
136+
var video_stream_theora = VideoStreamTheora.new()
137+
# File extension is ignored, so it is possible to load Ogg Theora videos
138+
# that have an `.ogg` extension this way.
139+
video_stream_theora.file = "/path/to/file.ogv"
140+
$VideoStreamPlayer.stream = video_stream_theora
141+
142+
# VideoStreamPlayer's Autoplay property won't work if the stream is empty
143+
# before this property is set, so call `play()` after setting `stream`.
144+
$VideoStreamPlayer.play()
145+
146+
.. note::
147+
148+
Godot doesn't support runtime loading of MP3 or WAV files yet. Until this is
149+
implemented, it's feasible to implement runtime WAV loading using a script
150+
since :ref:`class_AudioStreamWAV`'s ``data`` property is exposed to
151+
scripting.
152+
153+
It's still possible to *save* WAV files using
154+
:ref:`save_to_wav<class_AudioStreamWAV_method_save_to_wav>`, which is useful
155+
for procedurally generated audio or microphone recordings.
156+
157+
3D scenes
158+
---------
159+
160+
Godot has first-class support for glTF 2.0, both in the editor and exported
161+
projects. Using :ref:`class_gltfdocument` and :ref:`class_gltfstate` together,
162+
Godot can load and save glTF files in exported projects, in both text
163+
(``.gltf``) and binary (``.glb``) formats. The binary format should be preferred
164+
as it's faster to write and smaller, but the text format is easier to debug.
165+
166+
Example of loading a glTF scene and appending its root node to the scene:
167+
168+
::
169+
170+
# Load an existing glTF scene.
171+
# GLTFState is used by GLTFDocument to store the loaded scene's state.
172+
# GLTFDocument is the class that handles actually loading glTF data into a Godot node tree,
173+
# which means it supports glTF features such as lights and cameras.
174+
var gltf_document_load = GLTFDocument.new()
175+
var gltf_state_load = GLTFState.new()
176+
var error = gltf_document_load.append_from_file("/path/to/file.gltf", gltf_state_load)
177+
if error == OK:
178+
var gltf_scene_root_node = gltf_document_load.generate_scene(gltf_state_load)
179+
add_child(gltf_scene_root_node)
180+
else:
181+
show_error("Couldn't load glTF scene (error code: %s)." % error_string(error))
182+
183+
# Save a new glTF scene.
184+
var gltf_document_save := GLTFDocument.new()
185+
var gltf_state_save := GLTFState.new()
186+
gltf_document_save.append_from_scene(gltf_scene_root_node, gltf_state_save)
187+
# The file extension in the output `path` (`.gltf` or `.glb`) determines
188+
# whether the output uses text or binary format.
189+
# `GLTFDocument.generate_buffer()` is also available for saving to memory.
190+
gltf_document_save.write_to_filesystem(gltf_state_save, path)
191+
192+
.. _doc_runtime_file_loading_and_saving_fonts:
193+
194+
Fonts
195+
-----
196+
197+
:ref:`load_dynamic_font<class_FontFile_method_load_bitmap_font>` supports the following
198+
font file formats: TTF, OTF, WOFF, WOFF2, PFB, PFM
199+
200+
On the other hand, :ref:`load_bitmap_font<class_FontFile_method_load_bitmap_font>` supports
201+
the `BMFont <https://www.angelcode.com/products/bmfont/>`__ format (``.fnt`` or ``.font``).
202+
203+
Additionally, it is possible to load any font that is installed on the system using
204+
Godot's support for :ref:`doc_using_fonts_system_fonts`.
205+
206+
Example of loading a font file automatically according to its file extension,
207+
then adding it as a theme override to a :ref:`class_Label` node:
208+
209+
::
210+
211+
var path = "/path/to/font.ttf"
212+
var path_lower = path.to_lower()
213+
var font_file = FontFile.new()
214+
if (
215+
path_lower.ends_with(".ttf")
216+
or path_lower.ends_with(".otf")
217+
or path_lower.ends_with(".woff")
218+
or path_lower.ends_with(".woff2")
219+
or path_lower.ends_with(".pfb")
220+
or path_lower.ends_with(".pfm")
221+
):
222+
font_file.load_dynamic_font(path)
223+
elif path_lower.ends_with(".fnt") or path_lower.ends_with(".font"):
224+
font_file.load_bitmap_font(path)
225+
else:
226+
push_error("Invalid font file format.")
227+
228+
if not font_file.data.is_empty():
229+
# If font was loaded successfully, add it as a theme override.
230+
$Label.add_theme_font_override("font", font_file)
231+
232+
ZIP archives
233+
------------
234+
235+
Godot supports reading and writing ZIP archives using the :ref:`class_zipreader`
236+
and :ref:`class_zippacker` classes. This supports any ZIP file, including files
237+
generated by Godot's "Export PCK/ZIP" functionality (although these will contain
238+
imported Godot resources rather than the original project files).
239+
240+
.. note::
241+
242+
Use :ref:`load_resource_pack<class_ProjectSettings_method_load_resource_pack>`
243+
to load PCK or ZIP files exported by Godot as
244+
:ref:`additional data packs <doc_exporting_pcks>`. That approach is preferred
245+
for DLCs, as it makes interacting with additional data packs seamless (virtual filesystem).
246+
247+
This ZIP archive support can be combined with runtime image, 3D scene and audio
248+
loading to provide a seamless modding experience without requiring users to go
249+
through the Godot editor to generate PCK/ZIP files.
250+
251+
Example that lists files in a ZIP archive in an :ref:`class_ItemList` node,
252+
then writes contents read from it to a new ZIP archive (essentially duplicating the archive):
253+
254+
::
255+
256+
# Load an existing ZIP archive.
257+
var zip_reader = ZIPReader.new()
258+
zip_reader.open(path)
259+
var files = zip_reader.get_files()
260+
# The list of files isn't sorted by default. Sort it for more consistent processing.
261+
files.sort()
262+
for file in files:
263+
$ItemList.add_item(file, null)
264+
# Make folders disabled in the list.
265+
$ItemList.set_item_disabled(-1, file.ends_with("/"))
266+
267+
# Save a new ZIP archive.
268+
var zip_packer = ZIPPacker.new()
269+
var error = zip_packer.open(path)
270+
if error != OK:
271+
push_error("Couldn't open path for saving ZIP archive (error code: %s)." % error_string(error))
272+
return
273+
274+
# Reuse the above ZIPReader instance to read files from an existing ZIP archive.
275+
for file in zip_reader.get_files():
276+
zip_packer.start_file(file)
277+
zip_packer.write_file(zip_reader.read_file(file))
278+
zip_packer.close_file()
279+
280+
zip_packer.close()

tutorials/ui/gui_using_fonts.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,8 @@ possible to display CJK characters and emoji without having to load a custom
665665
font. There are some restrictions that apply though, as mentioned in the
666666
:ref:`Using emoji <doc_using_fonts_emoji>` section.
667667

668-
Create a SystemFont resource in the location where you desire to use the system font:
668+
Create a :ref:`class_SystemFont` resource in the location where you desire to
669+
use the system font:
669670

670671
.. figure:: img/using_fonts_system_font_create.webp
671672
:align: center
@@ -720,6 +721,10 @@ that labels can extend further if needed.
720721
distributions, different fonts may be displayed for a given system font name
721722
or alias.
722723

724+
It is also possible to load fonts at runtime even if they aren't installed on the system.
725+
See :ref:`Runtime loading and saving <doc_runtime_file_loading_and_saving_fonts>`
726+
for details.
727+
723728
.. _doc_using_fonts_font_prerendering:
724729

725730
Font prerendering

0 commit comments

Comments
 (0)