ArrayIndexOutOfBoundsException while updating

Hi guys,

I keep getting the following exception and can’t find the reason:

SCHWERWIEGEND: Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.ArrayIndexOutOfBoundsException: 69
at com.jme3.util.SafeArrayList.get(SafeArrayList.java:258)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:683)
at com.jme3.renderer.RenderManager.renderSubScene(RenderManager.java:683)
at com.jme3.renderer.RenderManager.renderScene(RenderManager.java:662)
at com.jme3.renderer.RenderManager.renderViewPort(RenderManager.java:1019)
at com.jme3.renderer.RenderManager.render(RenderManager.java:1078)
at com.jme3.app.SimpleApplication.update(SimpleApplication.java:260)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:152)
at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:192)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:233)
at java.lang.Thread.run(Thread.java:745)

This happens randomly at any point while I am running the game, either directly after starting, while loading the scene or when I am just floating around with the camera over my scene. Sometimes I do not get an exception but the game is freezing and the only way to get out is killing the process. I do only use mutlithreading at one point and the exception does also happen when I disable the feature (the minimap btw). So that does not seem to be the reason.

I have absoluetly no idea where this may come from and would be happy on any suggestions…

Thanks in advance :slight_smile:

Multithreading. Has to be. Check again.

What are you using for the UI? Do you use Swing? JavaFX?

You are running an older version of JME but if I extrapolate:

Somehow the size of the list changes between these two lines… ergo: multithreading.

It cannot be else.

Edit: unless you’ve foolishly extended Node and have done something strange.

Hi and thanks for your answers,

@normen
I am using the built in nifty gui.

@pspeed
The node where this happens is a normal node that is holding the buildings (only trees right now). This game is my first serious try with networking, the server is sending messages when a new building should be attached to the node. I had an eye on that, the messages are stored in a list until the next update call and are added then to avoid changing the scene when it shouldn’t be changed but I guess I might have done anything wrong there… I am gonna check it again and tell you if I found something

Why reinvent the wheel?

http://javadoc.jmonkeyengine.org/com/jme3/app/Application.html#enqueue(java.util.concurrent.Callable)

9 times out of 10 people invent the wheel wrong again anyway. Like, what kind of ‘list’ is your list?

An ArrayList… Actually I decided to rewrite that part so thanks for the suggestion :wink:

Which is not at all thread safe and the worst way to do ‘queued’ communication. (hint heavily in the word ‘queued’.)

I do not envy you. Network programming without any threading experience is like trying to learn to shoot a gun as the bear is coming towards you.

Haha, thank you for that hint. I should say I never professionally “learned” programming, it’s just a hobby so I probably might do some bullshit… I am going to rewrite the message handling with Callables (I did hardly use before…)
Any suggestions what I should definetely have an eye on?

Too many things.

But definitely go through the wiki.

For example: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:multithreading

Are there any Thread Safe List Implementations?
I guess they aren’t part of the JRE and come with apache commons, guava or something comparable?

And @Smire: Only the SceneGraph changes using Callable, most of it can be done in the network thread

See: java.util.concurrent and the 5.36 million articles in google.

1 Like

I worked with the Callables for my minimap, I guess I might transfer it now. Thank you for the suggestions.

I love you all :smiley: I do now work with Callables to handle the messages and they 1) Are much faster and 2) I could remove everything to make it Thread safe and it still works… My code looks so much better now^^

Hi again,

I keep having the same issue, even after reconstructing the whole process of adding buildings…

I found the source of the problems (if I comment it out the don’t occur) but I have no idea what I am doing wrong:

/**
 * Adds a building to the scene
 * @param bc The BuildingCreator
 * @throws java.lang.Exception if the building could not be added
 */
public void addBuilding(final BuildingCreator bc) throws Exception{
    if(bc != null && map != null && this.app.getBuildingNode() != null){    //Do not add if the game has not finished loading yet   
        final Spatial building = bc.createBuilding(app.getAssetManager());  //Load the building (just preparing the spatial)

        building.addControl(new HeightControl(app.getClientMap()));         //Add a control to adjust the height to the terrain if it is changed
    
        this.app.enqueue(new Callable<Spatial>() {                          

            @Override
            public Spatial call() throws Exception {
                app.getBuildingNode().attachChild(building);                //HERE IS WHERE THE EXCPETION HAPPENS!
                return building;
            }
        });
    } 
}

The scene is not modified anywhere else.
Please help me, I don’t know what else to do… :frowning:

Is addBuilding() called from another thread?

Why? (ie: why not wrap the whole addBuilding() body in the enqueue?)

What is the latest exception? Stack traces are important.

What does createBuilding() do?

If that line is truly where the exception is happening (hard to tell without a stack trace) then you still have another thread somewhere modifying the scene graph.

If this code is being called from a separate thread then the following line is bad because it is accessing a global non-thread-safe data member. At best it is suspicious. Don’t know get getBuildingNode() is doing so it’s hard to say.

Looks wrong, though.

Hi,

Is addBuilding() called from another thread?

addBuilding() is called when the client receives the message from the server that a building should be added. The message contains the BuildingCreator that stores the data (type of the building, position, rotation).

What does createBuilding() do?

CreateBuilding() creates a new spatial and adds the model (depending on the type) and sets it’s localRotation and LocalTranslation.

Why? (ie: why not wrap the whole addBuilding() body in the enqueue?)

I did wrap the whole stuff in the enqueue before but had the same problem so I thought it was better to take it out since the rest is not changing the scene graph.

Looks wrong, though.

I do also not like that line :confused: I had the problem that the messages with the buildings came too early sometimes and I got NullPointers because the game did not finish loading. I still get the IndexOutOfBoundsException if I take it out so it can’t be the problem. getBuildingNode() just returns the node buildings are attached to. I wanted to shorten
“((Node)getRootNode().getChild(“buildings”))”
, it does exactly the same.

If that line is truly where the exception is happening (hard to tell without a stack trace) then you still have another thread somewhere modifying the scene graph.

I get no exception if I comment that one line (and only that line) out. Also I did usage searches for every attachChild() and detachChild() usage and none of them can be called here.
Another thing I just realized: It only happens if I add a large amount of buildings the same time. Single buildings are no problem. Do you think that could be the reason or is it just that the chances to have a simultan modification somewhere else are (of course) much higher with more buildings?

Here is the latest exception. I tried catching it since it would not be a problem to have buildings not added because they are requested again later but then I get the exception while rendering you see in my first post. The Indeces are always different what would support my theory why the chance to get the exception is higher with more buildings.

 java.lang.IndexOutOfBoundsException: Index: 152, Size: 151
	at java.util.ArrayList.rangeCheckForAdd(ArrayList.java:661)
	at java.util.ArrayList.add(ArrayList.java:473)
	at com.jme3.util.SafeArrayList.add(SafeArrayList.java:269)
	at com.jme3.scene.Node.attachChildAt(Node.java:346)
	at com.jme3.scene.Node.attachChild(Node.java:321)
	at leader.game.ClientGraphicAppState$1.call(ClientGraphicAppState.java:150)
	at leader.game.ClientGraphicAppState$1.call(ClientGraphicAppState.java:146)
	at com.jme3.app.AppTask.invoke(AppTask.java:142)
	at com.jme3.app.Application.runQueuedTasks(Application.java:667)
	at com.jme3.app.Application.update(Application.java:681)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:234)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:152)
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:192)
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:233)
	at java.lang.Thread.run(Thread.java:745)

Thank you for your time btw :wink:

This will cause an exception if you call it while the main thread is attaching things to the root node. Or it may cause the other thread to throw an exception. It’s not thread safe so don’t call it from another thread.

You error is 100000% caused by accessing the scene graph from multiple threads. So don’t do that. Then repeat.

No you cannot even GET things (like getNodes()) from another thread. Don’t do it. Just don’t. Eliminate all cases where you access the attached scene graph (root node on down) from another thread and then your problem will go away.

I put the whole task back in the enqueue and WOOSH it works! :smiley:

I don’t know why I got the exception before I took it out but I guess I had something similar elsewhere…
I will have an eye on that now. You never stop learning :smile:

Thank you very much for your help, I guess I would have never figured it out alone!

1 Like