Git Product home page Git Product logo

Comments (18)

31 avatar 31 commented on September 1, 2024 1

I guess it's not a big deal--here's what I came up with a little later, which I think I'd actually be happy with:

[OnReadyGet(In = "my/node/somewhere")] private Node deep;
[OnReadyGet(Unique = true)] private Node myNodeSomewhereDeep;

from godotonready.

cphillips83 avatar cphillips83 commented on September 1, 2024 1

Just a side note to the _Ready issue, my workaround was instead of doing an override of _Ready, I created a ctor for the class and hooked to TreeEntered to execute my own source gen/node wire up logic.

I ended up using TreeEntered instead of Ready because _Ready is called before the event Ready is fired and I wanted to make sure that if I had custom logic in _Ready that the nodes would be gathered already.

from godotonready.

TacticalLaptopBag avatar TacticalLaptopBag commented on September 1, 2024 1

What's the status of updating to Godot 4? I'd love to make use of this as I currently have several variables being initialized in my _Ready() functions

from godotonready.

31 avatar 31 commented on September 1, 2024

A few things:

  • Private non-exported values. Often scripts are written for a specific scene, so it can make sense to require a specific arrangement of nodes. Making a generalized script that can accept any node paths (and work without certain nodes being present!) can be a waste of time, or even introduce new bugs with implementation.
  • Fetching scene-unique node names. Do these work with [Export] public Node n;? Will need to check, but I'm not sure how it would.
    • Similar: OnReadyFind.
  • Built-in null check (and optional null allowance).

from godotonready.

31 avatar 31 commented on September 1, 2024

Waiting for the final state of 4.0 to see how it ends up. But so far, it does look like Godot's adding the bare minimum and some people will still find GodotOnReady useful.

from godotonready.

31 avatar 31 commented on September 1, 2024

It turns out 4.0 broke _Ready method generation by having a source generator that scans the list of methods: https://github.com/godotengine/godot/blob/master/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs.

If a _Ready method isn't on that list, it isn't called, and since source generators run independently and don't (can't!) read each other's sources, the method generated by GodotOnReady won't be found, and won't be called.

The obvious workaround is that you need to write a _Ready method in each script to get it to call GodotOnReady's setup:

public override void _Ready()
{
  OnReadySetup();
}

Could use a partial method to let Godot's generator find the method and then fill it in with GodotOnReady:

partial override void _Ready();

I prefer the former because:

  • Now you don't need to use [OnReady] to do things on ready, like connect to signals from the nodes you've just set up. (Although you still could use [OnReady].)
  • If other source generators also want to generate code that runs on ready, you can simply add the call. You don't need to worry about two generators both trying to generate a partial _Ready method and conflicting.

In either case, analyzers could make sure that when [OnReadyGet] is being used, one of these is implemented. This would hopefully mean you don't get surprise null reference exceptions. But no matter what, the boilerplate regression is frustrating.

(I haven't tried any of this yet, this is from discussion in the Discord C# channel.)

from godotonready.

31 avatar 31 commented on September 1, 2024

I just tried it out in 4.0 and there's a more fundamental problem: GodotOnReady generates [Export] members, and there's now a Godot source generator that detects exported members. So, the generated members aren't included and don't show up in the inspector.

Any new version of GodotOnReady that works with 4.x will contain significantly more boilerplate than it previously did, and need a significantly different API because of that, so I don't see how it would be possible to continue the project in any recognizable form in 4.x+.

As for myself, I'm going to go forward with only the new [Export] public Node Foo { get; set; } feature and see what happens. I've edited the readme to indicate 3.x compatibility only.

from godotonready.

31 avatar 31 commented on September 1, 2024

If Roslyn implements something like this, then GodotOnReady would have a way forward:

from godotonready.

firebelley avatar firebelley commented on September 1, 2024

Hello! I am super interested in using source generation to achieve what you've done here in Godot 4. I have a similar library where I use reflection to find Nodes with matching names instead of source generation: https://github.com/firebelley/GodotUtilities/blob/master/GodotUtilities/src/ChildNodeAttribute.cs

The reason I bring this up is I am wondering if there's an alternate approach to generating the [Export] attribute. Is there a way to use a hybrid of source generation and name-guessing?

For instance, I define like so:

[OnReadyGet]
private MyNode myNode;

Under the hood, this tool could generate the following code (psuedocode example):

myNode = GetNodeOrNull<MyNode>("MyNode") ?? GetNodeOrNull<MyNode>("myNode") ?? GetNodeOrNull<MyNode>("my_node")

Basically generate every reasonable string that could be valid as a node name. Additionally the ability to provide a node path in the OnReadyGet attribute could be preserved. I realize that the user loses control over specifying exact node paths with this proposal but there are a couple of benefits in my opinion:

  • Most nodes defined in scenes don't change and have a relatively static structure. I think it's a little redundant to have to then configure the node paths after using [OnReadyGet]
  • Godot 4 now supports [Export]-ing Nodes rather than node paths, which is what users can use for uncertain or variable node paths

I'm sure calling some kind of setup method would still be necessary. In my reflection code I still require the user to call WireNodes.

Anyway, apologies if any of this is under-informed. But I am super curious about this project and how it could be used in Godot 4. Would appreciate your thoughts on anything I've suggested here! I'm thinking about potentially forking this code and trying my hand at implementing this.

from godotonready.

31 avatar 31 commented on September 1, 2024
myNode = GetNodeOrNull<MyNode>("MyNode") ?? GetNodeOrNull<MyNode>("myNode") ?? GetNodeOrNull<MyNode>("my_node")

How would the user specify a node that's nested somewhat deeply in the node hierarchy? (How would you represent / in the field name, or would you?) This is frequent in UI, where scene structure defines behavior.

  • Most nodes defined in scenes don't change and have a relatively static structure.

In my experience, nodes defined in scenes rarely have a static structure, and change frequently. πŸ˜„ I suppose this depends on the nature of the project being worked on.

Conceptually, I admit I prefer the purity of a node script defining its dependencies (which set of nodes it needs to be able to fetch, for what reasons), then hooking them up in the scene editor. This is probably why [Export] public Node Foo { get; set; } has been working fine for me.

This part of GodotOnReady isn't addressed here yet, and it's probably the part I'll actually miss:

[OnReadyGet("AnimationTree", Property = "parameters/playback")]
private AnimationNodeStateMachinePlayback _playback;

I'm sure calling some kind of setup method would still be necessary.

Yeah, this is my conclusion in #49 (comment). I think including an analyzer with a fixup is critical to make this approach user-friendly (whether for a reflection or source generation backed implementation).


Thanks for the interest. πŸ™‚ I don't think those solutions are right for GodotOnReady in 4.x. (Although I would support adding [OnReadyGuess] for the member-name multi-lookup suggestion!) I would prefer to wait for a solution that lets the library keep the [OnReadyGet] semantics (by generating [Export] members), or leave this library behind if that never becomes possible.

No argument from me about making a fork for 4.x with different semantics. It's MIT licensed, after all. πŸ˜„ I'm just happy it seems like reasonable enough code to fork.

from godotonready.

firebelley avatar firebelley commented on September 1, 2024

How would the user specify a node that's nested somewhat deeply in the node hierarchy? (How would you represent / in the field name, or would you?) This is frequent in UI, where scene structure defines behavior.

The new scene unique nodes are perfect for this, and could be used like so:

[OnReadyGet("%MyNodeSomewhereDeep")]
private Node node;

I think where we differ is I think many scenes (like a player scene) would have a large number of static nodes that all make up the player's behavior. I agree that when a node has external dependencies those should be configured using [Export]. But for all of the nodes that are sort of "internal" to the scene file itself I personally would prefer to not have to configure those paths.

I definitely see where you're coming from though! Thanks for the response, it's helpfulπŸ‘

from godotonready.

31 avatar 31 commented on September 1, 2024

For what it's worth, here's a design that I believe would work in 4.x without dropping features, but significantly clogs up the syntax:

public partial class Foo : Node
{
  [Export, GodotOnReady<Player>] public NodePath playerPath = "somewhere/is/my/player";

  public override void _Ready()
  {
    base._Ready();
    OnReadySetup();
  }

  public override void _Process(double dt)
  {
    player.Happy();
  }
}

Note: player is a generated member made by chopping Path off playerPath. I'm not too happy about using a variable that isn't declared in this class. It functions, but I want the generator to be invisible. (Also, this means Godot can't access it, e.g. for GDScript interop.)

from godotonready.

31 avatar 31 commented on September 1, 2024

The new scene unique nodes are perfect for this, and could be used like so:

[OnReadyGet("%MyNodeSomewhereDeep")]
private Node node;

The name of the field wouldn't realistically be node though, right? Rather, myNodeSomewhereDeep. That question was about the name convention in particular, avoiding that name duplication.

from godotonready.

firebelley avatar firebelley commented on September 1, 2024

I see what you're saying regarding generated members. If I understand right, I think the approach I'm thinking of is that the user would specify the Node members (like private Node node), rather than NodePath members, and then those Node members could just be assigned in the generated code.

The name of the field wouldn't realistically be node though, right? Rather, myNodeSomewhereDeep. That question was about the name convention in particular, avoiding that name duplication.

Ah, I don't think I'm describing myself very well. Essentially I would expect that if a node path/name is provided, then there would be no need to make a best-guess effort. The guess would only be necessary if no node path information was made available.

So for example:

[OnReadyGet("%MyNodeSomewhereDeep")]
private Node node;

Would generate the following code before doing any guessing:

node = GetNode<Node>("%MyNodeSomewhereDeep");

So in essence, there would be multi-step assignment logic that first checks if there is an supplied node path. If not, then move on to trying assignment via guessing the node name.

from godotonready.

31 avatar 31 commented on September 1, 2024

If I understand right, I think the approach I'm thinking of is that the user would specify the Node members (like private Node node), rather than NodePath members, and then those Node members could just be assigned in the generated code.

Yep, I understand the suggestion, it just isn't possible to make all the current features work with it.

Ah, I don't think I'm describing myself very well. Essentially I would expect that if a node path/name is provided, then there would be no need to make a best-guess effort. The guess would only be necessary if no node path information was made available.

I just wasn't expecting the guessing to stop working after any more than one-level-deep nodes. πŸ˜„ Getting direct children isn't a particularly common scenario for me.

I assumed the point was to optionally remove the (near-)duplication of the member name in [OnReadyGet("MyNode")] private Node myNode; so my first thought was to ask about additional common cases.

from godotonready.

31 avatar 31 commented on September 1, 2024

Well, well! I never considered generating a constructor. From there, the EnterTree or Ready signal makes sense. I don't actually have to pick EnterTree to preserve GodotOnReady functionality, because creating your own _Ready method was already forbidden while using GodotOnReady on a node script.

(I personally prefer Ready, because descendant node Ready methods/receivers might add additional nodes to the tree or cause other edge cases like that. EnterTree certainly works as its own thing, but as far as keeping GodotOnReady the same as it was in 3.x, it could cause unexpected behavior for some people.)

Thanks, I'll give that a try. I'm hoping I can end up creating one NuGet package that picks the strategy based on the version of Godot it's being used in.

from godotonready.

31 avatar 31 commented on September 1, 2024

Oh, never mind: I forgot that _Ready is only one part of the problem.

I just tried it out in 4.0 and there's a more fundamental problem: GodotOnReady generates [Export] members, and there's now a Godot source generator that detects exported members. So, the generated members aren't included and don't show up in the inspector.

from godotonready.

31 avatar 31 commented on September 1, 2024

What's the status of updating to Godot 4?

No change, here's a summary:

  • C# source generators still don't have the ability to use each other's output: dotnet/roslyn#57239
  • Godot still doesn't provide some other way to accomplish what's needed: godotengine/godot#66597. (The issue might not fully cover what's needed here--more about this above. The full feature set of GodotOnReady requires deeper integration than some other generators might.)
  • Personally, I'm satisfied by the 4.x support for [Export] public Node n;, so I have no personal motivation to find a way to push this through or make compromises on a more limited GodotOnReady API that would work under 4.x's limitations. This is hardly the extent of what GodotOnReady is capable of in 3.x, but it was the part of the library I ended up actually using 99% of the time myself. (I prefer to assign node references in the editor rather than in scripts using e.g. hard-coded strings.)
  • There are some other libraries linked to in godotengine/godot-proposals#2425 that might actually do what you need already. Otherwise, you might want to take a look at writing your own source generator and https://github.com/chickensoft-games/SuperNodes to make it compatible with other generators.

from godotonready.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.