[SOLVED] SpiderMonkey crash on first message from server

Hello everyone,

I’m currently working on adding multiplayer into S-RC Bots (my game).
I need to transfer initial data once, what I do for that is the following: Once the client has connected, it sends a “Hello” message to the server, which then sends over the initial data set.
The problem is, it crashes:

java.lang.RuntimeException: Error deserializing object, class ID:-49
    	at com.jme3.network.base.MessageProtocol.createMessage(MessageProtocol.java:184)
    	at com.jme3.network.base.MessageProtocol.addBuffer(MessageProtocol.java:160)
    	at com.jme3.network.base.ConnectorAdapter.run(ConnectorAdapter.java:169)
    Caused by: com.jme3.network.serializing.SerializerException: Class not found for buffer data.
    	at com.jme3.network.serializing.Serializer.readClassAndObject(Serializer.java:405)
    	at com.jme3.network.base.MessageProtocol.createMessage(MessageProtocol.java:180)
    	... 2 more

But when I comment out the block on the server that sends the response, I don’t get a crash. It might be helpful to know that when the response is commented out, the client spits out log messages about receiving serializer registrations, and it doesn’t when the crash occurs.
Interestingly, an “integrated server” (server and client in the same game process) always works, I suspect because the serializer is shared there.

Any ideas on a fix?

I don’t touch Java/jMonkey/SpiderMonkey for months, but I remember having lots of trouble with the Serializer class. Are you sure you’re adding the class that the server is sending to the client’s Serializer?

I’m not supposed to add anything to the serializer on the client because the server sends it over, at leasr that’s what I understood from some topics here.

Yes, I think only needs to be registered at the server. It’ll pass this on to the clients. There is a problem with it. That for me came on Linux every time, and on Windows randomly. That if you send something too fast, the serializers aren’t initialized yet on the client. Or that is what I understood, so adding a 500ms sleep service fixed this issue for me.

In a bit more detail, try adding a service as the first service that sleeps when connection is added. To let the serializer message process first.

Wow, things changed from last time I used it then :wink: . Shouldn’t there be a way for the Serializer on the client to wait until it’s initialized before it starts processing incoming messages? Because adding a sleep method looks kinda dirty to me.

What is this service thing you speak about @tonihele?

I’m not a super expert on this but might have been a change in JME 3.1 or 3.0.x.

A piece of code. Like so:
https://github.com/tonihele/OpenKeeper/blob/feature-263/src/toniarts/openkeeper/game/network/NetworkServer.java#L189

1 Like

Thanks for the ideas.
Doesn’t work though. I added a 500ms sleep to the client before it sends the first message that the server responds to:

try
    {
    client = Network.connectToServer(StaticVariables.NAME, StaticVariables.VERSION_NUMERIC, host, port);
    client.addMessageListener(new ClientMessageListener(this));
        client.addClientStateListener(this);
    client.start();
    
    logger.log(Level.INFO, "Client connected successfully.");
}
catch(IOException e)
{
    logger.log(Level.SEVERE, "Failed to create client.", e);
        //TODO: Display error message
}
    
    try
    {
        Thread.sleep(500);
    }
    catch(InterruptedException e)
    {
        //TODO
    }
    
    client.send(new ClientHelloMessage());

Still gets me the same crash.

Not the same thing, your code. I think. The delay needs to be before any of the other services and stuff init. Of course there is a chance that you don’t have the same problem.

Probably not the same problem then.
I start to initialize the GameState, but when I initialize the client and send the initial message, I wait until I receive the initial message from the server and only continue then.

I think in the debug logging it dumps all of the classes that the serializer has registered. That would be useful to see.

It could be one of a couple things but it’s hard to say.

If I don’t have the line in the server commented out, then the crash occurs and I’m not getting ANYTHING from the serializer.
Otherwise, it dumps my classes as normal.

Well, the server should have dumped its serialized output loooooong before then. Else it was never started properly.

Oh, sorry. I mean the client in this case.

I dont know your setup, but i have a client, server and shared project which contains the message classes they both need amongst the other shared stuff. Have you cleaned and rebuilt them all? Sometimes i get strange errors like that when i modify a shared class and only rebuild one side.

Note: since I still haven’t seen the list… I meant on the server.

I want to know what the server thinks ID -49 is. So the server list. The list of serializer registrations on the server.

Here’s the log when I connect a client with the message from the server commented out:

Okt 10, 2017 4:11:59 PM de.rbgs.srcb.Multiplayer.MultiplayerGameState loadMapSettings
INFORMATION: Client connected successfully.
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-19 = com.jme3.math.Vector3f, serializer=com.jme3.network.serializing.serializers.Vector3Serializer]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-41 = com.jme3.network.serializing.serializers.FieldSerializer, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-43 = [I, serializer=com.jme3.network.serializing.serializers.ArraySerializer]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-46 = [Lcom.jme3.network.message.SerializerRegistrationsMessage$Registration;, serializer=com.jme3.network.serializing.serializers.ArraySerializer]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-48 = de.rbgs.srcb.Multiplayer.Messages.BotDataMessage, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-49 = de.rbgs.srcb.Multiplayer.Messages.BotListUpdateMessage, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-50 = de.rbgs.srcb.Multiplayer.Messages.InitialBotDataMessage, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-51 = de.rbgs.srcb.Multiplayer.Messages.InitialServerDataMessage, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-52 = de.rbgs.srcb.Multiplayer.Messages.ClientHelloMessage, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-53 = de.rbgs.srcb.Multiplayer.MPSettings, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-55 = [Lde.rbgs.srcb.Bot.Parts.PartContainer;, serializer=com.jme3.network.serializing.serializers.ArraySerializer]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-56 = [Lde.rbgs.srcb.Bot.Weapon.WeaponGroup;, serializer=com.jme3.network.serializing.serializers.ArraySerializer]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-54 = de.rbgs.srcb.Bot.BotConfiguration, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-57 = de.rbgs.srcb.Bot.Parts.PartContainer, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-58 = de.rbgs.srcb.Bot.Weapon.WeaponGroup, serializer=null]
Okt 10, 2017 4:11:59 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Registering:Registration[-59 = de.rbgs.srcb.Bot.Weapon.WeaponPositionData, serializer=null]
Okt 10, 2017 4:11:59 PM de.rbgs.srcb.Main.GameStates.BaseGameState initPhase
INFORMATION: Game State init phase 2 done.

The client instance with integrated server always works and just says:

Okt 10, 2017 4:11:36 PM com.jme3.network.message.SerializerRegistrationsMessage registerAll
INFORMATION: Skipping registration as registry is locked, presumably by a local server process.

EDIT: Here is the BotListUpdateMessage.class:

package de.rbgs.srcb.Multiplayer.Messages;

import com.jme3.network.AbstractMessage;
import com.jme3.network.serializing.Serializable;
import java.util.List;

/**
 *
 * @author Robbi Blechdose
 * 
 */
@Serializable
public class BotListUpdateMessage extends AbstractMessage
{
    private List<BotDataMessage> updates;
    
    public BotListUpdateMessage() {}
    
    public BotListUpdateMessage(List<BotDataMessage> updates)
    {
        this.updates = updates;
    }

    public List<BotDataMessage> getUpdates()
    {
        return updates;
    }
}

And BotDataMessage.class:

package de.rbgs.srcb.Multiplayer.Messages;

import com.jme3.math.Vector3f;
import com.jme3.network.AbstractMessage;
import com.jme3.network.serializing.Serializable;

/**
 *
 * @author Robbi Blechdose
 * 
 */
@Serializable
public class BotDataMessage extends AbstractMessage
{
    private int botId;
    private Vector3f botPos;
    private Vector3f viewDir;
    private Vector3f walkDirection;
    
    public BotDataMessage() {}
    
    public BotDataMessage(int botId, Vector3f botPos, Vector3f viewDir, Vector3f walkDirection)
    {
	this.botId = botId;
	this.botPos = botPos;
	this.viewDir = viewDir;
	this.walkDirection = walkDirection;
    }

    public int getBotId()
    {
        return botId;
    }

    public Vector3f getBotPos()
    {
        return botPos;
    }

    public Vector3f getViewDir()
    {
        return viewDir;
    }

    public Vector3f getWalkDirection()
    {
        return walkDirection;
    }
}

Is this the message you are sending to the client?

And you are sending it ONLY as a response to something the client has sent? Or you are sending it as soon as the client connects?

I’m broadcasting it all the time to all clients. Is this a bad idea?
It transfers bot positions and directions, later on weapons fire etc., so I definetely need it.

EDIT: Seems that when I disable the broadcast, no crash occurs either. Any suggestions on how to manage this?

You could write a custom message from the client to the server which just tells the server that the client is ready to receive messages because it seems like even though the connection has been created successfully the client is still not able to receive messages which is also a little strange by the way.

But I need to broadcast things while the game is running.
So it shouldn’t crash when a new client joins but broadcasts are running.