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

_Init() is not being called for C# scripts. #22633

Open
KellyThomas opened this issue Oct 2, 2018 · 18 comments
Open

_Init() is not being called for C# scripts. #22633

KellyThomas opened this issue Oct 2, 2018 · 18 comments

Comments

@KellyThomas
Copy link
Contributor

KellyThomas commented Oct 2, 2018

Godot version:
dacc3f3 and 3.1 alpha

OS/device including version:
Window 7 x64

Issue description:
_Init() is not being called on my c# scripts

Steps to reproduce:
Create a node with this script:

using Godot;
using System;

public class InitTest : Node
{
    public override void _Init()
    {
        GD.Print("Hello World!");
    }
}

But when it runs no message is printed.

Minimal reproduction project:
init-test.zip

@star-tek-mb
Copy link

i think you should use _init()

@neikeq
Copy link
Contributor

neikeq commented Oct 2, 2018

Is _init actually something other than a GDScript feature? Where is it called from?

@reduz
Copy link
Member

reduz commented Oct 2, 2018 via email

@KellyThomas
Copy link
Contributor Author

It is exposed as part of Godot.Object

http://docs.godotengine.org/en/latest/classes/class_object.html#class-object-init

@willnationsdev
Copy link
Contributor

willnationsdev commented Oct 2, 2018

I guess the workflow in C# is just to use a constructor then? That would make sense.

Edit: Oh, if it's exposed, then idk what. Weird.

@reduz
Copy link
Member

reduz commented Oct 2, 2018 via email

@neikeq
Copy link
Contributor

neikeq commented Oct 2, 2018

I will hard-code the bindings generator to ignore _init then.

@willnationsdev Yes. However, you will have to add a default constructor as well, since the implicit one is removed if you add a constructor overload. (There was an issue about this but I can't find it).

@neikeq
Copy link
Contributor

neikeq commented Oct 2, 2018

@reduz Not sure about removing it from the docs. I would rather make it clear in the method description that it's a GDScript-only thing.

@willnationsdev
Copy link
Contributor

willnationsdev commented Oct 2, 2018

Is _init also used in VisualScript? I had thought it was (in which case, we should clarify that it's for "Godot languages" like GDScript and VisualScript).

@fire
Copy link
Member

fire commented May 23, 2019

Is this related to visual script?

@neikeq
Copy link
Contributor

neikeq commented May 23, 2019

Searching in the source code doesn't give any result that would indicate it's used in VisualScript, so I think it's GDScript-only.

Regarding C#, I'm not so sure about removing it anymore. I'm actually thinking of making it work.
The Godot editor has now we create placeholder instances of script classes in the editor for getting the default values of exported properties. The constructor has to be called for those instances. Having a _Init function that would only be called for real non-placeholder instances would be great.

@neikeq
Copy link
Contributor

neikeq commented May 23, 2019

I'm removing _Init for now in #29140, but I plan to add a working implementation in the future as explained in my previous comment.

@Pilvinen
Copy link

Any news on this?

I don't feel C# constructors are the C# version of _init due the way Godot works. C# constructor with Godot are largely useless due to the initialization order. We often end up implementing and manually calling our own Initialize() methods. But. Having _Init support in Godot's .NET version would, for instance, allow for a separate two-step construction and initialization for objects.

@neikeq

@lenscas
Copy link

lenscas commented Sep 29, 2023

How do C#'s constructors behave diffrently than GDScript's _init in this @Pilvinen ? I never used GDScript so I may be wrong but from what I know about them it sounds like they behave exactly the same?

@EnlitHamster
Copy link

@Pilvinen could you expand on your point? I also haven't used GDScript so I would be curious to know

@lenscas
Copy link

lenscas commented Nov 9, 2023

@EnlitHamster I managed to talk to @Pilvinen about it on discord. However this was a while ago so I might be misremembering so take the following with a grain of salt.

Basically, Pilvinen wants a method that gets called when the node is put into the tree together with its children, similar to OnEnterTree (Or whatever the method was called). However, unlike OnEnterTree it will only be called once.

Ready doesn't work for this (At least, not for Pilvinen) because this is called after every child has had it's Ready method called. Or said another way, the order is the opposite way around for Pilvinen.

Pilvinen was thinking/hoping that _init could be this method in C# but as far as I'm aware this isn't what _init does in GDScript.

@Pilvinen
Copy link

Pilvinen commented Nov 9, 2023

That pretty much sums it up.

The problem is that if you want to use Godot in a way where your work flow is code-centric you will get into all sorts of trouble with initialization order when you try to pass dependencies around. Anything that is passed to you from the editor via the export attribute is pretty much guaranteed to work. No problem there. But this is not always the case if you want to primarily be responsible for instantiating your own objects from code, passing them to child nodes that require them and adding nodes to the tree manually.

The work flow becomes reversed from what is customary in Godot.

_Ready of course doesn't accept parameters so you can't use it to pass dependencies around. C# has constructors and while constructor injection is normally a very powerful pattern in C#, this doesn't always work that well with Godot because by the time constructor runs - nothing is ready in Godot, so you can't depend on anything. You can only rely on your own code. If you need some piece of information from Godot, it is not available at this time.

It was my hope that _Init might have been an additional step in initialization which would have allowed clean separation between:

  • Object creation
  • Passing dependencies around via property injection or constructor injection
  • Initialization of the objects

While _Ready would have quaranteed that all child objects are, well, ready, the order would have been reverse with init - allowing us to do away with constructing and using our own Initialize() methods.

I spent a full year studying all the various approaches which could be used to pass data around and get dependencies in Godot in code-first approaches, essentially treating Godot as a library. For me reflection probably worked the best, but also felt like an overkill for something which should be simple.

Godot 4.x largely fixed all the problems which drove me into this in the first place by allowing export of nodes.

But in the end after a year of experimenting I simply finally gave up. The problem at the core wasn't really ever resolved. Godot is difficult to work with if you want to go code-first and ignore the editor. There is room for improvement. And my hope was (a long time ago) that _Init might have been a simple work flow improvement. There was some talk, a long time ago, of adding _Init support to Godot's C# version and bringing feature parity between GDScript and C# versions.

To sum it up.

My thinking was that you would do what ever injection you want with parameter/CTOR injection. Then you would go down the tree hierarchy with _Init and initialize the objects with data from a parent class. Then on _Ready you would come up the hierarchy child-to-parent and do final steps with your fully initialized objects and reliably present objects.

Now, maybe this is not how _Init works in GDScript. I don't know.

But what I do know is _EnterTree would have worked excellently for this exact purpose if it weren't for the annoying fact that it runs each time the node enters the tree vs. once on creation. I also tried using _EnterTree in my experiments and it required adding bool IsInitialized as class member to every object + logic for checking for this. Which became really old really soon. But other than that it did work exactly as described.

This was a long time ago and I've probably forgotten a lot of what the real and practical problems were, but I do believe the out of the ordinary way Godot required networking to be initialized in 3.x was a big part of the issue. And similar practices were also present in other places. But I've forgotten the details of the issues.

And I'm not sure what the situation in Godot 4.x is as I've mostly transitioned to using node exports after giving up on code-first approach.

I'm sure you can figure out the bottle necks for yourself with some experimentation.

@EnlitHamster
Copy link

Thank you very much for the detailed answer, it was illuminating.

I am doing some simulation work in Godot, and need to do some particular library loading. I hope I can figure out how to load the various modules just in their specific node to code-split the dependencies, but I'll just have to see what brick walls I find on the way.

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