SavableSerializer and client BufferUnderflowException

Well, I’m trying to send some Savable objects through the network with SpiderMonkey and it com.jme3.network.serializing.serializers.SavableSerializer. On both sides I register my classes on the same order (I have a global static registerer) with:

    Serializer.registerClass(MyClass.class, new SavableSerializer());

When sending it I’m getting the next trace in the client:

Grave: Termining connection due to unhandled error
java.nio.BufferUnderflowException
	at java.nio.HeapByteBuffer.get(HeapByteBuffer.java:145)
	at com.jme3.network.serializing.serializers.SavableSerializer$BufferInputStream.read(SavableSerializer.java:96)
	at java.io.BufferedInputStream.fill(BufferedInputStream.java:235)
	at java.io.BufferedInputStream.read1(BufferedInputStream.java:275)
	at java.io.BufferedInputStream.read(BufferedInputStream.java:334)
	at java.io.FilterInputStream.read(FilterInputStream.java:107)
	at com.jme3.export.binary.ByteUtils.readInt(ByteUtils.java:184)
	at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:139)
	at com.jme3.export.binary.BinaryImporter.load(BinaryImporter.java:125)
	at com.jme3.network.serializing.serializers.SavableSerializer.readObject(SavableSerializer.java:106)
	at com.jme3.network.serializing.Serializer.readClassAndObject(Serializer.java:357)
	at com.jme3.network.serializing.serializers.FieldSerializer.readObject(FieldSerializer.java:137)
	at com.jme3.network.serializing.Serializer.readClassAndObject(Serializer.java:357)
	at com.jme3.network.base.MessageProtocol.createMessage(MessageProtocol.java:180)
	at com.jme3.network.base.MessageProtocol.addBuffer(MessageProtocol.java:160)
	at com.jme3.network.base.ConnectorAdapter.run(ConnectorAdapter.java:169)

In the server I can see that it is calling the custom Savable serializer and sending it.

MyClass is a Savable and it is well de/serialized from/to disk. I tried to use this with very small objects (I’m pretty sure it’s not a size issue as the small ones are just composed by a Vector3f) and, even, with a null object.

The message I’m sending contains just a MyClass object.

It seems to should work like that, but It doesn’t. Am I missing something?

Thanks in advance for any help.

Does saving/loading your Saveable work otherwise? Something is trying to read more bytes than were sent… which could be because your Saveable is trying to read more things than were written.

Note: Saveable is not an efficient way to send data over the network… not sure why you are doing it that way.

I checked it a ton of times but I’ll check it again. It saves/loads fine from disk, the only thing that doesn’t work is the client side deserialization when the message is received.

Why isn’t it efficient?, I’m doing it because I need just the same info that is stored on disk to be sent to the client so I though that I could use the same serializer. Each savable (not movable entities) only serializes location and state information. When a client connects, has to receive all this information. I could make a workaround to get it work but it would be to make a less readable code and, if I can use the same serializer that to save on disk I’ll prefer it.

Well, something must be out of balance.

Anyway, Saveable was not really designed for efficiency. It tries to be a bit more robust. You could try just registering your class as a regular serializable for network transfer.

I tried it before but I have some data structures that needs custom serialization. For a first version I really wanted to have it easy done (just what SavableSerializer was supposed to do). If it doesn’t work I’ll make a workaround but before I just wanted to verify that I was doing things fine and SavableSerializer is broken.

EDIT: Ok, I just fixed it. Thanks for your help.

1 Like

Glad you found it. I guess no one ever used this class… and it existed since the old SM implementation and I never tested it either.

It has a couple strikes against it in general:

  1. it’s too tempting for users to think they can send things like spatials this way. That is 99.99999% of the time the exact wrong thing to do.
  2. it’s pretty inefficient. When you send a normal message that contains something like a Vector3f then SM’s serializer will send two bytes + 3 floats. If you were to send that same thing as a saveable then you end up sending the name of the class (length + chars), the name of the field (length + chars), the name of the Vector3f class (length + chars), the name of each of its fields (name + chars * 3) and the actual float values. So a 14 byte packed message ends up going as 67 bytes or so… more than 4 times as much…

For quick testing, I guess it’s ok.

What are you sending that otherwise would require a custom serializer?

Edit: corrected some numbers as I’d counted bits instead of bytes in one case.

Well, It’s just a terrain that contains some static (not movable) entities. This entities have their attributes. What I send is all this entities info as the client needs it all. I know there are more efficient ways but SavableSerializer fits just with what I need at the moment. Is just for loading so I’m not currently really interested on network optimization but on having a first usable version of the networking system.

Ok… but I still don’t see what the entities couldn’t be marked serializeable and just sent that way. So far nothing indicates that you couldn’t have used default serialization.

One thing you also have to be careful of is that there is a maximum message size for SM. So usually if a set of data is unbounded (and potentially large in your case) then it’s better to batch it up in smaller bits.

I think I go fine with the size limit (at least by the way). I’ll maybe use on a near future the default serialization but I have to make a few changes to use it. Thanks for all your help and dedication. Don’t worry, once the game is end and the client/server do what I want, I’ll change it to be the more efficient it can.

However, the size limit was… 32KB?.

Yes. And I must be at least five characters to post so “yes” again.