Nifty and networking

Hello everybody :slight_smile:

I have a serious issue with Nifty: I have a basic authentication panel, that sends the name to a server that checks if it’s available or not. Problem: I often get a null pointer exception right after I click on the submit button. Has anyone an idea on what is wrong here…? In advance, thanks for your time and your answers XD

Sources:

[java]

private ListBox<String> faction_alliance;
private ListBox<String> faction_rebelle;

public void sendName() {
login = nifty.getScreen(“connect”).findNiftyControl(“login”, TextField.class).getText();
NameMessage message = new NameMessage(login, true); //sends the login and a boolean. If the name is available, the server sends back the
game.getClient().send(message); //message without editing it. If it’s not, the server sets the boolean to false and a popup appears
}

public void messageReceived(Client source, final Message m) {
    
    if(m instanceof NameMessage) {
        NameMessage message = (NameMessage) m;
        if(message.getOk() == true) {
            factionPanel();
            FactionMessage fa = new FactionMessage();  //sends a message to the server to get current players. If there are no players, the client doesn't get any answer
            game.getClient().send(fa);
        }
        else if (message.getOk() == false) {
            createMyPopupMenu("Name already in use");
            nifty.showPopup(nifty.getCurrentScreen(), popup.getId(), null);
        }
    }
    
    if (m instanceof FactionMessage) {
        FactionMessage message = (FactionMessage) m;
        System.out.println("message received " + message.getName());
        if(nifty.isActive("Interface/accueil.xml", "choice_faction")) {
            if(message.getFaction() == 1) {
                faction_alliance.addItem(message.getName());    //Answers of the server if there are players actually playing. Their names are added to the ListBox of their faction
            }
            else if(message.getFaction() == 2) {
                faction_rebelle.addItem(message.getName());   //Same process
            }
        }
    }
}

public void factionPanel() {
    nifty.gotoScreen("choice_faction");
    faction_alliance = nifty.getCurrentScreen().findNiftyControl("listBoxStatic1", ListBox.class); //adds 2 ListBox to the screen (empty if there are no players)
    faction_alliance.addItem("Alliance");
    faction_rebelle = nifty.getCurrentScreen().findNiftyControl("listBoxStatic2", ListBox.class);
    faction_rebelle.addItem("Rebelle");
}[/java]

And the XML:

[java]
<screen id=“connect” controller=“mygame.NiftyGui”>
<layer id=“background” backgroundImage=“Interface/gui-background.png”>
</layer>
<layer id=“log” childLayout=“vertical”>

    &lt;panel id="panel1" height="60%" width="50%" align="center" valign="center" childLayout="center"&gt;  
       &lt;text text="Login" font="Interface/Fonts/Default.fnt" width="50%" height="50%" wrap="false" color="#FF1302"/&gt;
   &lt;/panel&gt;
    
    &lt;panel id="panel2" height="-10%" width="100%" valign="center" childLayout="center"&gt;  
        &lt;control name="textfield" id="login" width="15%" /&gt;
   &lt;/panel&gt;
    
   &lt;panel id="panel3" height="30%" width="100%" valign="center" childLayout="center"&gt;  
        &lt;control name="button" label=" Submit " id="submit" align="center" valign="center" visibleToMouse="true"&gt; 
        &lt;interact onClick="sendName()"/&gt;
        &lt;/control&gt;
   &lt;/panel&gt;
   
&lt;/layer&gt;     

</screen>

//////////////////////////////////////////////////////////////////////////////

&lt;screen id="choice_plane" controller="mygame.NiftyGui"&gt;
&lt;layer id="background" backgroundImage="Interface/gui-background.png"&gt;
&lt;/layer&gt;
 

 &lt;layer id="couche1" childLayout="vertical" &gt;
    &lt;panel id="panel_top" height="80%" width="100%" valign="center" childLayout="center"&gt;  
      &lt;control name="button" label="Avion 1" id="plane1" align="center" valign ="center" visibleToMouse="true" &gt; 
        &lt;interact onClick="choicePlane(p1)"/&gt;
        &lt;/control&gt; 
    &lt;/panel&gt;
    &lt;panel id="panel_top" height="-40%" width="100%" valign="center" childLayout="center"&gt;  
      &lt;control name="button" label="Avion 2" id="plane2" align="center" valign ="center" visibleToMouse="true" &gt; 
        &lt;interact onClick="choicePlane(p2)"/&gt;
        &lt;/control&gt; 
    &lt;/panel&gt;
  &lt;/layer&gt;  
    &lt;layer id="couche2" childLayout="vertical" &gt;
     &lt;panel id="panel_bottom_left" height="60%" width="40%" valign="center" childLayout="center"&gt;  
        &lt;image filename="Interface/pyramid.jpg" height="190px" id="image1" width="199px" /&gt;
    &lt;/panel&gt;
     &lt;panel id="panel_bottom_right" height="20%" width="40%" valign="center" childLayout="center"&gt;  
        &lt;image filename="Interface/cube.jpg" height="190px" id="image2" width="199px" /&gt;
    &lt;/panel&gt;    
 &lt;/layer&gt;

&lt;/screen&gt;

[/java]

Finally, the error:

[java]
SEVERE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]
java.lang.NullPointerException
at de.lessvoid.nifty.elements.Element.canHandleInteraction(Element.java:1474)
at de.lessvoid.nifty.elements.Element.mouseEvent(Element.java:1405)
at de.lessvoid.nifty.screen.MouseOverHandler.processMouseEvent(MouseOverHandler.java:101)
at de.lessvoid.nifty.screen.Screen.forwardMouseEventToLayers(Screen.java:360)
at de.lessvoid.nifty.screen.Screen.mouseEvent(Screen.java:336)
at de.lessvoid.nifty.Nifty.forwardMouseEventToScreen(Nifty.java:266)
at de.lessvoid.nifty.Nifty.access$1400(Nifty.java:73)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processEvent(Nifty.java:1370)
at de.lessvoid.nifty.Nifty$NiftyInputConsumerImpl.processMouseEvent(Nifty.java:1329)
at com.jme3.niftygui.InputSystemJme.onMouseMotionEventQueued(InputSystemJme.java:186)
at com.jme3.niftygui.InputSystemJme.forwardEvents(InputSystemJme.java:258)
at de.lessvoid.nifty.Nifty.update(Nifty.java:248)
at com.jme3.niftygui.InputSystemJme.endInput(InputSystemJme.java:113)
at com.jme3.input.InputManager.processQueue(InputManager.java:821)
at com.jme3.input.InputManager.update(InputManager.java:885)
at com.jme3.app.Application.update(Application.java:606)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:230)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:185)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:228)
at java.lang.Thread.run(Thread.java:722)
[/java]

Wow… That’s a massive post, sorry :smiley:

Well, one thing is that network messages are received on a non-rendering thread (assuming you are using SpiderMonkey)… so it is probably not safe to modify GUI elements directly. (I assume nifty has the same restrictions as JME in this regard.)

<cite>@pspeed said:</cite> Well, one thing is that network messages are received on a non-rendering thread (assuming you are using SpiderMonkey)... so it is probably not safe to modify GUI elements directly. (I assume nifty has the same restrictions as JME in this regard.)

I know it (thanks to the tutorials !). But it doesn’t seems to be a problem of update by an other thred: when I don’t get the excepetion (3 out of 4 times), the ListBox is properly updated. I really don’t get why it crashes 1 out of 4 times…

Well, threading problems will appear to be random since one thread is messing with the data of another thread at odd times. I can see a bunch of code that will cause problems in what you posted.

You will need to fix those anyway… and they may make your problem go away.

<cite>@pspeed said:</cite> I can see a bunch of code that will cause problems in what you posted.

Could you help me and point out what is wrong in the code ?

In all of those places, you are potentially making the state of nifty invalid by changing things from a non-rendering thread. If you want to change the UI from a network message handler then you have to enqueue a callable or some other interthread communication. There is already a wiki page on this.

Well, I use it with others messages (when shooting or moving planes), I’ll make I try and confirm later if the problem was it (I want to be sure to give a straight answer…)

Thanks for your time :amused:

Well, after many tests, it seems that you were right ! The problem was caused by the separated threads. Many Thanks for your quick answer, it was really helpful !

Edit: the final code (or particulary the modified code):

[java]
public void messageReceived(Client source, final Message m) {

    if(m instanceof NameMessage) {
        NameMessage message = (NameMessage) m;
        if(message.getOk() == true) {
            game.enqueue(new Callable() {
                public Object call() throws Exception {
                    factionPanel();
                    FactionMessage fa = new FactionMessage();
                    game.getClient().send(fa);
                    return null;
                }
            });
        }
        else if (message.getOk() == false) {
            game.enqueue(new Callable() {
                public Object call() throws Exception {
                    createMyPopupMenu("Nom déjà utilisé");
                    nifty.showPopup(nifty.getCurrentScreen(), popup.getId(), null);
                    return null;
                }
            });
        }
    }
    
    if (m instanceof FactionMessage) {
        final FactionMessage message = (FactionMessage) m;
        game.enqueue(new Callable() {
            public Object call() throws Exception {
                if(nifty.isActive("Interface/accueil.xml", "choice_faction")) {
                    if(message.getFaction() == 1) {
                        faction_alliance.addItem(message.getName());
                    }
                    else if(message.getFaction() == 2) {
                        faction_rebelle.addItem(message.getName());
                    }
                }
                return null;
            }
        });
    }
}[/java]