Nifty GUI: Unable to call public method (how to reload nifty GUI XMLDocument)

I’m trying to create a dialogue box for non-player characters. Whenever this dialogue box appears, I want its contents to differ depending on which non player character node was clicked. I have an AppState dedicated to this, called NonPlayerCharacterInteractionControl.

In this class, I have an action handler for incoming inputs registered to the primary appstate:

@Override
    public void onAction(String name, boolean isPressed, float tpf) {
        if (name.equals(INPUT_MOUSE_SELECT) && isPressed) {
            Geometry clickedGeometry = getGeometryFromMouseCursor();
            String tag = (String) getUserDataFromParents((Spatial) clickedGeometry, "tag");
            
            if (tag != null) {
                if (tag.equals("NonPlayerCharacter")) {
                    if (doubleClickDelta > 0.0f) {
                        Integer id = (Integer) getUserDataFromParents((Spatial) clickedGeometry, "id");
                        
                        nifty.gotoScreen("dialogue");
                    }
                    
                    doubleClickDelta = DOUBLE_CLICK_SPEED;
                }
            }
        }
    }

The nifty instance referenced is running off of the following XML file:

<nifty>
    <screen id="blank" childLayout="horizontal"></screen>
    <screen id="dialogue" childLayout="vertical">
        <layer id="background" childLayout="horizontal">
            <panel id="text_box" childLayout="vertical" height="40%" width="50%" align="center" margin="5%">
                <panel id="dialogue_head" childLayout="horizontal" align="left" height="15%" width="45%" backgroundColor="#010101">
                    <text text="John Smith" font="Interface/Fonts/Arial.fnt" width="100%" height="100%" />
                </panel>
                <panel id="dialogue_body" childLayout="horizontal" height="85%" width="100%" backgroundColor="#0f0f0f0f">
                    <text text="${CALL.getDialogue()}" align="left" font="Interface/Fonts/Arial.fnt" width="100%" height="100%" />
                </panel>
            </panel>
        </layer>
    </screen>
</nifty>

Here you’ll notice I have the text for the body of the box set to ${CALL.getDialogue}, which exists in the NonPlayerCharacterInteractionControl and looks like this:

public String getDialogue() {
        return "Hey! Listen!";
    }

But when I run the game, it doesn’t show the new text, only the name of the method I’m calling. What should I do to ensure that it calls the function every time I double-click the NPC?

Show us the ScreenController class. Just to make sure NonPlayerCharacterInteractionControl is a ScreenController like I understood.

It is a ScreenController, yes.

public class NonPlayerCharacterInteractionControl extends AbstractControl implements ActionListener, ScreenController {

At the moment nifty has no idea what controller you are referencing. You need to set your controller in the screen xml like:

<screen id="start" controller="jme3test.niftygui.TestNiftyGui">

1 Like

OK, so I’ve set the name of the controller for both screens in the XML file. When I attempt to tun the game, I get these messages logged to the console multiple times:

WARNING: class [com.******.**.client.controls.NonPlayerCharacterInteractionControl] could not be instantiated (java.lang.InstantiationException: com.******.**.client.controls.NonPlayerCharacterInteractionControl)
Apr 11, 2020 10:45:01 AM de.lessvoid.nifty.loaderv2.types.ScreenType create
WARNING: Missing ScreenController for screen [dialogue] using DefaultScreenController() instead but this might not be what you want.
Apr 11, 2020 10:45:01 AM de.lessvoid.xml.tools.MethodInvoker invoke
WARNING: invoke for method [getDialogue()] failed

It should be noted that the asterisks are something that I’ve altered about the original output. I didn’t literally put asterisks in there.

Does it have a parameter-less constructor? It is most likely required so that it can be constructed via reflection by Nifty.

No, it doesn’t.

The only constructor I have looks like this:

public NonPlayerCharacterInteractionControl(Node rootNode, Camera camera, InputManager inputManager, Nifty nifty) {
        this.rootNode = rootNode;
        this.camera = camera;
        this.inputManager = inputManager;
        this.nifty = nifty;
        
        this.inputMap = new HashMap<>();
        inputMap.put(INPUT_MOUSE_SELECT, new MouseButtonTrigger(MouseInput.BUTTON_LEFT));
        
        registerInputs(inputMap);
    }

Hmm, it doesn’t seem to be a requirement. At least I also have constructors of all sorts and it works…

In nifty you can use a screen controller in one of two ways:

  1. Provide your own instance to nifty (I don’t remember how as I haven’t used nifty in about 8 years)
  2. Let nifty construct it for you… in which case it 100% must have a no-arg constructor.

But (2) is almost never what a JME user wants since then the object won’t have a reference to anything useful.

2 Likes

Yes, Paul is right, I didn’t remember. This is exactly what we do.

  1. We construct the screencontrollers ourselves, then you don’t need the parametersless constructor
  2. app.getNifty().registerScreenController(screen);

This is done before requesting screen of course.