[SOLVED]Problems with sending ArrayList over network

Hello javagaming community.
I am working on a multiplayer game using kryonet. I am trying to send an arraylist over the network but everytime I send the it, the server crashes and there is no exception thrown.
How can I fix this bug? ??? ???

Sending the bullets over the network:



public void update(float delta)
{
//networkBullets and bullets are arraylists
if(networkBullets != bullets)
		{
  //send bullets over to the server
			PacketUpdateBullet packet = new PacketUpdateBullet();
			packet.bullet = bullets;
			network.client.sendUDP(packet);

			networkBullets = bullets;
		}
}



Adding to the bullets arraylist:


public void shoot() {

		if(bullets.size() == MAX_BULLETS) return;
		bullets.add(new Bullet(x, y, radians));
		Jukebox.play("shoot");
		Spaceoids.cam.project(new Vector3(x, y, 0));

	}

Thank you for your support.
EDIT: Thank you chrislo27, VaTTeRGeR, basil_ for helping me solving this problem

Can we have a look at your registration code (registering classes on the server and client for serialization)? Perhaps you may be missing a class that is vital for sending the entire ArrayList over.

Server registration of classes:


server = new Server();
		server.getKryo().register(ArrayList.class);
		server.getKryo().register(Bullet.class);
		server.getKryo().register(PacketAddPlayer.class);	
		server.getKryo().register(PacketAsteroids.class);
		server.getKryo().register(PacketRemovePlayer.class);
		server.getKryo().register(PacketUpdateAcceleration.class);
		server.getKryo().register(PacketUpdateBullet.class);
		server.getKryo().register(PacketUpdateDeath.class);
		server.getKryo().register(PacketUpdateFlames.class);
		server.getKryo().register(PacketUpdateHit.class);
		server.getKryo().register(PacketUpdatePosition.class);
		server.getKryo().register(PacketUpdateRotation.class);
		server.getKryo().register(PacketUpdateStats.class);
		for(int i = 0; i < server.getKryo().getNextRegistrationId(); i++)
		{
			System.out.println("Registering: " + server.getKryo().getRegistration(i).toString());
		}
		server.bind(port, port + 1);
		server.start();
		server.addListener(new SpaceoidsServer());
		System.out.println("The server is ready");

Client registration of classes:



		this.ip = ip;
		this.port = port;
		client = new Client();
		client.getKryo().register(ArrayList.class);
		client.getKryo().register(Bullet.class);
		client.getKryo().register(PacketAddPlayer.class);	
		client.getKryo().register(PacketAsteroids.class);
		client.getKryo().register(PacketRemovePlayer.class);
		client.getKryo().register(PacketUpdateAcceleration.class);
		client.getKryo().register(PacketUpdateBullet.class);
		client.getKryo().register(PacketUpdateDeath.class);
		client.getKryo().register(PacketUpdateDeath.class);
		client.getKryo().register(PacketUpdateFlames.class);
		client.getKryo().register(PacketUpdateHit.class);
		client.getKryo().register(PacketUpdatePosition.class);
		client.getKryo().register(PacketUpdateRotation.class);
		client.getKryo().register(PacketUpdateStats.class);
		client.addListener(this);

		client.start();
		try {
			client.connect(5000, ip, port, port + 1);
		} catch (IOException e) {
			reason = e.toString();
			e.printStackTrace();
		}
	

Packet for sending the bullets:



import java.util.ArrayList;

import com.waleed.Spaceoids.entities.Bullet;

public class PacketUpdateBullet{
	
	public int id;
	public final int MAX_BULLETS = 4;
	public ArrayList<Bullet> bullet;

}

looks good on first glance. do you get a crash-dump at least ?

i guess it’s Bullet.class deserialization. how does the class look like ?

If you cannot get it to work with the default serializer, there’s the option to write your own serializer.
Just extract the array from the ArrayList and de-/serialize it with one of the default serializers!

Here’s an example with the Artemis-odb “Bag” class, it is quite similar to ArrayList.

//Add your package name and other necessary imports here
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;

import static com.esotericsoftware.kryo.serializers.DefaultArraySerializers.*;

public class BagSerializer extends Serializer<Bag<?>>{

	ObjectArraySerializer oas = new ObjectArraySerializer();
	
	public BagSerializer() {
		oas.setElementsAreSameType(false);//Choose true  for optimization if your ArrayLists contain ONLY objects of the same class
		oas.setElementsCanBeNull(true);//can be set to false if all elements are "!= null"
	}
	
	@Override
	public Bag<?> read(Kryo kryo, Input in, Class<Bag<?>> bagClass) {
		Object[] content = kryo.readObjectOrNull(in, Object[].class, oas);
		Bag<Object> bag = new Bag<Object>(content.length);
		for (int i = 0; i < content.length; i++) {
			bag.add(content[i]);
		}
		return bag;
	}
	
	@Override
	public void write(Kryo kryo, Output out, Bag<?> bag) {
		kryo.writeObjectOrNull(out, bag.getData(), oas);
	}
}

Then call this:

server.getKryo().register(ArrayList.class, new ArrayListSerializer());

How would I apply the BulletSerializer class in my code?

I’ve noticed you don’t have an empty constructor in your Bullet class. When using the default serializer, Kryo requires an empty constructor so it can instantiate the class after deserialization.

Try using the default serializer (proceed as normal) but put an empty constructor in the Bullet class.

It’s also possible you’re not getting any errors shown because your Kryonet logger level isn’t detailed enough.

Thank you! This solved my problem ;D ;D

Glad to hear! I was just about to go look up the pluggable serialization for you but I’m happy to hear it’s resolved.

It’s a bit annoying to have the empty constructor especially for entities (sometimes I’ll accidentally use it instead of the actual “real” constructor) but I suppose it’s much easier than writing a serializer for each entity type.