libgdx/gdx-ai

Is there a reason to use getFields instead of getDeclaredField in BTreeParser

jhoukem opened this issue · 5 comments

Issue details

On my way to try the framework I struggled to get the @TaskAttribute annotation to work. I always got the following exception : throw stackedTaskException(getCurrentTask(), "unknown attribute '" + name + "'");

The issue was that I set my field as private and in the BehaviorTreeParser the findMetadata method() use the method ClassReflection.getField which only return the public field.

Is there a reason for that ? Wouldn't it be more intuitive to use ClassReflection.getDeclaredField method instead ? If not I think we should update the documentation to notify this behaviour.

Reproduction steps/code

Create a simple LeaftTask with a private field annotated with @TaskAttribute, set the TaskAttribute in the .btree file and try to parse it. You will get a unknow attribute error.

Version of gdx-ai and/or relevant dependencies

1.8.1

This also becomes a problem when using Kotlin instead of Java. It would be awesome, if the Annotation could be extended to be allowed on Setter Methods so it's also possible to do some post-processing.

I created a PR for this issue.

@tommyettinger Should we close this issue since 117 has been merged?

@jhoukem Since using getDeclaredFields() won't find inherited members but getFields() will, 117 was just reverted (117 breaks existing code that inherited fields, and existing code couldn't have used private fields before and so still can't). I'd like to be able to have this handle the Kotlin case mentioned above and the current inheritance use case, but it doesn't seem straightforward. I'm not sure why you actually would need private fields in your behavior tree Tasks, except for Kotlin's quirks which 117 wouldn't be able to handle (since it would need to handle setters).

So there's your reason, getFields() allows inheriting fields as long as they are public, and getDeclaredFields() does not allow inheriting fields.

As of Mar 2022, the unexpected behavior described in this issue still appears for LeafTasks in Kotlin when annotated as documented for Java.

What seems to have worked for me was adding @JvmField annotation before the @TaskAttribute annotation in the LeafTask class as so:

@JvmField
@TaskAttribute
var doing : String? = null

Also important appears to be how one creates the tree. I was unable to get attribute data into the LeafTask class from the btree using the following tree parsing approach (from GdxDemo3d):

// Create behavior tree through the library
BehaviorTreeLibraryManager btlm = BehaviorTreeLibraryManager.getInstance();
this.tree = btlm.createBehaviorTree("btrees/dog.btree", this);

However, the following tree parsing approach (inspired by Benoit Dumas's Alchemist project) populates the LeafTask attribute as I would expect:

var tree : BehaviorTree<KoboldCharacter>

init {
    val reader = FileReader("android/assets/btree/kobold.btree")
    val parser = BehaviorTreeParser<KoboldCharacter>(BehaviorTreeParser.DEBUG_HIGH)
    tree = parser.parse(reader, this)
}

Hope this helps.

Thank you,
Ian