Static typing prevents GDScript parsing in runtime-loaded resource packs

Godot Version

4.2.1.stable.official.b09f793f5
Linux

Question

I’m trying to implement a mod loading system as suggested in the documentation: Exporting packs, patches, and mods — Godot Engine (stable) documentation in English

So far, it works as expected, except for the specific problem with static typing.
Whenever I load a pack with a script having statically typed variables, it won’t parse and load if it uses custom types featured in other .gd files of the loaded pack. No problems happen when variables are typed as built-in classes.

# This declaration will result in an error
@export var custom_resource : CustomResource
# This declaration will load properly
@export var custom_resource : Resource

I don’t know how the ProjectSettings.load_resource_pack method works under the hood, but here is my understanding of what’s happening. Probably, the script files that are attached to nodes in the scene from the pack are loaded first, so when such files are parsed, there are types that don’t exist in the scope at this moment (either they are loading after the scene scripts or does not load at all). Here is the error message that I’ve encountered:

Parser Error: Could not find type "CustomResource" in the current scope.

This fails further script loading. Here is an example message:

E 0:03:49:0170   main.gd:8 @ change_scene_to_pack(): Failed to load script "res://test_pack/scripts/color_changer.gd" with error "Parse error".
  <C++ Source>   modules/gdscript/gdscript.cpp:2788 @ load()
  <Stack Trace>  main.gd:8 @ change_scene_to_pack()

Once again, I have no idea how the ProjectSettings.load_resource_pack method or GDScript parsing works under the hood, so I don’t claim this is exactly the cause behind the errors. These are just my assumptions to make the problem description less vague. The link to a GitHub demo can be found below if anyone wants to test the problem.

I’ve managed to circumvent the issue by replacing static typings with their builtin class parents. So, replacing the CustomResource type with the Resource will not trigger any error but will make development miserable without proper static typing. You can test this with the demo by uncommenting one of the custom_resource variable declarations in color_changer.gd. I’ll provide more information about the demo project structure below.

It would be nice to hear suggestions on how to properly implement script loading at runtime.

Demo project on GitHub

The GitHub repo has two directories:

  • Demo-TestPack
  • Demo-PackLoader

Directories correspond to the different Godot projects (creating and loading a pack, respectively) that should be imported separately.

Demo - TestPack

This is the pack’s project. You can either download the pack that will be loaded in the PackLoader from the GitHub releases or export it yourself from this project. If you are exporting it from the project, choose Export selected resources as the export mode. You’ll need to export only the test_pack folder as test_pack.zip. Please name the exported zip exactly like this since PackLoader is hardcoded for this name. I’ll give details on pack loading in the PackLoader section. For now, just store test_pack.zip anywhere.

TestPack has a scene res://test_pack/pack.tscn that will be loaded by PackLoader. The scene has a button that’s supposed to switch colors when pressed. The logic behind this is implemented in the color_changer.gd and custom_resource.gd files that create minimal conditions to reproduce the error. You can investigate these scripts yourself; they are very straightforward, with just a few lines of code. I’ll just point out that changing the declaration from lines 4 to 7 of the color_changer.gd will resolve the issue as I described above and demonstrate that the problem is in the custom types parsing.

Demo - PackLoader

The project consists of a single scene main.tscn that has the sole purpose of loading a zip pack from the user:// directory (user:// is default). Place the test_pack.zip archive directly into the user:// directory and run the PackLoader project from the editor. You’ll need to run the project at least once to generate the user:// directory. Like the TestPack, you can get the exported executable of PackLoader from the GitHub releases.

That’s expected as the pack loader project does not have that class registered so it does not know it exists.

I don’t think it’s possible to do what you want to do but feel free to open an issue here Issues · godotengine/godot · GitHub explaining what you want to do and the problem you are facing.

I see. This seems to be very limiting. Anyway, thank you for your reply. I wanted to open an issue on GitHub anyway but decided to check the forums first to see if there is something obvious I’m doing wrong.