Nifty TextField causing render IllegalStateException

I’m currently working on the HUD for my game but I’ve run into an issue. I’m trying to add a textfield to it but as soon as I try to get into the game (as soon as it tries to switch to the hud screen) it crashes and gives this error:

java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call. 
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node

I can’t figure out why the textfield wouldn’t be working. I haven’t put in any code for it yet, it only exists in the xml file. It did work earlier when I first added it to the xml but when I added more to the hud this started happening so I removed what I added and it was still happening so I narrowed it down to this textfield. I don’t know why that would be the case and it really makes me clueless as to what to even do.

heres the relevant XML:

	<layer id="foreground" backgroundColor="#0000" childLayout="absolute">
		<panel id="bottom_bar" x="30.625%" width="38.75%" y="90%" height="10%" childLayout="horizontal" backgroundColor="#aaaf">
			<panel id="slot_1" width="25%" childLayout="absolute" backgroundColor="#faaa">
				<panel id="s1_d" x="0%" width="20%" y="0" height="100%" childLayout="center" backgroundColor="#444f">
					<text font="assets/guis/fonts/aurulent-sans-16.fnt" color="#cccf" text="&lt;" align="center" valign="center" />
					<interact onClick="decrease(1)" />
				</panel>
				<panel id="s1_key" x="20%" width="60%" y="0" height="25%" childLayout="center" backgroundColor="#555f">
					
				</panel>
				<panel id="s1_count" x="20%" width="60%" y="25%" height="75%" childLayout="center" backgroundColor="#666f">
					<!---THIS IS WHATS BREAKING IT--->
					<control name="textfield" id="s1_count_text" text="" />
					<!------------------------------->
				</panel>
				<panel id="s1_i" x="80%" width="20%" y="0" height="100%" childLayout="center" backgroundColor="#444f">
					<text font="assets/guis/fonts/aurulent-sans-16.fnt" color="#cccf" text="&gt;" align="center" valign="center" />
					<interact onClick="increase(1)" />
				</panel>
			</panel>
		</panel>
		
	</layer>

If there’s any other code that might be relevant just let me know. All of the methods in the HudScreen class are empty, including increase() and decrease() (for now).

How are you switching to the hud screen? Where are you calling that?

Edit: because note that the error you provided indicates the you are modifying the 3D scene outside of the normal update loop and it’s hard to see from here why that would have anything to do with a nifty screen which will be in its own viewport and not normally affect the root node.

in start.xml i have a button:

<control name="button" label="Start" id="startButton" align="center" valign="center">
	<interact onClick="startGame()" />
</control>

startGame in the start screen controller:

public void startGame() {
	Application app = getApplication();
	if (app instanceof ClientMain) {
		((ClientMain)app).startGame();
	}
}

startGame() in ClientMain:

public void startGame() {
	try {
		client = Network.connectToServer("FirstGame", 1, "localhost", 6100, 6101);
		client.start();
		client.addMessageListener(this);
		
		setupInput();
		
		//where the actual screen switching happens
		nifty.gotoScreen("hud");
		
		//setDisplayFps(false);
	} catch (IOException e) {
		e.printStackTrace();
		app.stop();
	}
}

setting up the GUIs (called first thing in simpleInitApp()):

public void createGuis() {
	NiftyJmeDisplay niftyDisplay = NiftyJmeDisplay.newNiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
	nifty = niftyDisplay.getNifty();
	
	try {
		nifty.validateXml("assets/guis/start.xml");
		nifty.validateXml("assets/guis/hud.xml");
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	nifty.fromXml("assets/guis/start.xml", "start");
	
	nifty.registerScreenController(new HudScreen());
	nifty.addXml("assets/guis/hud.xml");
	
	start = (StartScreen) nifty.getScreen("start").getScreenController();
	hud = (HudScreen) nifty.getScreen("hud").getScreenController();
	hud.setClientMain(this);
	stateManager.attachAll(start, hud);
	
	guiViewPort.addProcessor(niftyDisplay);
}

I see how this is relevant but at the same time it works perfectly fine if i just comment out the <control name=“textfield”… /> element

FYI: How to type code blocks

But that seems unlikely… at best a coincidence… or there is some other method being called that is modifying the main scene graph.

The error indicates that some child of rootNode has been modified outside of the normal update pass. Either because you are modifying things from your network listeners or maybe because you are modifying them from your GUI controller and it happens at the wrong time somehow (very strange if so).

When I see code like the above, my first instinct is to blame it on network message listeners since the messages come on a different thread and the listeners must never ever ever do anything directly with the scene graph.

Thanks for that about the code blocks. I’ll use the backticks from now on.

If this is a coincidence I must be extremely unlucky. I think there must be some behind the scenes weird interaction or something, because I just created the hud gui today and haven’t added anything that depends on any of the functionality of the game. Everything has been working just fine and I haven’t changed anything regarding what was there before i created the hud gui. It shouldn’t be any of the network stuff because it all worked perfectly fine, and like I said, the hud isn’t connected to my code yet, much less anything that has to do with network messages/information from them. I literally have the bare minimum to just draw it with xml.

Is there some behind the scene code that is breaking it because it tries to do something funky to the stuff behind it when trying to render it? is there some weird corner of the code thats causing issues with text input? I know earlier when it was working, all of my keyboard input was being rerouted to the textfield instead of in game controls and i couldn’t “deselect” the textfield but i figured I’d deal with that later. I don’t think thats related but I just don’t know where else to look for related details.

It could be a timing issue. As far as I know, nifty can’t do anything to modify the root node.

If you have network listeners, try not adding them and see if it fixes this issue.

999 times out of 1000 in networking cases, these errors are caused by bad message listeners that modify the scene graph directly.

IMPORTANT SAFETY NOTE: if you are modifying the scene graph directly from message listeners then that’s a bug. Whether or not you see an error ‘today’ or not, it’s still a bug. You should never ever ever ever (99 evers) do it. As in never. not once. Not 0.1 times.

So if you have network code, please double check that you aren’t accessing the scene graph from it.

Edit: because eventually you WILL see a bug. Randomly, based on timing, etc… you are accessing the scene graph badly if you do this.

well it turns out I just am the unluckiest person. I sat there and tried running it randomly commenting/uncommenting the textfield, and the very last time, out of nearly twenty runs where it went exactly how i thought it should of based on whether it was commented or not, it actually didnt crash when I thought it should have. I checked my message listeners and it turned out i had a single misplaced bracket that was causing my rootNode.attachChild(text); to not be inside of the enqueue(). its working 100% of the time now. unbelievable. I wish that luck could have gone to something better. Sorry for wasting your time but i think given the evidence my conclusions were reasonable. Thanks though. I still can’t believe how unlucky i was getting.

2 Likes

Sure they were reasonable. That’s why we need a second set of eyes. :slight_smile:

The code wouldn’t allow for your hypothesis so I had to harp on the real most likely cause… and that’s the painful part about timing issues.

In retrospect, it’s quite amazing that adding a text field was a consistent enough timing adjuster to consistently cause the problem somewhere completely unrelated.

1 Like