(sim-eth-es) questions digest

(I think I have to start this one, as I feel I’ll have more along the way)

Why were physics system listeners put in SafeArrayList? Isn’t it a bit overkill?

1 Like

I dont know why I have the permission, but I removed the ‘dumb’ from the title :smiley:

Edit: That actually feels very invasive of sorts

1 Like

I wanted to leave some excuse for myself… you ruined it(( :wink:

1 Like

What do you suggest as an alternative that allows iteration without creating an iterator?

2 Likes

Hmm well as far as I see, it’s created and populated once, you never modify it during game session itself, so why not just ArrayList?
p.s. and yes, I checked it, it doesn’t break in fact with ArrayList

1 Like

And how did you iterate over the array list?

1 Like
// for( PhysicsListener l : listeners.getArray() ) 
for( PhysicsListener l : listeners ) 
{
    l.removeBody(body);
}
1 Like

That is creating an iterator. To iterate over the arraylist without creating a new iterator you must go with the for(int i....) alternative (which has lots of checks and it is way slower than an array iteration). However, the SafeArrayList provides the getArray() without recreating that array on each call and allowing the fastest iteration.
Edit: If you are not constantly modifying the collection and the main purpose of it is to get iterate over (which seems to be the case), that’s the most efficient and gc-friendly solution.

3 Likes

Thank you, sirs. That wasn’t immediately obvious from SafeArrayList javadoc, though I should assume that from “without creating” words. Need to improve my java obviously.

1 Like

Well, any collection that can be iterate with the for(Object obj : collection) syntax is because it implements the java.lang.Iterable interface (with the exception of native arrays), which means that it is just asking for the iterator() method on that object. That method is very likely creating a new Iterator every time you call it (it is the default behavior and that’s why it isn’t explicitly mentioned in the javadoc).

2 Likes

And anyway, there is no real down side to using SafeArrayList over ArrayList in most use cases.

For listener lists there are a few advantages, though. One being that it is easy to iterate over the list garbage-free… the other being that listeners can modify the list (ie: remove themselves or add new listeners) without issue. That’s not true for ArrayList and comes up quite often with listeners.

Edit: so you will find I will default to using SafeArrayList for any listeners anywhere if the project is already depending on JME.

2 Likes

Question #2:

If I use dome shape in model view state on client side with

hemisph.setMode(Mesh.Mode.LineLoop);

it’s shown as expected, but when I’m pressing Esc, instead of a menu I’m getting exception:

13:26:07,177 ERROR [LegacyApplication] Uncaught exception thrown in Thread[jME3 Main,5,main]
java.lang.IndexOutOfBoundsException
	at java.nio.Buffer.checkIndex(Buffer.java:540) ~[?:1.8.0_111]
	at java.nio.DirectShortBufferU.get(DirectShortBufferU.java:253) ~[?:1.8.0_111]
	at com.jme3.scene.mesh.IndexShortBuffer.get(IndexShortBuffer.java:53) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.mesh.WrappedIndexBuffer.get(WrappedIndexBuffer.java:80) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.collision.bih.BIHTree.initTriList(BIHTree.java:96) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.collision.bih.BIHTree.<init>(BIHTree.java:135) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.collision.bih.BIHTree.<init>(BIHTree.java:139) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Mesh.createCollisionData(Mesh.java:966) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Mesh.collideWith(Mesh.java:995) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Geometry.collideWith(Geometry.java:450) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Node.collideWith(Node.java:611) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Node.collideWith(Node.java:611) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.scene.Node.collideWith(Node.java:611) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.simsilica.lemur.event.PickEventSession.cursorMoved(PickEventSession.java:467) ~[lemur-1.9.1.jar:?]
	at com.simsilica.lemur.event.MouseAppState.dispatchMotion(MouseAppState.java:93) ~[lemur-1.9.1.jar:?]
	at com.simsilica.lemur.event.BasePickState.update(BasePickState.java:169) ~[lemur-1.9.1.jar:?]
	at com.jme3.app.state.AppStateManager.update(AppStateManager.java:287) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:236) ~[jme3-core-3.1.0-stable.jar:3.1-stable]
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.runLoop(LwjglAbstractDisplay.java:151) ~[jme3-lwjgl-3.1.0-stable.jar:3.1-stable]
	at com.jme3.system.lwjgl.LwjglDisplay.runLoop(LwjglDisplay.java:193) ~[jme3-lwjgl-3.1.0-stable.jar:3.1-stable]
	at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:232) ~[jme3-lwjgl-3.1.0-stable.jar:3.1-stable]
	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_111]

I wonder why?

1 Like

I think the problem is actually only for android because we have escape analysis on the HotSpot.

1 Like

Yes and no.
current JME is way better than older JME2 version the first few seconds, due to modifications like this.

The older one would need several seconds before the frame rate got stable and faster. Producing code that runs more efficiently without escape analysis already reduces the burden on the JIT quite significantly allowing better initial performance.

1 Like

Yeah, a for-each style iteration over an array is going to be way faster right from the start. No iterator creation, no bounds checking per element, etc…

Escape analysis only gets you so far.

When possible, iterate over arrays. Seriously… it makes a difference for anything you will do a lot.

2 Likes

I guess JME’s dome has issues and isn’t pickable. So when you hit escape to open the menu and Lemur starts trying to do collideWith() on the scene graph then you see these bugs in JME code.

You can either extend that Mesh to not be pickable (or the geometry that holds it)… currently the only way to avoid picking on an object in JME.

…or you can segregate your scene graph into pickable and not pickable subgraphs (can be a pain)… and then modify how the main scene is registered with Lemur’s picking to only include the pickable root.

…or if you will never pick in the 3D scene then you can remove it from Lemur’s consideration.

For either of those last ones, you will want to look here:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/event/BasePickState.html#removeCollisionRoot(com.jme3.renderer.ViewPort)

And possible here:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/Lemur/com/simsilica/lemur/event/BasePickState.html#addCollisionRoot(com.jme3.scene.Spatial,%20com.jme3.renderer.ViewPort)

2 Likes

Question #3:

If I have some platform with guns mounted on strictly defined joints (i.e. their relative locations against platform’s pivot point never change during their lifetime, only orientations do), it looks reasonable not to publish whole Positions to client, just orientations. Then the client, knowing the parent structure dimensions, will position them properly and thus I can save some network throughput. But, when dealing with ZoneManager, I have to submit positions there as well. Should I just calculate them prior to do that, or should I dig deeper and consider some changes to ZoneManager itself? Won’t there be unnecessary duplication (or rather multiplication) of work somewhere if I will calculate whole Position for every fixed-to-parent entity?

1 Like

If the position doesn’t change the SimEthereal sends that as just one bit.

Is that bit what you are worried about avoiding? Seems like a lot of work just to get around sending 1 extra bit, to me.

Edit: or are you publishing the world position instead of the local position?

Yeah, there is a parent-child relationship built into sim-ethereal but I don’t think I ever finished it. Still, you may want to wait until it’s a problem. Even a moving position is pretty small, bitwise.

2 Likes

So looks like the easiest way would be to transfer all entities as plain local, and leave that to client to properly assemble them based on ChildOf → ChildOf → … → parent trace.

1 Like

That’s the idea… but currently the issue is that the zone manager will see your object as in some other zone near 0, 0, 0. It’s the part of the parent->child thing that wasn’t implemented yet.

1 Like