As I mentioned in this thread, I’m developing a project with Spidermonkey. My project uses java.util.UUID extensively, and in many cases UUIDs need to be sent between the server and the client. Since Spidermonkey doesn’t natively support those, I made a UUIDSerializer class.
As I mentioned in the other thread, I’m using the Spidermonkey registration service to propagate message registrations from the server to the client. In the absence of finding explicit documentation on this topic, I assumed that a custom class serializer like this would need to be registered on both the client and the server. However, when I place
Serializer.registerClass(UUID.class, new UUIDSerializer());
in both the server and the client network initialization (before any connections are established), the client fails to connect and logs the following stack trace:
May 29, 2017 10:50:01 AM com.jme3.network.base.DefaultClient handleError
SEVERE: Termining connection due to unhandled error
java.lang.ClassCastException: java.util.UUID cannot be cast to com.jme3.network.Message
However, if I comment out the serializer registration on the client (but leave it on the server), the client connects successfully. (I haven’t tested what happens if I attempt to send a message that contains a UUID, however.)
I find it rather odd that the client would fail like this when registering a custom serializer on both the server and client. If using the registration service, is the client reflectively finding and creating an instance of the custom serializer? Am I correct to conclude that the right way to handle custom serializers when using the registration service is to register them only on the server, giving them no special treatment client side?
It used to be that you had to register on both the client and the server. But it was a pain because they had to be registered in EXACTLY the same order. Generally, this meant that you had to have all of your registrations in one giant shared static method. It also meant that writing reusable services was pretty much impossible. Or certainly required some really fragile setup on the part of the user of the service.
So one of the first services written was one that would automatically transmit the server’s mappings to the clients… thus the clients didn’t have to register anything and the server-side services could register them in whatever order they liked.
Edit: and the reason you get the class cast exception is because the other end thinks your send UUID is really one of the Message classes because the IDs have been messed up.
Note: another solution in these cases is to just convert UUID to one of its simpler forms in the message fields and then translate back on the other end. You can make UUID work, though… that translation technique may be better left to classes that can’t be serialized for one reason or another.
I’d like to avoid translating UUIDs. It’s not a big deal, but so many messages use UUID I’d rather just use a serializer. The odd thing about the exception is that I don’t think any UUIDs are being sent at all yet. I haven’t touched some parts of the network code in quite a while though, so I’d need to check and verify that.
Yeah, what happens is that UUID gets registered as ID ‘a’ and some message class gets registered as ID ‘b’… but on the client it’s backwards… so when the message gets sent then the client tries to read it as a UUID… which will contain garbage and certainly won’t be castable to Message.
P.S.: UUIDs are kind of heavy-weight to be sending in messages all the time. It’s very strange to have to be sending 128 bits worth of ID data all the time. Almost always better to use just a long or something except for things that truly should be universally unique across the whole world of all software ever.
Generally, an ever increasing long is enough for most network-related IDs.
Edit: and often much less than that depending on what it is.
Oh, gotcha… in my case that was probably the heartbeat.
Yes, in my case UUIDs are used to identify unique objects across a decentralized and distributed server network. Users have UUIDs, entities have UUIDs, assets have UUIDs, etc. At the moment the protocol is only using them for asset downloads (assets are fully dynamic at runtime), but I suspect that when I get to the code for interaction in the world they will come up again. I suppose I could make a client/server service pair that translates between short (int or smaller) network ids and the full UUIDs, but this seems error-prone.