How to inlcude messages received via network (SpiderMonkey) into game?

Hi,



I am receiving shot coordinates (mouse position x:y) over the network via Spidermonkey (code sample 1)

I also have a function that calculates a Ray on some objects that I want to shoot (code sample 2)



My question:

What is the best way to call this function (code sample 2) when new coordinates Message arrives and triggers the MessageListener?



When I call the shoot function from an ActionListener with onAction() method with [java]shoot(inputManager.getCursorPosition());[/java] it works fine.



However I just don’t know how to code it with the input from the MessageListener, so that it works with the data received via the network. Maybe is it not a good idea to have the MessageListener as an inner class in the game?



Do I need to put this method or the data into an ‘enqueue’ to make it thread safe, as it comes from a SpiderMonkey Message? If so, what is a good way?

An Arraylist with the data and then call the shoot method in the simpleUpdate method? like this?



[java]public void simpleUpdate(float tpf) {

player.rotate(1tpf, 0.5ftpf, 0.5f*tpf);



try {

Vector2f shot;

Iterator i = shotVector.iterator(); // Must be in synchronized block

while (i.hasNext()) {

shot = (Vector2f)(i.next());

shoot(shot);

}



} catch (Exception e) {

// handle somthing

}

}

[/java]



It would be very nice if you could help me.



Many thanks!

Marc











code sample 1:

[java]

private static class ShotClientListener implements MessageListener<Client> {

public void messageReceived(Client source, Message message) {

if (message instanceof ShotMessage) {



ShotMessage shot = (ShotMessage) message;



// create new Vector with X and Y coords received via network

Vector2f shot2d = new Vector2f((float)shot.getX(), (float)shot.getX());



}

}

}

[/java]





code sample 2:



[java]

public void shoot(Vector2f coords) {



CollisionResults results = new CollisionResults();

Vector2f click2d = coords;



System.out.println(“Shooting at: " + coords.x + “|” + coords.y);



Vector3f click3d = cam.getWorldCoordinates(

new Vector2f(click2d.x, click2d.y), 0f).clone();

Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d);

Ray ray = new Ray(click3d, dir);





// 3. Collect intersections between Ray and Shootables in results list.

shootables.collideWith(ray, results);

// 4. Print the results

System.out.println(”


Collisions? " + results.size() + "
");
for (int i = 0; i < results.size(); i++) {
// For each hit, we know distance, impact point, name of geometry.
float dist = results.getCollision(i).getDistance();
Vector3f pt = results.getCollision(i).getContactPoint();
String hit = results.getCollision(i).getGeometry().getName();
System.out.println("* Collision #" + i);
System.out.println(" You shot " + hit + " at " + pt + ", " + dist + " wu away.");

shootables.detachChild(results.getCollision(i).getGeometry());

}
// 5. Use the results (we mark the hit object)
if (results.size() > 0) {
// The closest collision point is what was truly hit:
CollisionResult closest = results.getClosestCollision();
// Let's interact - we mark the hit with a red dot.
mark.setLocalTranslation(closest.getContactPoint());
rootNode.attachChild(mark);
} else {
// No hits? Then remove the red mark.
rootNode.detachChild(mark);
}

}
[/java]

Problem solved!



I am writing the incoming coordinates into a syncronized Arraylist which is then called in the simpleUpdate() method…



[java] static final List<Vector2f> shotVector2d = Collections.synchronizedList(new ArrayList(100));

[/java]



The MessageListener:



[java]private static class ShotClientListener implements MessageListener<Client> {

public void messageReceived(Client source, Message message) {

if (message instanceof ShotMessage) {



ShotMessage shot = (ShotMessage) message;



// create new Vector with X and Y coords received via network

Vector2f shot2d = new Vector2f((float)shot.getX(), (float)shot.getY());

synchronized(shotVector2d) {

shotVector2d.add(shot2d);

}

}

}

}[/java]



And then call in simpleUpdate():



[java]@Override

public void simpleUpdate(float tpf) {



// triggers the shooting method to calculates the shot intersections

synchronized(shotVector2d) {

for (int i=0; i<shotVector2d.size(); i++) {

shoot((Vector2f)shotVector2d.get(i));

}

shotVector2d.clear();

}

}[/java]





Maybe someone can use this…

You will have better performance and can remove the heavy-handed “synchronized” if you switch to a java.util.concurrent.ConcurrentLinkedQueue. Add the items in the listener and drain them (poll until null) in the update.



This also gives you the opportunity to bail out early if there are too many updates and just catch the rest on the next pass. I mean as a general approach and not in this case specifically. In this case, you’d always want to fully drain, I suspect.