godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.14k stars 93 forks source link

Add autoload annotation to GDScript #7165

Open DispairingGoose opened 1 year ago

DispairingGoose commented 1 year ago

Describe the project you are working on

An action platformer side scroller boss rush (think Terraria but only the fighting bosses part of the game)

Describe the problem or limitation you are having in your project

Having to navigate through project settings to create a new autoload is awkward.

Additionally, I often find myself putting # autoload [ClassName] at the top of my autoload scripts to signpost that the script I am in:

Describe the feature / enhancement and how it helps to overcome the problem or limitation

The autoload keyword will work identically to class_name, whilst creating an autoload of the given name provided (as if the 'global variable' checkbox in the autoload menu is clicked.

It prevents having to navigate through UI as you can simply put autoload [ClassName] extends Node at the top - a much quicker process. Additionally, it acts as the same signpost as commenting # autoload [ClassName] - without the caveat of the fact that comments can become outdated and get 'bugs'.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Example of a signal bus script making use of this feature:

autoload GlobalSignals
extends Node

signal player_spawned()
signal player_died()

signal round_over()

If this enhancement will not be used often, can it be worked around with a few lines of script?

It can be worked around by using the autoload menu in Project Settings.

The signposting complaint can be worked around with a comment (# autoload [ClassName])

Is there a reason why this should be core and not an add-on in the asset library?

Many users prefer representing aspects of their code via code instead of UI.

Signals come to mind here - you have the option to connect them up in the editor or in code via [SignalName].connect(func(): do_something()).

dalexeev commented 1 year ago

I had this idea too. Note that:

  1. Thanks to static variables in 4.1, in many cases you can now use static classes instead of autoloads.
  2. Autoload in Project Settings allows you to add not only scripts (.gd), but also scenes (.tscn). Even for GDScript, we can't replace a scene with a script (at least not until we've implemented #1935).
  3. Autoload in Project Settings works with other languages, including unofficial ones.
  4. For compatibility reasons, we should not remove the current version.
  5. It seems to me that this should be an annotation, not a keyword.
DispairingGoose commented 1 year ago

Would it be possible to introduce multilanguage support? I'm thinking -

namespace Test;

[Autoload]
public partial class MyAutoload : Node
{
}
kleonc commented 1 year ago

Also note that:

  1. Order of the autoloads do matter. How could it be customized with a keyword/annotation? Or would it be supposed to only add it to the already existing list of the autoloads in the project settings (where it could be reordered)?
  2. The same script can potentially be added multiple times, as separate autoloads. The same would need to be possible with the keyword/annotation.
DispairingGoose commented 1 year ago

Maybe add these as parameters to an annotation?

@autoload(2, 1) # creates the node as the 3rd autoload with 1 instance
class_name GlobalSignals
extends Node

signal player_spawned()
signal player_died()

signal round_over()

Although now order of autoloads will need to be synced across both the annotations and project settings (note I'm not overly familiar with Godot's internal architecture so this may / may not be a problem)

A bit of a bodge, but project settings could act as GUI to add the autoload annotation, and then only annotations need to be kept track of (or vice versa)

theraot commented 1 year ago

In all honesty, I'd see the annotation as a convenience not as a replacement (you should still be able to control autoloads the old way, so feature parity is not a must).

When is it convenient? For me, it is to have easy to reuse code. For example a folder with some scripts and other resources that you can copy and paste into another project and have it work without messing with project settings. So I could only care about the order between autoloads that work and are deployed together (e.g. they are from the same folder I was copying).

However, in practice, the issue is not making a script an autoload, but that there will be code that expect an autoload to be there.

With that in mind, I would flip the idea: Instead of annotating that a particular script should be an autoload. I would want to be able to add autoloads declaratively from a script. Similar to preload, like this:

@autolaod("AutoloadName", "res://path/to/autoload/to/be/added/before/this/script.gd")

It should be at the top of the script.

About duplicates: It would not add the autoload if there is already an autoload with that name, but you can still have duplicates if you give them different names.

About the order: If an autoload requires another autoload to be prior it to work correctly, then can use the sane annotation to make sure the other autoload was there first. Aside from that, write your code avoiding having them mess with each other.


Addendum 1 After writing this, I realized there is nothing wrong with an script adding itself. So we might have an adjustment: let @autoload("Name") (without the path) make the same script an autoload. That way you get the feature you want too.

Also thinking about it, you could have empty string mean a nameless autoload.

Addendum 2: It might be a keywork or an annotation, I just default to minimizing breakage.

DispairingGoose commented 1 year ago

This would allow for autoloading scenes as well

@autolaod("AutoloadName", "res://path/to/autoload/to/be/added/before/this/script.tscn")