[SOLVED] Nifty bugs

Found a few bugs in Nifty while testing but I am not sure if its something I am doing.

First,

WARNING: RuntimeException in callMethod(public void mygame.states.LobbyState.onClick(java.lang.String,de.lessvoid.nifty.elements.events.NiftyMousePrimaryClickedEvent)) for [mygame.states.LobbyState@38e3d68a]
java.lang.IllegalArgumentException: argument type mismatch
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at de.lessvoid.nifty.NiftyMethodInvoker.callMethod(NiftyMethodInvoker.java:157)
	at de.lessvoid.nifty.NiftyMethodInvoker.performInvoke(NiftyMethodInvoker.java:112)
	at de.lessvoid.nifty.Nifty$DelayedMethodInvoke.perform(Nifty.java:1481)
	at de.lessvoid.nifty.Nifty.invokeMethods(Nifty.java:1457)
	at de.lessvoid.nifty.Nifty.handleDynamicElements(Nifty.java:439)
	at de.lessvoid.nifty.Nifty.access$1600(Nifty.java:87)
	at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processEvent(Nifty.java:1727)
	at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processMouseEvent(Nifty.java:1665)
	at com.jme3.niftygui.InputSystemJme.handleMouseEvent(InputSystemJme.java:123)
	at com.jme3.niftygui.InputSystemJme.onMouseButtonEventQueued(InputSystemJme.java:231)
	at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:295)
	at de.lessvoid.nifty.Nifty.update(Nifty.java:368)
	at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:112)
	at com.jme3.input.InputManager.processQueue(InputManager.java:843)
	at com.jme3.input.InputManager.update(InputManager.java:907)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:725)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:227)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232)
	at java.lang.Thread.run(Thread.java:745)

It was first reported here but I found nothing addressing it.

It happens when using the @NiftyEventSubscriber annotation and you select a text control. In this case, the text control does nothing and the annotation is set on the button control.

The text control,

<panel id="text_panel" height="100%" width="70%" childLayout="center">
    <control id="namefield" name="textfield" maxLength="20"/>
</panel>

The Button control.

<panel id="panel_bottom" height="34%" width="100%" align="center" childLayout="center">
    <control id="login" name="button" label="Login" visibleToMouse="true"></control>
</panel>

The Annotation.

    @NiftyEventSubscriber(id="login")
    public void onClick(String id, NiftyMousePrimaryClickedEvent event) {
        System.out.println("element with id [" + id + "] clicked at [" + event.getMouseX() + ", " + event.getMouseY() + "]");
        
        nifty.gotoScreen("hud");
        getState(KeyboardRunState.class).setEnabled(true);
    }

Using an mouse event handler with the <interact> XML element works as expected.

=================================

Second bug or issue I am seeing is that on occasion, when clicking on the button, the ScreenController skips the onClick method call or any method call for that matter and prints this to the screen.

I've been clicked:New Node (Node) MouseButton(BTN=0, RELEASED)

This happens under any scenario, using the @NiftyEventSubscriber or just a mouse event handler. Can spam press the button and get ten misses and then will work for no reason I can determine.

This is what the login state looks like in case its something I am doing wrong.


package mygame.states;

import com.jme3.app.Application;
import com.jme3.app.state.BaseAppState;
import com.jme3.niftygui.NiftyJmeDisplay;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.NiftyEventSubscriber;
import de.lessvoid.nifty.elements.events.NiftyMousePrimaryClickedEvent;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author mitm
 */
public class LobbyState extends BaseAppState implements ScreenController {

    private static final Logger LOG = Logger.getLogger(LobbyState.class.getName());
    private Nifty nifty;
    
    @Override
    protected void initialize(Application app) {
        NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay(
                getApplication().getAssetManager(),
                getApplication().getInputManager(),
                getApplication().getAudioRenderer(),
                getApplication().getGuiViewPort());
        /**
         * Create a new NiftyGUI object
         */
        nifty = niftyDisplay.getNifty();
        // attach the Nifty display to the gui view port as a processor
        getApplication().getGuiViewPort().addProcessor(niftyDisplay);

    }

    @Override
    protected void cleanup(Application app) {
    }

    //onEnable()/onDisable() can be used for managing things that should 
    //only exist while the state is enabled. Prime examples would be scene 
    //graph attachment or input listener attachment.
    @Override
    protected void onEnable() {
        /**
         * Read your XML and initialize your custom ScreenController
         */
        nifty.fromXml("Interface/screen.xml", "lobby", this);
//        nifty.setDebugOptionPanelColors(true);
    }

    @Override
    protected void onDisable() {
        //Called when the state was previously enabled but is now disabled 
        //either because setEnabled(false) was called or the state is being 
        //cleaned up.
    }
    
    @Override
    public void update(float tpf) {
        //TODO: implement behavior during runtime
    }

    @Override
    public void bind(Nifty nifty, Screen screen) {
//        this.nifty = nifty;
        System.out.println("bind( " + screen.getScreenId() + ")");
    }

    @Override
    public void onStartScreen() {
        System.out.println("onStartScreen()");
    }

    @Override
    public void onEndScreen() {
        System.out.println("onEndScreen");
    }
    
    public boolean connectToServer() {
        System.out.println("Login button clicked.");

        nifty.gotoScreen("hud");
        getState(KeyboardRunState.class).setEnabled(true);
        return true;
    }
    
    @NiftyEventSubscriber(id="login")
    public void onClick(String id, NiftyMousePrimaryClickedEvent event) {
        System.out.println("element with id [" + id + "] clicked at [" + event.getMouseX() + ", " + event.getMouseY() + "]");
        
        nifty.gotoScreen("hud");
        getState(KeyboardRunState.class).setEnabled(true);
    }
    
}

Okay, so a few things here.

First. Nifty mouse clicking can be a little weird in how it detects clicks. If you want to capture “every” click, you really need to use onRelease not onClick. There is a slight delay after a click has been detected that it won’t detect another one where onRelease will catch it every time.

Second, i’ve actually stepped through the nifty code for that exact exception before. I can’t remember all the specifics (it’s been probably 2 years). Try renaming the methods in your test control first… I know the textfield control has two methods with that name so my guess is that it is trying to call onClick and it sees the method on your top controller and then you get that error. Otherwise… you would have to step through the code.

Changing to onRelease fixed the problem with textfield throwing an exception.

That didn’t help with the button missing the ButtonClickedEvent. I narrowed it down to clicking on the button text label though. Clicking on the button body works as expected but if I click on the second character O in the word Login, the ScreenController doesn’t get notified of the ButtonClickedEvent. This happens for any character I use.

Edit: Tried changing the text and still get same problem. Its not just the second char. It can be several chars but its the label that’s causing the problem. Anyone else seeing this with their buttons?

Figured it out.

When testing Lemur I had added a mouse event listener to a node and forgot to remove it.

Thanks for your input @glh3586.

Edit: To clarify what was happening, since this is testing, I load the character without a login and it was standing in the exact spot of the nifty screen button. So when I clicked on the button in GUI in that exact spot, jme was getting the event first. Once things are configured properly it wouldn’t of happened but just started implementing this stuff.

1 Like