How can I access C# consts from gdscript?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By atiaxi

I have a C# class that looks like this:

public partial class Constants : Node
{
	public const int None = 0;
	public const int X = 1;
	public const int O = 2;
}

(It’s actually a full tic-tac-toe class, this is just a minimal example)

I’d like to be able to access those constants from GDScript, but it really doesn’t seem to want me to. I’ve added this to the tree as a script attached to a plain Node named Constants.

Things that I have tried that do not work:

  • $Constants.X → Invalid get index ‘X’ (on base: ‘Node (Constants.cs)’).
  • load("res://game_logic/Constants.cs").X → Invalid get index ‘X’ (on base: ‘CSharpScript’).
  • load("res://game_logic/Constants.cs").new().X → Invalid get index ‘X’ (on base: ‘Node (Constants.cs)’).
  • Suggested by AI: $Constants.call("X") → Invalid call. Nonexistent function ‘X (via call)’ in base ‘Node (Constants.cs)’.
  • $Constants.get("X") → null
  • $Constants.get_script().get_script_constant_map()["X"] → Invalid get index ‘X’ (on base: ‘Dictionary’). (the dictionary is, in fact, empty)
  • Doing any of the above but changing const in Constants.cs to static → The same errors as before

The only solution I’ve found to this is to give up altogether and only attempt to access instance variables. However, this only solves the GDScript ↔ C# interoperability. Other C# scripts which were referring to e.g. Constants.None can now no longer do so since they’re instance-side. My workaround so far is to just define both and call e.g. $Constants.gdX:

public partial class Constants : Node
{
	public const int None = 0;
	public const int X = 1;
	public const int O = 2;

	public int gdNone = None;
	public int gdX = X;
	public int gdO = O;
}

I’ve noticed that gdscript seems to have only grudging support for static type access in general, so is this just an instance of language mismatch? Is this even possible? Is there a workaround that satisfies both sides of the language divide?

I think your class Constants could be static and not a node or just enum :slight_smile:

Moreus | 2023-03-20 22:15

As mentioned, there’s more to the class than just the constants (e.g. the full game has a StartGame, a TakeTurn, etc) this was a minimal example to reproduce the problem.

If I change the example to be static it’s perfectly accessible from the C# side, but I can no longer attach it as a script on the gdscript side (because it needs to also be partial and/or has to inherit from Node)

atiaxi | 2023-03-20 22:21

:bust_in_silhouette: Reply From: Moreus

Did you Follow this?

Yes, that page has no information on static or constant variables from either side of the language divide.

atiaxi | 2023-03-20 22:22

As const are processed at compile time itself, they are replaced with their values as soon as code is compiled. Than mean you better make getter for your constants because they only numbers :slight_smile:

Moreus | 2023-03-21 08:15

:bust_in_silhouette: Reply From: Moreus

You could try properties to make work

public partial class Constants : Godot.Node
{
    public const int valueNone = 0;
    public int None { get { return valueNone; } }
    public const int valueX = 1;
    public int X { get { return valueX; } }
    public const int valueO = 2;
    public int O { get { return valueO; } }
}

or even shorter

public partial class Constants : Godot.Node
{
    public int None { get { return 0; } }
    public int X { get { return 1; } }
    public int O { get { return 2; } }
}

If this will not work try methods

public partial class Constants2 : Node
{
    public int None() => 0;
    public int X() => 1;
    public int O() => 2;
}

Have fun :slight_smile: