Dynamically finding and loading resources from the Filesystem for Android and Web Exports
A little while ago, I created a type of AudioManager to make it easier to work with sound files in bulk: Rather than assigning audio streams by hand, I was doing it programmatically; reading the contents of a directory and using
load()
to get the resources. It worked great and saved a lot of time over just assigning hundreds of sound resources by hand. And while this worked during development and for Windows exports, it failed on Android and Web exports.
Godot Engine 4 will, at export time, shuffle around and remap some of these resources. So if you are reading directly from the directory where you’re expecting a file to exist, it may be there after the project was exported. Instead, you might find the same file with a “.remap” suffix. Just strip off that “.remap” suffix and instead of using
load()
directly, use
ResourceLoader.load()
, which understands the resource mapping and will be able to retrieve the proper resource for you.
The reason is that some platforms require assets to be bundled in specific ways or stored in specific locations. The original asset has been moved, but Godot will instead have the same filename with an added “.remap” suffix to indicate that.
If you need to load something dynamically, use the ResourceLoader, and if you’re trying to discover content, scan the directory, and strip off the .remap suffix.
As long as you’re aware of this pitfall, you should be able to dynamically handle resources in your Godot game.
I’ve abstracted this into a general resource-aware file finder:
class_nameGGResourceFinderextends RefCounted## Iterates over files in a directory## making it easy to load contents from disk at run-time.#### This finder helps find resources that are remapped for Android## and Web exportsstaticfuncfind(directory:String,suffix:String) -> Array[String]:var files:Array[String] =_dir_contents(directory, suffix) files.sort()return files## Recursively find files from a directorystaticfunc_dir_contents(path,suffix) -> Array[String]:var dir =DirAccess.open(path)if !dir:print("GGResourceFinder: An error occurred when trying to access path: %s" % [path])return []var files:Array[String] dir.list_dir_begin()var file_name = dir.get_next()while file_name !="": file_name = file_name.replace('.remap','')if dir.current_is_dir(): files.append_array(_dir_contents("%s/%s" % [path, file_name], suffix))elif file_name.ends_with(suffix): files.append("%s/%s" % [path, file_name]) file_name = dir.get_next()return files
This script can then be used to find scenes from a particular directory. This may be relevant if you’re looking to support mods or DLCs in your Godot game since the game will have to have some kind of way to discover and load the new content.
func_ready() -> void:_load_content_scenes()func_load_content_scenes():if content_directory.is_empty(): returnvar files = GGResourceFinder.find(content_directory,".tscn")for filename in files:var scene =ResourceLoader.load(filename)if scene isPackedScene: content_scenes.append(scene)func_find_audio_theme_files(): _audio_files = GGResourceFinder.find(audio_directory,".tres") _audio_files.sort()
Anyway, path remapping is something to be aware of. I feel like that’s one of those things that’ll sneak up on you. Everything works great up until exporting, then suddenly everything’s broken for trying to be too data-driven. Some additional reading:
Hugo-Dz created Super Godot Galaxy: https://github.com/Hugo-Dz/super-godot-galaxy, which he announced in this Reddit post. It uses the 3D Starter Kit from Kenney and shows how to achieve the effect of applying gravity toward the center of a small spherical planet.
A new version of the Inventory System is available with more multiplayer-related features. The Multiplayer Interaction Demo can now run in multiple modes, through two separate implementations of the Character scene: The simple character scene leverages the MultiplayerSynchronizer and can either let the client have authority and move the character, or have the client send …
Dynamically finding and loading resources from the Filesystem for Android and Web Exports
A little while ago, I created a type of AudioManager to make it easier to work with sound files in bulk: Rather than assigning audio streams by hand, I was doing it programmatically; reading the contents of a directory and using
load()
to get the resources. It worked great and saved a lot of time over just assigning hundreds of sound resources by hand. And while this worked during development and for Windows exports, it failed on Android and Web exports.Godot Engine 4 will, at export time, shuffle around and remap some of these resources. So if you are reading directly from the directory where you’re expecting a file to exist, it may be there after the project was exported. Instead, you might find the same file with a “.remap” suffix. Just strip off that “.remap” suffix and instead of using
load()
directly, useResourceLoader.load()
, which understands the resource mapping and will be able to retrieve the proper resource for you.The reason is that some platforms require assets to be bundled in specific ways or stored in specific locations. The original asset has been moved, but Godot will instead have the same filename with an added “.remap” suffix to indicate that.
If you need to load something dynamically, use the ResourceLoader, and if you’re trying to discover content, scan the directory, and strip off the .remap suffix.
As long as you’re aware of this pitfall, you should be able to dynamically handle resources in your Godot game.
I’ve abstracted this into a general resource-aware file finder:
This script can then be used to find scenes from a particular directory. This may be relevant if you’re looking to support mods or DLCs in your Godot game since the game will have to have some kind of way to discover and load the new content.
Anyway, path remapping is something to be aware of. I feel like that’s one of those things that’ll sneak up on you. Everything works great up until exporting, then suddenly everything’s broken for trying to be too data-driven. Some additional reading:
Related Posts
Super Godot Galaxy Concept
Hugo-Dz created Super Godot Galaxy: https://github.com/Hugo-Dz/super-godot-galaxy, which he announced in this Reddit post. It uses the 3D Starter Kit from Kenney and shows how to achieve the effect of applying gravity toward the center of a small spherical planet.
Inventory System v1.2 available
A few new features: Bug fixes:
Inventory System v1.8.1 available
A quick update to yesterday’s release with a few fixes:
Inventory System v1.14 available
A new version of the Inventory System is available with more multiplayer-related features. The Multiplayer Interaction Demo can now run in multiple modes, through two separate implementations of the Character scene: The simple character scene leverages the MultiplayerSynchronizer and can either let the client have authority and move the character, or have the client send …