Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal type wrapper object for Godot #21203

Closed
willnationsdev opened this issue Aug 19, 2018 · 1 comment
Closed

Universal type wrapper object for Godot #21203

willnationsdev opened this issue Aug 19, 2018 · 1 comment

Comments

@willnationsdev
Copy link
Contributor

willnationsdev commented Aug 19, 2018

Godot version:
Godot 3.2/4.0+

Issue description:

UE4 UClass

I would ideally like to be able to emulate UE4's UClass functionality within Godot. This entails the following:

  1. UClass is effectively an enumerated type where the options include all in-engine classes and all custom classes.
  2. UClass can be used to create a new instance of the selected type.
  3. UClass can provide reflection information on the selected type.
  4. When exporting a UClass variable to the Editor, the UClass variable's value can be restricted by inheriting from a particular in-engine/custom type.
  5. Important: It provides an effective wrapper around all type references and manipulations.

That last point is really the reason why this feature is so desirable. It makes a whole host of other tasks much easier: allowing users to customize custom classes with their own custom types (or with engine types of their choosing), simplifying logic that deals with a variety of underlying types by unifying them under a single API, etc.

Use Case

Just as an example, I made a VBoxItemList script where users can supply their own Control node variant to get plugged into the list. There are a few issues with this functionality though.

  1. I have to account for the user specifying a Script vs. a PackedScene and execute a custom API for handling each type of resource (.new() vs. .instance()).

  2. The user can't specify an in-engine type because GDScript does not allow you to store a type into a variable:

     var type = Button
     var button = type.new()
    

The user can hack around this by creating an empty script that extends Button and then supplying a path to it, but it's a hack that should really have a more low-level solution. Now, while providing an in-engine type wouldn't be very useful for the script I made specifically, there are other situations where you might want to plug in an in-engine type for some purpose but can't do so because there's no left-hand value that can support it.

Optimal Alternative

What I would like to be able to do in this situation is use a new type wrapper class to resolve these problems and add the other UClass-like features:

(Assuming we call this low-level wrapper type ClassType...)

  1. Export a ClassType from my script.
  2. When the user clicks on the value in the Inspector, they will see an enumeration list of the possible class types, which include all in-engine types and registered class types. Ideally, this list would also include globally registered scenes with their own names (yes, registering scenes with names warrants a separate Issue altogether, similar to Ability to link scene with class #21187). The user could also begin typing into a search bar in the popup to filter the enumeration results.
  3. When selected, the variable's value would be a wrapper class that has the following features:
    1. Can grab the string version of the class name from it with something like get_name().
    2. Can call .new() on it to get an instance of the C++ type, Script, or PackedScene that the name refers to.
    3. Can call reflection methods like has_method and a generic get_base_type.
      1. get_base_type would return another ClassType
      2. For scenes, all reflection methods would operate as if they were interacting with the in-engine type or scripted type that exists at the root node of the scene.
      3. Also for scenes, testing whether the ClassType "is" a Script or PackedScene would function so: if the right-hand argument is a PackedScene, then the ClassType would have to refer to a PackedScene that is inheriting the right-hand argument scene; if the right-hand argument is a Native type or Script, then the default "is" test would have to be conducted, but using the root node of the scene instead.
    4. Can get an enum value informing the user of what type of asset is stored in the ClassType (engine type, Script, or PackedScene).
    5. Can call as_native(), as_script(), and as_scene() methods to fetch the underlying asset (returns null if not applicable).
    6. Could potentially have this class also fetch any documentation data that has been defined for the class (whenever that feature is supported for scripts/scenes as well).

Implementation Concept

Here are my thoughts on how creating a class like this might actually be possible.

  1. Expose a native type wrapper class for each scripting language (so, e.g. for GDScript, we would expose GDScriptNativeClass) that way doing things like:

    var button_type = Button

...would actually work. This could be something that is scripting language specific(?). Could make it an abstract type called NativeClass or something.

  1. Create a way to register names for scenes, that way a scene can be represented by just a StringName. The simplest way of doing this would be a SceneServer-like entity (although it would be preferable if we could make it an editor-only entity that sets up a map of names to scene resources in ProjectSettings and then have ScriptLanguage::init calls set up global constants in their respective scripting languages, that way we avoid changes in core).

  2. Define the ClassType, probably extending Reference, that wraps the functionality of NativeClass, Script, and PackedScene.

  3. Devise a schema of PropertyInfo values that allow us to select a type in this fashion, e.g.

     {
         "name": "type_to_insert",
         "type": TYPE_OBJECT,
         "hint": PROPERTY_HINT_ENUM,
         "hint_string": <ClassName goes here>
     }
    

I believe I overheard reduz say that he is interested in redesigning this type hint stuff in part 4, so I assume that would be up for change as well.

Being able to constrain the results by a particular type would be really cool, but the only way I can think of to do it (if we didn't change the type hint system) would be to put in a delimeter for the hint_string so that, e.g. "Button:Control" would work, but "Sprite:Control" wouldn't.

Anyway, what do you guys think? Desirable? Doable to some extent?

Edit: Added the ClassType (PackedScene) is <something> scenario description.

@willnationsdev
Copy link
Contributor Author

Based on the discussion in #21187, there is no need to continue working on this. Anything that can assist both the editor (can't be a module, must be in core or editor) and runtime (can't be in editor) would have to be in core, and any and all core changes that would enable a user-defined type system will not be approved by reduz.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants