godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.17k stars 98 forks source link

Allow scripts to export static variables, and allow them to be assigned in the editor #10961

Open pineapplemachine opened 1 month ago

pineapplemachine commented 1 month ago

Describe the project you are working on

Currently I am working on a project where it would be very helpful for certain node or resource types to have a globally configured reference to another value or resource, without having to hardcode paths, or having to manually specify the reference for every instance.

For example, where a node type needs a reference or path to a PackedScene to create and attach instances of that scene depending on runtime logic. Currently, the options are to either hardcode the path (in which case it does not get updated if the scene file is renamed or moved in Godot) or to use an instance @export that must be specified for every individual node, even when this PackedScene would be the same for all.

Describe the problem or limitation you are having in your project

There is seemingly no easy way to create and handle custom global configuration values in Godot.

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

This would become allowed, e.g. in GDScript:

class_name MyConfigurableType

@export static var my_resource: MyResourceType

When an object of this type is viewed in the inspector, an additional section titled e.g. "MyConfigurableType Static" would show alongside the instance sections. Here, the global values would be visible and configurable.

Ideally, there should also be a new tab or window which aggregates all of these static exports in one place, without needing to create an instance of MyConfigurableType in order to view and edit the global values.

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

In GDScript:

@export static var my_resource: MyResourceType

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

There does not seem to be any existing clean solution for this.

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

This would involve a GDScript language change.

AThousandShips commented 1 month ago

Having non-instance data be editable in the inspector is IMO confusing and error prone, it also doesn't really make sense UI wise to me, having it be configurable in a dedicated project settings menu would make more sense

The bigger question is how it would work, your proposal doesn't actually explain how this would be loaded and initialized, or where it would be stored, or how it would handle values between the class and such configuration

What happens if you assign a value in the script source? Is it the default? What happens if you change this? Is the configured value in the settings/inspector used?

dalexeev commented 1 month ago

Static variables belong to the class, not to instances. I don't think this is a good idea, since it's not clear what to do with multiple instances exporting different values ​​of static variables and when they should be applied.

You could store global parameters in a separate resource instead:


const PARAMS = preload("./params.tres")

static var param_1 = PARAMS.param_1
static var param_2 = PARAMS.param_2

It's even possible to use them as constants, although I'm not sure that's the intention:


const PARAMS = preload("./params.tres")

const PARAM_1 = PARAMS.param_1
const PARAM_2 = PARAMS.param_2
pineapplemachine commented 1 month ago

@AThousandShips I am not knowledgeable enough about engine internals to suggest an implementation.

But I think assigning the value in code would work like assigning any exported instance var in code. At runtime, it would update the value like any typical mutable global value. In a tool script, it would make the change persistently, and would be reflected in whatever editor UI is used to assign these values.

@dalexeev I did end up using an approach similar to this to handle global config in my project.

I created a custom Resource class, created a single instance somewhere in the project directory, and added a static func to the Resource class for getting that single designated instance via a path hardcoded only once within that Resource class. The single instance is editable in the inspector, things like resource and scene references are automatically kept consistent, and scripts that need to access this global config do so via e.g. MyConfigResource.GetInstance().my_var. This is what I've ended up doing in some cases where I needed globally configured references to resources (e.g. which Texture2D to use in the UI in places where an icon is meant to represent some game concept) that ideally I wanted to 1. edit in the inspector rather than in code and 2. have paths automatically update and be repaired in case I moved or renamed a resource, rather than silently broken.

But global custom project settings, which seems like something with almost universal utility, should really should have some option with better usability in my opinion.