Res:// in the browser!

Godot Version

Godot 4.3

Question

Hello everyone!

I’m developing a 2D web browser game on Godot and ran into a problem where the skins in the store are not showing up. The problem seems to be that I’m using the path “res://Resource/skins/”, but I know that (res://) doesn’t work in the browser version.

What can be used instead of it for the correct loading of resources? Any help would be appreciated!

I also add the complete code that I use to upload skins to the store:

func load_skins():
	var skins_path = "res://Resource/skins/"
	var dir = DirAccess.open(skins_path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			if file_name.ends_with(".tres"):
				var skin_name = file_name.get_basename()
				skins[skin_name] = skins_path + file_name
			file_name = dir.get_next()
		dir.list_dir_end()
	print("Skins: ", skins)

        #A function that displays skins
	load_skins_ui()

Does this work exported to a desktop platform? I think not, when exported most resources take on a .remap suffix, but you still have to load the .tres path, it’s a big mess as of right now; you might be able to modify your code like so to support .remap files

if file_name.ends_with(".tres") or file_name.ends_with(".tres.remap"):
	var skin_name = file_name.get_basename()

At the end of that discussion this pull request is slated for 4.4, that offers a new function in ResourceLoader to help this situation.

1 Like

You might find this discussion helpful (I’m not sure; I don’t have a direct answer to your question). I didn’t think file access issues were different in web exports vs other exports, but I don’t know for sure.

https://www.reddit.com/r/godot/comments/13u9w0j/loading_resources_in_exported_projects/

1 Like

The browser gives the following error:

bunnyjump.js:474 You skins: 
onPrintError @ bunnyjump.js:474
put_char @ bunnyjump.js:9
write @ bunnyjump.js:9
write @ bunnyjump.js:9
doWritev @ bunnyjump.js:9
_fd_write @ bunnyjump.js:9
$func24155 @ 0a418b96:0x19ad861
$func9000 @ 0a418b96:0x73a546
$func6058 @ 0a418b96:0x49086c
$func32189 @ 0a418b96:0x1b3d7bb
$func32188 @ 0a418b96:0x1b3d75a
$func12829 @ 0a418b96:0x9e550b
$func741 @ 0a418b96:0x86ef1
$func9312 @ 0a418b96:0x76238e
$func25967 @ 0a418b96:0x1a2b5f7
$func4908 @ 0a418b96:0x3a6a23
$func1600 @ 0a418b96:0x16220d
$func46119 @ 0a418b96:0x21b67c4
$func7607 @ 0a418b96:0x5ced0a
$func863 @ 0a418b96:0x9a0b8
$func19980 @ 0a418b96:0x108bf71
$func57811 @ 0a418b96:0x23de4ec
$func19894 @ 0a418b96:0x1080aa7
$func57672 @ 0a418b96:0x23d7355
$func383 @ 0a418b96:0x481cf
$func19960 @ 0a418b96:0x1088756
$func19964 @ 0a418b96:0x1088fb8
$func57775 @ 0a418b96:0x23dc576
$func14345 @ 0a418b96:0xabd18d
callUserCallback @ bunnyjump.js:9
runIter @ bunnyjump.js:9
Browser_mainLoop_runner @ bunnyjump.js:9

For some reason DirAccess does not work, cannot open the file.

For web exports, you should use relative paths.

var skins_path = "skins/"

If these are skins that need to be saved/loaded during runtime:

var skins_path = "user://skins/"

(I might be misunderstanding the issue, But this seems to be your problem?)

(Also sorry gert for sniping your threads lol)

(Ah nevermind, I see where you literally said you know this would work lol. Im gonna leave this comment up for posterity for other web users but just know im dumb.)

1 Like

print error? I’m not sure exactly how to decipher that message. Seems like it does print an empty skins or fails to serialize the dictionary.

If it really cannot open the file you would add else statements to better understand the control flow

func load_skins():
	var skins_path = "res://Resource/skins/"
	var dir = DirAccess.open(skins_path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			if file_name.ends_with(".tres") or file_name.ends_with(".tres.remap"):
				var skin_name = file_name.get_basename()
				skins[skin_name] = skins_path + file_name
			else:
				##
				print("Found file with invalid extension ", file_name)
			file_name = dir.get_next()
		dir.list_dir_end()
	else:
		##
		print("Failed to open dir ", skins_path)

	print("Skins: ", skins)

        #A function that displays skins
	load_skins_ui()
1 Like

Now I don’t understand anything at all(

The same problem, an error at 100 lines of code (

It looks like you’re trying to use a previously loaded skin (which is a file) as if it were a directory? This is a different problem than just the res:// path issue.

Yeah that seems confusing! Make sure you are rebuilding the game for web when testing, gotta have a clean slate. The first line, "Not directory: { "black": "res://Resource/skins/black.tres" }" is there any other DirAccess being opened? On a dictionary too?

Test it in a desktop export first, I do not think it’s a Web export specific issue, though web exports do have their own unique problems like these print errors. It should be easier to debug if there is an issue through a desktop export.

1 Like

Try this. I really gotta stop opening this website at 4 am 3 hours before work and doing more in 30 mins then I do in 3 days of coding at my real job lol.

extends Node

var skins = {}
var current_skin = null
var skin_container = null

func _ready():
	create_skin_ui()
	load_skins()

func load_skins():
	# Clear the skins dictionary first to avoid contamination
	skins.clear()
	
	if OS.has_feature("web"):
		var skin_files = ["black.tres", "blue.tres", "red.tres", "green.tres"] 
		
		print("Web export detected. Using explicit skin list.")
		for file in skin_files:
			var skin_path = "res://Resource/skins/" + file
			var skin_name = file.get_basename()
			var skin_resource = load(skin_path)
			if skin_resource:
				skins[skin_name] = skin_resource
				print("Loaded skin: ", skin_name)
			else:
				print("Failed to load skin: ", skin_path)
	else:
		var skins_path = "res://Resource/skins/"
		print("Desktop/mobile export. Scanning directory: ", skins_path)
		
		var dir = DirAccess.open(skins_path)
		if dir:
			dir.list_dir_begin()
			var file_name = dir.get_next()
			while file_name != "":
				if file_name.ends_with(".tres"):
					var skin_name = file_name.get_basename()
					var skin_resource = load(skins_path + file_name)
					if skin_resource:
						skins[skin_name] = skin_resource
						print("Found and loaded skin: ", skin_name)
					else:
						print("Failed to load skin resource: ", skins_path + file_name)
				else:
					print("Found file with invalid extension: ", file_name)
				file_name = dir.get_next()
			dir.list_dir_end()
		else:
			print("Failed to open directory: ", skins_path)
			print("Error code: ", DirAccess.get_open_error())
	print("Total skins loaded: ", skins.size())
	print("Available skins: ", skins.keys())
	
	load_skins_ui()


func create_skin_ui():

	if not skin_container:
		skin_container = VBoxContainer.new()
		skin_container.name = "SkinContainer"
		

		add_child(skin_container)
		
		var label = Label.new()
		label.text = "Available Skins"
		skin_container.add_child(label)
		
		print("Created skin UI container")

func load_skins_ui():
	for child in skin_container.get_children():
		if child is Button:
			child.queue_free()
	
	for skin_name in skins.keys():
		var button = Button.new()
		button.text = skin_name
		button.name = "Skin_" + skin_name
		button.pressed.connect(_on_skin_selected.bind(skin_name))
		skin_container.add_child(button)
	
	print("Updated skin UI with ", skins.size(), " options")

func _on_skin_selected(skin_name):
	print("Selected skin: ", skin_name)
	if skins.has(skin_name):
		current_skin = skins[skin_name]
		apply_current_skin()
	else:
		print("Error: Selected skin not found!")

func apply_current_skin():
	if current_skin:
		print("Applied skin: ", current_skin)
	else:
		print("No skin selected to apply")

func has_skin(skin_name):
	return skins.has(skin_name)

func get_skin(skin_name):
	if skins.has(skin_name):
		return skins[skin_name]
	return null

Also thanks to my dad who helped me write this. Shout out to you pops.

2 Likes

The following error appeared:

I will send the complete code that I use for the store system, maybe the problem is in something else then:

var skins : Dictionary = {}
var skin_price = {
	"black" : 50
}



func _ready() -> void:
	load_skins()
	label_2.text = str(PlayerData.player_money)


func _on_back_pressed() -> void:
	get_tree().change_scene_to_file("res://Scenes/scenes/menu.tscn")


func load_skins():
	var skins_path = "res://Resource/skins/"
	var dir = DirAccess.open(skins_path)
	if dir:
		dir.list_dir_begin()
		var file_name = dir.get_next()
		while file_name != "":
			if file_name.ends_with(".tres") or file_name.ends_with(".tres.remap"):
				var skin_name = file_name.get_basename()
				skins[skin_name] = skins_path + file_name
			else:
				print("Found file with invalid extension ", file_name)
			file_name = dir.get_next()
		dir.list_dir_end()
	else:
		print("Failed to open dir ", skins_path)
	print("Skins: ", skins)
	load_skins_ui()


func load_skins_ui():
	for child in grid_container.get_children():
		child.queue_free()
		
	for skin_name in skins.keys():
		if skin_name == "white":
			continue
		var panel = Panel.new()
		panel.custom_minimum_size = Vector2(50, 50)
		
		var texture_button = TextureButton.new()
		texture_button.custom_minimum_size = Vector2(50, 50)
		texture_button.stretch_mode = TextureButton.STRETCH_KEEP_CENTERED
		
		var sprite_frame = load(skins[skin_name])
		if sprite_frame is SpriteFrames:
			var texture = sprite_frame.get_frame_texture("Idle", 0)
			texture_button.texture_normal = texture
		texture_button.name = skin_name
		texture_button.pressed.connect(func(): _on_skin_view(skin_name))
		grid_container.add_child(panel)
		panel.add_child(texture_button)
2 Likes

You’re getting errors because your game is trying to load .remap files directly, which isn’t supported in Godot. The .remap files are typically generated during export and aren’t meant to be loaded directly.

1 Like

Cool, very interesting that it found black.tres, but finding the .tres.remap files is good.

You may have to use a more complex naming system as load doesn’t work on .remap files, it sadly still expects a .tres extension. This substr will truncate to the first . found, not just the extension; I doubt you intend to add dots as part of the filename. Then it re-applies the .tres extension to the stored path. This should work for both .tres and .tres.remap files

if file_name.ends_with(".tres") or file_name.ends_with(".tres.remap"):
	var skin_name: String = file_name.substr(0, file_name.find('.'))
	skins[skin_name] = skins_path.path_join(skin_name + ".tres")

The "You skins: " error is intersting, I don’t see that in the code.

2 Likes

Yes, sorry, it looks like the code didn’t all get pasted, You skins it from here:

func _on_timer_timeout() -> void:
	label_2.text = str(PlayerData.player_money)
	printerr("You skins: ")

I am very grateful to you, and in general to everyone who helped me, the problem was fixed, now the skins are loaded in the store. But there are two more mistakes:

1 Like

What error do you see in game that you think relates to this error? Is something operating before being added as a child?