godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
89.84k stars 20.96k forks source link

Custom resource loaders are not working in server exports #85101

Open Zylann opened 10 months ago

Zylann commented 10 months ago

Godot version

4.1.3

System information

Windows 10 64 bits NVIDIA GeForce GTX 1060

Issue description

I have a plugin (HTerrain) that defines a custom resource by inheriting ResourceFormatLoader. It can load .hterrain files. It works when tested in the editor, and it also works when exported as a game. But when exporting with resources in "Server" mode, the resource gets "loaded", but the custom loader's logic seems to never be executed. This causes users with server exports to be unable to use my plugin (https://github.com/Zylann/godot_heightmap_plugin/issues/410).

Steps to reproduce

1) Have a custom resource:

@tool
extends Resource

const EXTENSION = "custom"

var loaded = false

2) Have a custom loader for the custom resource (based on the plugin's code, which worked for years):

@tool
class_name CustomLoader
extends ResourceFormatLoader

const CustomResource = preload("./custom_resource.gd")

func _get_recognized_extensions() -> PackedStringArray:
    print("Calling _get_recognized_extensions")
    return PackedStringArray([CustomResource.EXTENSION])

func _get_resource_type(path: String) -> String:
    print("Calling _get_resource_type")
    var ext := path.get_extension().to_lower()
    if ext == CustomResource.EXTENSION:
        return "Resource"
    return ""

# Handle UIDs?
# By default Godot will return INVALID_ID,
# which makes this resource only tracked by path, like scripts. The loader works fine without this.
# func _get_resource_uid(path: String) -> int:
#   return ???

func _handles_type(typename: StringName) -> bool:
    print("Calling _handles_type")
    return typename == &"Resource"

func _load(path: String, original_path: String, use_sub_threads: bool, cache_mode: int):
    print("Calling _load")
    var res = CustomResource.new()
    res.loaded = true
    return res

3) Create an empty file resource.custom

4) Create a main scene with the following script on the root:

extends Node

func _ready():
    print("_ready")

    var res = load("res://resource.custom")
    print("Res: ", res)
    if res != null:
        print("Res is loaded: ", res.loaded)
    else:
        print("Res is null")

    print("_ready end")

5) Run the project in the editor: observe functions of the resource loader are called, and the loaded flag is true.

_ready
Calling _get_recognized_extensions
Calling _load
Res: <Resource#-9223372009491135328>
Res is loaded: true

6) Enable file logging in Project Settings (check advanced settings, then Debug category)

7) Create a non-server export preset, export the project with debug enabled, run it, and check the logs: observe functions of the resource loader are still called, and the loaded flag is true, just like when tested in the editor.

8) Create a server export preset by choosing Export as dedicated server in the dropdown below the Resources tab in export settings. Export, run it, and check the logs: observe functions of the resource loader are NOT called, and the loaded flag is false. This is not expected.

_ready
Res: <Resource#-9223372012527811424>
Res is loaded: false
_ready end

Minimal reproduction project

Project.zip

BatteryAcid commented 10 months ago

I built and tested the example project attached above with 4.2, and the issue still persists:

Screenshot 2023-11-30 at 9 30 17 AM
scotmcp commented 3 months ago

Can I get an update on this bug? I don't see how this isn't seen as a serious problem for games with dedicated server infrastructures.