Sending Geometry through a message

Like the title says, i wanna know if it is possible doing this thing because I tryed to do that but i get an error and don’t know if it is cause by the impossibility of serializing a Geometry object.



The error is:



4-set-2011 22.08.33 com.jme3.network.serializing.serializers.FieldSerializer writeObject

AVVERTENZA: [FieldSerializer][???] Exception occurred on writing. Maybe you’ve forgotten to register a class, or maybe a class member does not have a serializer.

4-set-2011 22.08.33 com.jme3.network.base.DefaultClient handleError

GRAVE: Termining connection due to unhandled error

java.lang.RuntimeException: Error serializing message

at com.jme3.network.base.MessageProtocol.messageToBuffer(MessageProtocol.java:83)

at com.jme3.network.base.DefaultClient.send(DefaultClient.java:213)

at com.jme3.network.base.DefaultClient.send(DefaultClient.java:193)

at it.mygame.network.ClientNetListener.clientConnected(ClientNetListener.java:37)

at com.jme3.network.base.DefaultClient.fireConnected(DefaultClient.java:306)

at com.jme3.network.base.DefaultClient.dispatch(DefaultClient.java:348)

at com.jme3.network.base.DefaultClient$Redispatch.messageReceived(DefaultClient.java:371)

at com.jme3.network.base.ConnectorAdapter.dispatch(ConnectorAdapter.java:131)

at com.jme3.network.base.ConnectorAdapter.run(ConnectorAdapter.java:173)

Caused by: com.jme3.network.serializing.SerializerException: Error writing object

at com.jme3.network.serializing.serializers.FieldSerializer.writeObject(FieldSerializer.java:184)

at com.jme3.network.serializing.Serializer.writeClassAndObject(Serializer.java:374)

at com.jme3.network.base.MessageProtocol.messageToBuffer(MessageProtocol.java:75)

… 8 more

Caused by: java.lang.IllegalArgumentException: Class has not been registered:class com.jme3.scene.Geometry

at com.jme3.network.serializing.Serializer.getSerializerRegistration(Serializer.java:308)

at com.jme3.network.serializing.Serializer.getSerializerRegistration(Serializer.java:277)

at com.jme3.network.serializing.Serializer.writeClass(Serializer.java:352)

at com.jme3.network.serializing.Serializer.writeClassAndObject(Serializer.java:373)

at com.jme3.network.serializing.serializers.FieldSerializer.writeObject(FieldSerializer.java:178)

… 10 more

4-set-2011 22.08.33 com.jme3.network.serializing.serializers.FieldSerializer writeObject

AVVERTENZA: [FieldSerializer][???] Exception occurred on writing. Maybe you’ve forgotten to register a class, or maybe a class member does not have a serializer.

4-set-2011 22.08.33 com.jme3.app.Application handleError

GRAVE: Uncaught exception thrown in Thread[LWJGL Renderer Thread,5,main]

java.lang.RuntimeException: Error serializing message

at com.jme3.network.base.MessageProtocol.messageToBuffer(MessageProtocol.java:83)

at com.jme3.network.base.DefaultClient.send(DefaultClient.java:213)

at com.jme3.network.base.DefaultClient.send(DefaultClient.java:193)

at it.mygame.MainClient.simpleInitApp(MainClient.java:133)

at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:230)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:124)

at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:200)

at java.lang.Thread.run(Thread.java:662)

Caused by: com.jme3.network.serializing.SerializerException: Error writing object

at com.jme3.network.serializing.serializers.FieldSerializer.writeObject(FieldSerializer.java:184)

at com.jme3.network.serializing.Serializer.writeClassAndObject(Serializer.java:374)

at com.jme3.network.base.MessageProtocol.messageToBuffer(MessageProtocol.java:75)

… 7 more

Caused by: java.lang.NullPointerException

at com.jme3.network.serializing.serializers.IntSerializer.writeObject(IntSerializer.java:52)

at com.jme3.network.serializing.serializers.FieldSerializer.writeObject(FieldSerializer.java:176)

… 9 more



And thi line of code that I think can cause this error is:



[java]c.send(new JoinPlayerMessage(app.getPlayerGeometry(), true));[/java]



Thanks a lot

The important part of all of that:

“Caused by: java.lang.IllegalArgumentException: Class has not been registered:class com.jme3.scene.Geometry”



Geometry is not registered to be serialized through SpiderMonkey’s Serializer. And really, this is not a good way to send that data anyway.



You could try registering it but you will end up having to also register half a dozen other classes that may or may not be even possible (vertex buffer, material, shader, etc.) It gets pretty nightmarish pretty quickly.



…and you are likely to overflow the 32k message limit anyway.



Better to send the raw data. If you have access to the mesh data then send that. Otherwise, send the j3o compressed in a byte[] field or make a j3o from it and compress it.

2 Likes

So I have the same problem, I have tried to say what you say pspeed but I have a
[java]java.nio.BufferOverflowException
at java.nio.Buffer.nextPutIndex(Buffer.java:513)
at java.nio.HeapByteBuffer.put(HeapByteBuffer.java:163)
at com.jme3.network.serializing.serializers.ByteSerializer.writeObject(ByteSerializer.java:52)
at com.jme3.network.serializing.serializers.ArraySerializer.writeArray(ArraySerializer.java:125)
at com.jme3.network.serializing.serializers.ArraySerializer.writeObject(ArraySerializer.java:110)
at com.jme3.network.serializing.serializers.FieldSerializer.writeObject(FieldSerializer.java:174)
at com.jme3.network.serializing.Serializer.writeClassAndObject(Serializer.java:392)
at com.jme3.network.base.MessageProtocol.messageToBuffer(MessageProtocol.java:74)
at com.jme3.network.base.DefaultServer.broadcast(DefaultServer.java:201)
at org.LRTeam.main.server.ServerMain.sendMap(ServerMain.java:90)
at org.LRTeam.main.server.ServerListener.messageReceived(ServerListener.java:23)
at org.LRTeam.main.server.ServerListener.messageReceived(ServerListener.java:16)
at com.jme3.network.base.MessageListenerRegistry.messageReceived(MessageListenerRegistry.java:69)
at com.jme3.network.base.DefaultServer.dispatch(DefaultServer.java:283)
at com.jme3.network.base.DefaultServer$Redispatch.messageReceived(DefaultServer.java:570)
at com.jme3.network.base.DefaultServer$Redispatch.messageReceived(DefaultServer.java:566)
at com.jme3.network.base.KernelAdapter.dispatch(KernelAdapter.java:184)
at com.jme3.network.base.KernelAdapter.createAndDispatch(KernelAdapter.java:238)
at com.jme3.network.base.KernelAdapter.run(KernelAdapter.java:281)[/java]

my code :
[java]File file = new File(“assets/Scenes/island.j3o”);
FileInputStream fis;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try
{
fis = new FileInputStream(file);
for (int readNum; (readNum = fis.read(buf)) != -1;)
{bos.write(buf, 0, readNum);}
}
catch (IOException e)
{e.printStackTrace();}
mapByte = bos.toByteArray();
server.broadcast(new MapSpatialMessage(mapByte));//got the exception here[/java]

MapSpatialMessage is a class whit a byte[] as field and constructor.

You are likely exceeding the maximum size of a spider monkey message.

Generally, this is not to way to do this kind of networking.

Edit: note also that you will find sending Spatials over the network to be so super extremely painful that it’s just not worth it. Even if you do it write and use the proper JME serialization for spatials and break the message up.

1 Like

i am sending only location and rotation and animation state for entities.
but how to send entire map?? this is just for first time loading or sinch.
now i use the same map, but i have vision to make random generated maps, then i need somehow to transfer all the stuff to other clients :-?

  1. Generate the random map on the server side with an unique ID (file name) and save it as .j3o file

  2. Send to the clients this ID

  3. And then use the assetManager load method with urlLocator to dl the new map on each clients

  4. When the game is finished destroy the map to release server resources

  5. Let’s go again to the next game…

3 Likes

Well have the map in binary as a bytebuffer somewhoe ?filereader genreating in memory whatever?)

Split into 10kb subbuffers.
Send int with amount of splits
-> Client creats a buffer for recival with the approximate size
Send one wait for confirm of recival (do nto send all at once, to prevent slow clients from getting ddosd by your server), then send the next.
-> Client sores the block into the large buffer
-> -> Show nice progessbar meanwhile (recived/amount)
after( recived==amount) cutof left over bytes (as the last split might be smaller than 10kb)

The urllocator does not support progress showing wich is why i would only use it for very small objects, but then you could send them directly anyway as they are below the 32kb limit

Remember that a j3o might also need other stuff, eg textures make sure you really transmitted every necessary file.

2 Likes

Thank you I will try all of you solution. :slight_smile:

@Empire Phoenix : So I have tried you method, but I get a exception, I don’t know If I am in the good section since the exception is a ArrayIndexOutOfBoundsException, and I have do this

  1. Read the file to a byte array,
    [java]byte[] mapByte;

    File file = new File(app.getPathToMap());
    FileInputStream fis;
    byte[] buf = new byte[1024];

    fis = new FileInputStream(file);
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    for (int readNum; (readNum = fis.read(buf)) != -1;)
    {bos.write(buf, 0, readNum);}
    mapByte = bos.toByteArray();[/java]

  2. Split into a 1kB sub-buffer for each message
    [java]public byte[] getMapByteToSend(int id){
    byte[] mapByteToSend = new byte[1024];
    int idToTake = id*1024;

    for(int i = 0; i < 1024 ; i++){
    mapByte[idToTake] = 0;
    mapByteToSend[i] = mapByte[idToTake];
    idToTake++;
    }

    return mapByteToSend;
    }[/java]

  3. Send it
    [java]FilePartMessage filePart = new FilePartMessage(getMapByteToSend(0));[/java]

  4. Wait for the confirmation of the client and send the next sub-buffer
    [java]if(m instanceof ReceveidFilePartMessage){
    ReceveidFilePartMessage message = (ReceveidFilePartMessage)m;
    if(message.nextId >= mapByte.length)//if all the file have been transfered
    {logger.log(Level.INFO, “File transfered”);}
    else{
    logger.log(Level.INFO, “{0} Ko/{1} Ko”, new Object[]{message.getNextId(),mapByte.length});
    FilePartMessage filePart = new FilePartMessage(getMapByteToSend(message.getNextId()));
    filePart.setReliable(true);
    source.getServer().broadcast(Filters.in(source), filePart);
    }
    }
    [/java]

The problem when I have transfered 503 Ko/515 303 Ko of my file.
[java]java.lang.ArrayIndexOutOfBoundsException: 515303
at org.LRTeam.main.server.ServerListener.getMapByteToSend(ServerListener.java:117)[/java]
The line where I get the exception :
[java]mapByte[idToTake] = 0;[/java]

Sorry if I am not on the appropriate section.

The mapByte array is shorter than 515303.

You need to add a check to not include data in the last message that exceed your original data array.
So in the getMapByteToSend method add a check for length.

[java]
for(int i = 0; i < 1024 && idToTake < mapByte.length; i++){
mapByte[idToTake] = 0; // This line makes all your data sent ZERO either way. (Why??)
mapByteToSend[i] = mapByte[idToTake];
idToTake++;
}
[/java]

1 Like

Oops sorry the second line is just for testing where happen exception I have forget to delete it. ^^
Thank you for you help, I have understand my other mistake I get the size of the map in byte, but I use a kilo byte, I am stupid. -.-

A big thank to all of you for your patience with me.