godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.13k stars 88 forks source link

Implement exporting struct variables in C# #438

Open kayomn opened 4 years ago

kayomn commented 4 years ago

Describe the project you are working on:

Top-down shooter with a heavily reliance on data-driven design in character composition.

Describe the problem or limitation you are having in your project:

I have a Resource named Race which defines species data about the visual and physical composition about a creature, which is then taken and applied to a generic RigidBody-derived Actor class.

using Godot;
using Godot.Collections;

namespace Data
{
    public class Race : Resource
    {
        [Export]
        public string title = "";

        [Export]
        public Array<BodyPart> bodyParts = new Array<BodyPart>();
    }

    public struct BodyPart
    {
        public Texture texture;

        public int frames;
    }
}

I am using structs to group data together that is related, in order to avoid managing multiple arrays of parallel values in the editor's inspector UI. In this system, structs are preferred over class instances due to their lighter footprint and lack of need for polymorphism.

Describe how this feature / enhancement will help you overcome this problem or limitation:

This approach is not currently supported as Godot cannot export struct members into the inspector UI.

I am blanking on a workaround for this and believe that this is something that the engine should support in some way.

Show a mock up screenshots/video or a flow diagram explaining how your proposal will work:

Screenshot_20200204_122458

Describe implementation detail for your proposal (in code), if possible:

A sub-grouping that appears in the editor's inspector view containing the exported properties of the struct.

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

This enhancement is purely additive and should not impact existing code in any way.

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

It involves integration into the engine's editor UI and most likely its Mono / editor bindings.

Marmotus commented 4 years ago

I really want this to be implemented.

Calinou commented 4 years ago

@MarmotLord Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

Shadowblitz16 commented 4 years ago

this should be serialized as a value type so for example if you had something like so..

public class MyNode : Node
{
  [Export]
  public MyStruct struct
}

public struct MyStruct
{
  [Export]
   public string name

  [Export]
  public int value
}

MyNode's MyStruct property should be serialized in such a way that its not a drag and dropable item but instead is a expandable category similar to what unity does.

kayomn commented 4 years ago

@Shadowblitz16 I agree.

My primary reasoning for recommending using structs is that they have a far lower instantiation cost (when not boxed) as well as lower individual access (reducing the amount of pointer chases necessary to access memory).

wmigor commented 3 years ago

Use Resource and this addon https://github.com/wmigor/godot-mono-custom-resource-register

Kezzo commented 1 year ago

Interestingly godot already DOES support struct exporting for some specific struct types like Vector2, Vector3 including exporting Arrays of those struct types: https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/c_sharp_exports.html#exporting-arrays

I think a good first start towards this is to limit the scope of this to immediate primitive typed fields in the struct like Vector2 does as well. (Only int and int as exported class fields).

Could someone point me at the code that does handle the Vector2 exporting?

kayomn commented 1 year ago

Interestingly godot already DOES support struct exporting for some specific struct types like Vector2, Vector3 including exporting Arrays of those struct types: https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/c_sharp_exports.html#exporting-arrays

I think a good first start towards this is to limit the scope of this to immediate primitive typed fields in the struct like Vector2 does as well. (Only int and int as exported class fields).

Could someone point me at the code that does handle the Vector2 exporting?

It's been a while since I went through it, but there is a bunch of C# marshalling code that if else's over a selection of primitive types then any types that inherit Godot.Object.

wonson commented 1 year ago

I was also thinking of working on addon to see if it can be achieved by adding Custom C# Attribute, to marshal the struct by myself then translate them into current ExportGroup behaviour.

However, those code to read C# Attribute is in ScriptPropertiesGenerator.cs. So I guess it's out of my reach unless anyone implement it in Godot source.

frostymm commented 12 months ago

I'm currently facing this exact struggle wth converting my game scriptables from my unity project.

HeavensSword commented 12 months ago

I'm currently facing this exact struggle wth converting my game scriptables from my unity project.

Same exact problem here. While porting I had converted my structs and serialized classes into classes that derive from Resource, but quickly realized that it does not work how I had hoped...

Calinou commented 11 months ago

This likely depends on https://github.com/godotengine/godot-proposals/issues/7329 being implemented first, as exposing structs to the inspector requires the presence of a core struct type in the first place.

Drommedhar commented 9 months ago

Gonna copy my problem as well (from another issue). Currently I have no idea how to solve that.

Ran into this issue myself. In my case I want to subset an array of modifiers inside a resource to a class/struct. These contain always the same properties, but can be filled with different values/settings. In Unity I would just create a ScriptableObject class for these modifiers, add these as an array to my other ScriptableObject and was able to add/remove and change each value directly on the object itself. In Godot this would require me to create an resource for each modifier, link it (which is a pain with the big dropout for even creating new resources inside a resource) etc. This is not really usable.

I can't even use the ExportGroup attribute here, as I need to have multiple modifier and not just one. I would love to just use a C# struct for that and be able to export it, as I currently don't know how to do it otherwise. Again using a variety of Resources for that is out of the option, as this would result in hundreds of resources for something which should not be a resource at all.

To give more insight. I have an Item class (as a resource) which has AttributeModifiers (which would alter player or enemy attributes). This might include add or remove health etc. These are driven by an enum, which would tell me whic attribute to manipulate, what to do with it and so on.

rapushka commented 5 months ago

I can reach literally needed behaviour with

public partial class MyNode : Node
{
    [ExportGroup("Coordinates")]
    [Export] private int Colum { get; set; }
    [Export] private int Row { get; set; }

    public Coordinates Coordinates => new(Column, Row);
}

(yes I know about Vector2I)

But it would be not cool to just copy-paste these lines every time i need to provide this thing

Calinou commented 5 months ago

@rapushka Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

rapushka commented 5 months ago

@rapushka Please don't bump issues without contributing significant new information. Use the :+1: reaction button on the first post instead.

oh ok, sorry. rewrote my previous comment