webots
                                
                                 webots copied to clipboard
                                
                                    webots copied to clipboard
                            
                            
                            
                        getNodeFromDef dot-pathing should be able to skip levels
It is good that supervisor.getFromDef will seek out a node with the given DEF-name at any level of the scene tree. So, e.g., if I have one robot with a solid LEFT_WHEEL, I can use getFromDef('LEFT_WHEEL') to get that node, without needing to worry about whatever intervening ancestor nodes might lie above it.
Sometimes you'll have multiple nodes with the same DEF-name in the scene tree, e.g., if you have multiple robots that are clones of each other, with the same DEF-names for their parts.
To allow for such cases getFromDef also accepts a path notation, e.g., getFromDef('ROBOT.JOINT.SOLID'). Unfortunately, this path notation requires that every node on the path be included. So, e.g., if I clone my original robot, so now ROBOT1 and ROBOT2 each have a left wheel, I currently can't refer to these as 'ROBOT1.LEFT_WHEEL' and 'ROBOT2.LEFT_WHEEL'. Instead I now need to DEF-name and explicitly list all the intervening nodes, e.g., ROBOT1.LEFT_SIDE_TRANSFORM_LEFT_AXLE.LEFT_WHEEL and ROBOT2.LEFT_SIDE_TRANSFORM.LEFT_AXLE.LEFT_WHEEL.
In many ordinary use cases, like the one described above, this need to explicitly DEFname and list all intervening nodes is tedious and unnecessary. Instead I would suggest that getFromDef('name1.name2') should first seek out a node with DEFname name1 at any level, and then seek out a descendant node with DEFname name2 at any level below that, not just a single level below that. I.e., it should produce exactly the same result that getFromDef('name2') would if the scenetree consisted just of the node named name1 and its descendants. (Your implementation for no-dot inputs likely already has a recursive search for traversing the tree anyway, so the suggestion is to start this recursive search at the node named name1, and use it to find a node named name2, skipping levels if necessary just as no-path getFromDef already does.)
If you search immediate children first, then in every case where the old implementation yielded a result, this suggested new implementation would yield the same result, so it should be highly backwards compatible. The only difference would be that this would now let you name only the important disambiguating levels (like ROBOT1 vs ROBOT2) in a dot-path, rather than needing to explicitly list every single intervening level (like LEFT_SIDE_TRANSFORM and LEFT_AXLE).
Here's some Python code that performs the recursive search I'm talking about (taking an API Node and a defName as input), though I'm sure my list of searchable_field types is incomplete, and I'm sure it would be better for this to be performed in the C part of Webots rather than out in the controller where things must be much slower. Since you already have getFromDef skipping levels fine when it receives non-pathed input, you can probably just reuse the recursive search it already has, but if not, you could use this recursive search as a model.
searchable_fields = "children appearance geometry".split(' ')
def seekFromDef( node, name ):
    """This works the way one would wish Webots' path version of getFromDef would, 
       seeking out, at *any* level, a descendant of the given node whose DEFname is name.
       This uses a list of searchable_field names that may contain further nodes.  For each
       such searchable field, this checks whether node has such a field. If so, it
       confirms that this field is of a type (SFNode/MFNode) that can contain nodes,
       and if so, checks if that field's value(s) match name -- if so return our match!
       If not, this triggers a recursive search of each such node, seeing if we
       can turn up something called name under it. Returns None if no match found."""
    print( f"Recursively searching {node.getDef()} for {name}." ) 
    for fname in searchable_fields:
        field = node.getField(fname)
        if field:
            print( f"Searching field {fname}" )
            type = field.getType()
            if type == field.SF_NODE:
                child = field.getSFNode()
                if child:
                    if child.getDef()==name: return child  # FOUND IT!!!
                    success = seekFromDef(child, name) # otherwise recursively search this child
                    if success: return success # SUB-SEARCH FOUND IT!!!
            elif type == field.MF_NODE:
                for i in range(field.getCount()):
                    child = field.getMFNode(i)
                    if child:
                        if child.getDef()==name: return child  # FOUND IT!!!
                        success = seekFromDef(child, name) # otherwise recursively search this child
                        if success: return success # SUB-SEARCH FOUND IT!!!
        # go back up to try next fname
    #if we got here, our recursive search of searchable fields failed...
    return None # report our failure
This could actually be easily implemented here by replacing:
const QList<WbNode *> &descendants = baseNode->subNodes(false, allowSearchInProto, false);
with
const QList<WbNode *> &descendants = baseNode->subNodes(true, allowSearchInProto, false);
And updating the documentation accordingly.
This could actually be easily implemented here by replacing:
const QList<WbNode *> &descendants = baseNode->subNodes(false, allowSearchInProto, false);with
const QList<WbNode *> &descendants = baseNode->subNodes(true, allowSearchInProto, false);And updating the documentation accordingly.
Yes, this will work correctly. But we will loose the benefits in terms of performance of using the dot-pathing because all the subnodes will be retrieved. It could be more efficient to apply a sort of breadth-first search first where the direct children of the node are inspected (as in the current code), then if not found the method should retrieve all the subnodes and loop through them.