Godot Mono : GetChild by name - mono

Some context :
In Godot, one is constantly working with nodes and those nodes' children.
Godot has made the design choice of letting the dev manipulate nodes with some sort of querying language that often relies on the full path (starting from the root of the current scene).
For example if the scene is structured like this :
MyRootNode
|
|-- MyChild1
| |
| |-- MySubChild1
|
|
|-- Mychild2
...then the devs are encouraged to access "MySubChild1" with a path :
node = get_node("MyRootNode/MyChild1/MySubChild1")
(note: I''m using the verbose "get_node" syntax rather than $ syntax for readability to C# devs)
Because of that ease of use, I can see that GDScript devs have a tendency to do this :
root = get_node("MyRootNode")
child1 = get_node("MyRootNode/MyChild1")
subchild1 = get_node("MyRootNode/MyChild1/MySubChild1")
...rather than this (pseudo-code) :
root = get_node("MyRootNode")
child1 = root.get_child("MyChild1")
subchild1 = child1 .get_child("MySubChild1")
It makes perfect sense to write queries in a weakly-typed scripting language : all the queryable items have more or less the same type.
The named version of get_child() doesn't even exist. In reality you would need to do this :
root = get_node("MyRootNode")
child1 = root.get_child(0) // first child
subchild1 = child1 .get_child(0) // first child
=================
This is all very awkward for a C# developer. Because of the typing. It's like we're given safety but then it's instantly taken away.
Imagine this :
public class MyRootNode : Node
{
private Control MyChild1 = null; // initialized in _Ready once and for all
public override void _Ready()
{
MyChild1 = GetNode<Control>("MyChild1");
}
public override void _Process(float delta)
{
// Not possible!!!
var mySubChild1 = MyChild1.GetChild<TextureRect>("MySubChild1");
}
}
My question : Is there a way of getting a child in a safe way? It seems to me that none of the solutions seem natural (as developed below), and I mean "safe" in contrast to that.
If I do this :
var mySubChild1 = GetNode<TextureRect>("MyRootNode/MyChild1/MySubChild1");
...then it's extremely unsafe in case of nodes renaming or if I decide to change the tree structure.
If I do this :
var mySubChild1 = MyChild1.GetChild<TextureRect>(0);
....then it's still horrendously unreadable (accessing named items by index? No thanks)
As a C# dev, how do you do it?

My question : It seems to me that there's no way of getting a child in a safe way. None of the solutions seem natural.
That is not a question. That is an statement of opinion.
If I do this:
var mySubChild1 = GetNode<TextureRect>("MyRootNode/MyChild1/MySubChild1");
…then it's extremely unsafe in case of nodes renaming or if I decide to change the tree structure.
This is more unsafe that just a matter of changing the code. The problem is that the scene tree can change independently of the code. In my own terms: the scene tree is external to the code. And thus, the scene tree changing is a reason of change for the code. In other words, the scene tree changing is a responsibility of the code.
Remember single responsibility principle? That is how the software architects would suggest you deal with potential external changes. Make a piece of your code that is the only part that needs to change when the external change happens, so the change does not propagate across your code. I would relax it and say that it does not have to be a separate class, it just has to be self-contained.
In that order of ideas, this makes sense:
onready var root = get_node("MyRootNode")
onready var child1 = get_node("MyRootNode/MyChild1")
onready var subchild1 = get_node("MyRootNode/MyChild1/MySubChild1")
If you use these kind of declarations and initialization on top of your file, that is the only place where you would have to change the code to fix it. Granted, you don't have onready in C#, instead you have to do it on _Ready.
If I do this:
var mySubChild1 = MyChild1.GetChild<TextureRect>(0);
… then it's still horrendously unreadable (accessing named items by index? No thanks)
Agreed. Then don't do it.
As a C# dev, how do you do it?
I don't know what C# developers do. Because I'm not actively using C# at the time.
Now, I did bring up a few other things in comments.
First, if you are in control of the project, you can make sure your code does not fail. That of course might means changing the paths… However, if you use Scene Unique Nodes you can minimize it.
This code:
onready var root = get_node("MyRootNode")
onready var child1 = get_node("MyRootNode/MyChild1")
onready var subchild1 = get_node("MyRootNode/MyChild1/MySubChild1")
Would turn into this:
onready var root = get_node("%MyRootNode")
onready var child1 = get_node("%MyChild1")
onready var subchild1 = get_node("%MySubChild1")
That is, the scene tree hierarchy is no longer relevant. And given that you give good names to your Nodes, you should be able to move them around in your scene tree without further issue. And to be clear, this is implemented in the get_node function so other languages such as C# can use (and GDScript gets some syntactic sugar on top, which I'm not using here).
So yes, you can do that in C#:
private Control MyChild1 = null;
public override void _Ready()
{
MyChild1 = GetNode<Control>("%MyChild1");
}
Second, you can use get_node_or_null (GetNodeOrNull in C#). So your code does not throw when there isn't a node. Instead you can handle the null.
Speaking of nulls. When a Node is freed (e.g. by calling queue_free, which is QueueFree in C#) it does not make the references to it null. And no, Godot does not override the equality operators in C#. Which is why we also have is_instance_valid (Object.IsInstanceValid in C#).
Third, the idea of getting a child by name is not needed in Godot because get_node et.al. can do it.
To be clear, get_node does not work from the root of the current scene, it works from the Node on which you call it. So you can do this:
public class MyRootNode : Node
{
private Control MyChild1 = null; // initialized in _Ready once and for all
public override void _Ready()
{
MyChild1 = GetNode<Control>("MyChild1");
}
public override void _Process(float delta)
{
// Notice I'm using GetNode here
var mySubChild1 = MyChild1.GetNode<TextureRect>("MySubChild1");
}
}
I don't know if that is satisfactory for you, and I don't know if that is a common practice.

Someone else posted this answer in a different discussion channel : It provides extra elements, more centered around C#'s possibilities.
if it’s exported nodepaths I highly recommend
https://github.com/31/GodotOnReady it cuts down on a lot of
boilerplate code.
Otherwise parentNode.GetNode(“path”) has been working great.
Using % in combination with "Access as Scene Unique Name" is
cool with stuff that you will tweak and move around a lot, I use
it with UI mostly.
For additional safety, you can rock parentNode.GetNodeOrNull(path).
Unlike GetNode, GetNodeOrNull with a type won’t raise an Exception if
something doesn't match (type or name), it just returns null.
So at least it won’t silently burn you.
Best practice I found is to only use these methods in node setup
methods.
Otherwise I do regular dependency injection, and groups to
find what I need.
That being said, I always advocate failing loudly and failing fast,
so I only use GetNode and existing references. If it explodes
it means I messed up.

No matter what anyone does there are ways for it to break. Some of the responsibility simply must fall on developers changing code to test their work. If you wish to access something by name, then changing that name on the object but not at the point of access is going to cause failure. That said, you can avoid the risk of reorganization of your object breaking your code by using the less-efficient
Node : find_node ( String mask, bool recursive=true, bool owned=true ) const
so
root = get_node("MyRootNode")
child1 = get_node("MyRootNode/MyChild1")
subchild1 = get_node("MyRootNode/MyChild1/MySubChild1")
can become
root = find_node("MyRootNode")
child1 = find_node("MyChild1")
subchild1 = find_node("MySubChild1")
It requires you to name your nodes of interest uniquely within this object. But the structure to traverse to reach said nodes can change.

Related

Is there any possibility that QAbstractItemModel::beginResetModel and endResetModel can create a performance issue?

My Dev setup:
Qt version : Qt 5.15.0
OS: Embedded Linux
I have a list of information.
Assume I have a structure called MyStruct
My model class is having a member variable of QList of above structure, to hold data for my view. Whenever I am opening the view, I am updating the QList (Note: There may or may not be a change). Updating here is something like assigning a new QList to existing one. before assignment, I am calling beginResetModel and after assignment I am calling endResetModel,
void MyModelClass::SomeInsertMethod(const QList<MyStruct>& aNewData)
{
beginResetModel();
m_lstData = aNewData;
endResetModel();
}
One thing I believe can be improved, is putting a check, if the new data is different than the existing data and then doing the above. Something like this:
void MyModelClass::SomeInsertMethod(const QList<MyStruct>& aNewData)
{
if (m_lstData != aNewData)
{
beginResetModel();
m_lstData = aNewData;
endResetModel();
}
}
Apart from that, is there any possibilities of getting a performance issue for calling beginResetModel/endResetModel? I m seeing a very small delay in the view coming up in my application.
I checked the documentation of QAbstractItemModel for above methods. Didn't get anything specific to the performance issue.
The other way, which this can be done, is by individually comparing the elements of the lists and triggering a dataChanged signal with appropriate model index and roles. But I feel, this will unnecessarily introduce some additional loops and comparisons, which again may cause some other performance issue. Correct me if I am wrong.
Is there any advantage of using dataChanged over beginResetModel/EndResetModel?
Please let me know your views on the above.

Common return type for all ANTLR visitor methods

I'm writing a parser for an old proprietary report specification with ANTLR and I'm currently trying to implement a visitor of the generated parse tree extending the autogenerated abstract visito class.
I have little experience both with ANTLR (which I learned only recently) and with the visitor pattern in general, but if I understood it correctly, the visitor should encapsulate one single operation on the whole data structure (in this case the parse tree), thus sharing the same return type between each Visit*() method.
Taking an example from The Definitive ANTLR 4 Reference book by Terence Parr, to visit a parse tree generated by a grammar that parses a sequence of arithmetic expressions, it feels natural to choose the int return type, as each node of the tree is actually part of the the arithmetic operation that contributes to the final result by the calculator.
Considering my current situation, I don't have a common type: my grammar parses the whole document, which is actually split in different sections with different responsibilities (variable declarations, print options, actual text for the rows, etc...), and I can't find a common type between the result of the visit of so much different nodes, besides object of course.
I tried to think to some possible solutions:
I firstly tried implementing a stateless visitor using object as
the common type, but the amount of type casts needed sounds like a
big red flag to me. I was considering the usage of JSON, but I think
the problem remains, potentially adding some extra overhead in the
serialization process.
I was also thinking about splitting the visitor in more smaller
visitors with a specific purpose (get all the variables, get all the
rows, etc.), but with this solution for each visitor I would
implement only a small subset of the method of the autogenerated
interface (as it is meant to support the visit of the whole tree),
because each visiting operation would probably focus only on a
specific subtree. Is it normal?
Another possibility could be to redesign the data structure so that
it could be used at every level of the tree or, better, define a generic
specification of the nodes that can be used later to build the data
structure. This solution sounds good, but I think it is difficult to
apply in this domain.
A final option could be to switch to a stateful visitor, which
incapsulates one or more builders for the different sections that
each Visit*() method could use to build the data structure
step-by-step. This solution seems to be clean and doable, but I have
difficulties to think about how to scope the result of each visit
operation in the parent scope when needed.
What solution is generally used to visit complex ANTLR parse trees?
ANTLR4 parse trees are often complex because of recursion, e.g.
I would define the class ParsedDocumentModel whose properties would added or modified as your project evolves (which is normal, no program is set in stone).
Assuming your grammar be called Parser in the file Parser.g4, here is sample C# code:
public class ParsedDocumentModel {
public string Title { get; set; }
//other properties ...
}
public class ParserVisitor : ParserBaseVisitor<ParsedDocumentModel>
{
public override ParsedDocumentModel VisitNounz(NounzContext context)
{
var res = "unknown";
var s = context.GetText();
if (s == "products")
res = "<<products>>"; //for example
var model = new ParsedDocumentModel();
model.Title = res; //add more info...
return model;
}
}

How to fetch an integer property from a Model and use it to initialize a local variable, in Razor?

I have a model containing an integer property called Pointer. I want to use that property inside the Razor view, as follows:
However I am getting an error...
How do I solve this? Is this error because of the line: int pnt = #Model.Pointer; ?
Yes, and you are generally overusing #. Your code should probably read something like:
#for (var i = 0; i < Model.Lists.ToList().Count; i++) {
var pointer = Model.Pointer;
if (i == pointer) {
var url = "/Subscriber/List/" + i;
<li>#Model.Lists.ToList()[i].ListName</li>
}
}
Apart from your actual question, I suggest you consider writing some extensions to the HtmlHelper class, i.e. to allow writing e.g. Html.SubscriberListItem(number), to keep concerns properly separated and the view clean.
Another option would be moving most of the logic to the view model (or possibly controller). I.e. there could be something like a Model.Subscribers.Link.Uri and a Model.Subscribers.Link.Text. This may even be the preferred option, depending on what your model looks like. (Perhaps the uri should be hooked up with the RoutingTable also.)
The code you've written is prone to throwing exceptions, and moving the logic out from the view will make writing safe code easier as well, if you don't mind my saying so.

Logic in setter and state pattern

Let's define a simple state machine:
public enum State {
A, B, C, D;
private List<State> validChange;
static {
A.validChange = Arrays.asList(B);
B.validChange = Arrays.asList(C);
C.validChange = Arrays.asList(A, D);
D.validChange = Arrays.asList(D);
}
public boolean couldChange(State newState) {
return validChange.contains(newState);
}
}
and a simple state object
public class StateObject {
private State currentState;
public State getCurrentState() {
return currentState;
}
public void setCurrentState(State currentState) {
if (this.currentState != null && !this.currentState.couldChange(currentState)) {
throw new IllegalStateException(String.format("Can not change from %s to %s", this.currentState, currentState));
}
this.currentState = currentState;
}
}
As we see in the setter we check that the state change is valid. My questions:
is it a good solution to add some logic to setter method (we are not interest how does it work but only fact logic inside setter)?
when should we add logic, when should we not?
if not why?
The state pattern has its reference implementation for years. The implementation is free of your concerns. States are not represented as enums but rather as classes inheriting from the same base class. This way the implementation of transition between states is much simpler and cleaner as each state is only responsible for its own transitions.
I wonder why you decide to try your own approach instead of following a good, reliable practice.
Answering your question - there is nothing fundamentally wrong in having a code in a setter. But the way you approach the implementation of the state pattern raises unnecessary issues.
In general, yes, it's OK to have logic in setters.
If you think SRP is a good idea, then you're OK if you add logic that is related to setter functionality, which primarily means maintaining the integrity of the object w.r.t to the change of the attribute's value.
Like I said, one of the cases when this is a bad idea is an SRP violation.
In fact, I would say the code posted shows an example of such a violation, since the setter has two responsibilities:
initialize the State of a new StateObject instance,
process any transition into a new State.
The second responsibility would become even more apparent if you'd implement the remaining part of a canonical state machine, i.e. the full transition function, including transition actions.
A primary example of where this separation of concerns would become important is in code where you only have setter injection - how do you differentiate between initialization and transition in this case? With this code, you can't.
Additionally, I believe the case would become more apparent if you'd refactor validChange to StateObject, which I think is necessary, since the current code breaks encapsulation - State, a state machine label, contains "guard specification" for the state transition function. Let's say you would like to have the same labels in a different state machine - as the code currently stands, you can't have that (there's even a nice code smell that should point you towards the problem, as instead of using an enum constructor, you're forced to create a static initialization block).

Generators for regular classes in scalacheck

In scalacheck's user guide there is "Generating Case Classes" paragraph. I modified example from it to use regular classes instead of case classes:
import org.scalacheck._
import Gen._
import Arbitrary._
sealed abstract class Tree
object Leaf extends Tree
class Node(left:Tree, rigth:Tree, v:Int) extends Tree
object Main {
val genLeaf = value(Leaf)
val genNode = for{
v <- Arbitrary.arbitrary[Int]
left <- genTree
rigth <- genTree
} yield new Node(left, rigth, v)
val genTree:Gen[Tree] = oneOf(genLeaf, genNode)
def main(args:Array[String]){
println(genTree.sample)
}
}
It seems everything working but I'm afraid of using this approach in production code before I ask here: is there any pitfalls?
This should work fine. There's nothing about case classes that are particularly magical about case classes as far as ScalaCheck is concerned. Any old class can get a generator, or even be convertible to Arbitrary.
As far as testing goes, one difference is that every non-case-class tree you generate will be unique, and thus for no two trees you generate will tree1 == tree2. That's different from how it is with case class, which test equality based on value rather than identity. You may need more tests to handle issues with aliasing that become possible when you have identity-based rather than value-based equality.
I see no problem here. The reason why case classes are used in that example is that the Tree shown is an algebraic data type, made possible with case classes. With normal classes, you cannot pattern match on the tree, and, in fact, you won't even be able to get left, right and v without declaring them val.