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

Implement exporting struct variables in C# #438

Open
kayomn opened this issue Feb 4, 2020 · 19 comments
Open

Implement exporting struct variables in C# #438

kayomn opened this issue Feb 4, 2020 · 19 comments

Comments

@kayomn
Copy link

kayomn commented Feb 4, 2020

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

This comment has been minimized.

@Calinou

This comment was marked as resolved.

@Shadowblitz16
Copy link

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
Copy link
Author

kayomn commented Jul 25, 2020

@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
Copy link

wmigor commented Mar 27, 2021

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

@Kezzo
Copy link

Kezzo commented Nov 27, 2022

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?

@Calinou Calinou changed the title Exporting Struct Variables in C# Implement exporting struct variables in C# Nov 27, 2022
@kayomn
Copy link
Author

kayomn commented Nov 27, 2022

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
Copy link

wonson commented Apr 23, 2023

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
Copy link

frostymm commented Oct 9, 2023

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

@HeavensSword
Copy link

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
Copy link
Member

Calinou commented Oct 10, 2023

This likely depends on #7329 being implemented first, as exposing structs to the inspector requires the presence of a core struct type in the first place.

@Drommedhar
Copy link

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
Copy link

rapushka commented Apr 15, 2024

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

This comment was marked as resolved.

@rapushka

This comment was marked as resolved.

@mrkyee
Copy link

mrkyee commented Jan 29, 2025

This is exactly my biggest pain point at present. Inheritance from "resource" is too bloated for me. I see that this issue was put forward five years ago. I wonder if there has been any progress or if there is something like a planned roadmap?

@Calinou
Copy link
Member

Calinou commented Jan 29, 2025

This is exactly my biggest pain point at present. Inheritance from "resource" is too bloated for me. I see that this issue was put forward five years ago. I wonder if there has been any progress or if there is something like a planned roadmap?

This still needs a struct type to be exposed to GDScript first, as mentioned above: #438 (comment)

There was a pull request implementing structs but it seems to be on hold for now: godotengine/godot#82198

Therefore, I don't know when this will be implemented.

@pineapplemachine
Copy link

Would there be any possibility of not adding structs to GDScript as a prerequisite before this? This feature would be extremely useful to me too, even if the GDScript interop wasn't there at first. GDScript seems fine as a simpler introduction to coding for newbies, but for more substantial projects C# is by far the stronger choice at the moment (at least in my opinion), and I think this feature would probably be much more important to the latter kind of use case than the former. And so maybe it would be okay for the GDScript implementation to come after?

@Calinou
Copy link
Member

Calinou commented Jan 30, 2025

Would there be any possibility of not adding structs to GDScript as a prerequisite before this?

The issue is that the rest of Godot needs a struct type to be exposed before it can effectively be used within the editor. If you want to be able to export a struct type, it needs to be editable within the inspector, usable as a method parameter and a return type (so it appears in the class reference correctly). At this point, you've done a big chunk of the work required to implement structs in GDScript, so you might as well go all the way there 🙂

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