I'm trying to do a server for my game, responsible for the authentication and the matchmaking.
I have an ArrayList of Rooms (the rooms just keep track of the list of players in a game), which I use for matchmaking.
I have two singletons, PoulpiciousServer.java which is the main class, that runs everything, and MatchmakingEngine, which is run on another thread, and handles the players asking for a room to play.
Here are the classes (I use KryoNet) :
package com.poulpicious.server;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Server;
import com.poulpicious.network.packets.Packet00Login;
import com.poulpicious.network.packets.Packet01LoginAcknowledge;
import com.poulpicious.network.packets.Packet02CharacterInfos;
import com.poulpicious.network.packets.Packet03CharacterInfosResponse;
import com.poulpicious.network.packets.Packet04RequestMatchmaking;
import com.poulpicious.network.packets.Packet05MatchmakingResponse;
import com.poulpicious.network.packets.Packet06StopMatchmaking;
public class PoulpiciousServer {
private static class PoulpiciousServerHolder {
private static final PoulpiciousServer _instance = new PoulpiciousServer();
}
public static PoulpiciousServer get() {
return PoulpiciousServerHolder._instance;
}
private Server server;
private Map<Integer, ServerPlayer> serverPlayers = new HashMap<Integer, ServerPlayer>();
private List<Room> rooms;
private Thread matchmakingEngineThread;
public PoulpiciousServer() {
this.server = new Server();
this.rooms = Collections.synchronizedList(new ArrayList<Room>());
Kryo k = this.server.getKryo();
k.register(Packet00Login.class);
k.register(Packet01LoginAcknowledge.class);
k.register(Packet02CharacterInfos.class);
k.register(Packet03CharacterInfosResponse.class);
k.register(Packet04RequestMatchmaking.class);
k.register(Packet05MatchmakingResponse.class);
k.register(Packet06StopMatchmaking.class);
}
public void run() {
try {
this.rooms.add(new Room());
server.addListener(new PoulpiciousServerListener(this));
this.matchmakingEngineThread = new Thread(MatchmakingEngine.get(), "matchmaking");
this.matchmakingEngineThread.start();
server.start();
server.bind(25565, 25565);
System.out.println("Master server started.");
} catch (IOException e) {
e.printStackTrace();
}
}
public void registerPlayer(Connection c, String username) {
this.serverPlayers.put(c.getID(), new ServerPlayer(c, username));
}
public static void main(String[] args) {
new PoulpiciousServer().run();
}
public ServerPlayer getServerPlayer(int connID) {
return this.serverPlayers.get(connID);
}
public Room getRoom(int index) {
synchronized (rooms) {
return this.rooms.get(0);
}
}
public List<Room> getRooms() {
return rooms;
}
}
And the matchmaking engine:
package com.poulpicious.server;
import java.util.ArrayList;
import com.poulpicious.network.packets.Packet05MatchmakingResponse;
public class MatchmakingEngine implements Runnable {
private static class MatchmakingEngineHolder {
private static final MatchmakingEngine _instance = new MatchmakingEngine();
}
public static MatchmakingEngine get() {
return MatchmakingEngineHolder._instance;
}
private boolean running;
private ArrayList<ServerPlayer> playersSearching = new ArrayList<ServerPlayer>();
public MatchmakingEngine() {
this.running = true;
}
@Override
public void run() {
while (running) {
if (PoulpiciousServer.get().getRooms().size() > 0)
System.out.println(PoulpiciousServer.get().getRooms().size());
synchronized (playersSearching) {
// System.out.println(playersSearching.size());
if (playersSearching.size() > 0) {
System.out.println("Matching a player");
ServerPlayer current = playersSearching.get(0);
PoulpiciousServer.get().getRoom(0).addPlayer(current);
Packet05MatchmakingResponse pmr = new Packet05MatchmakingResponse();
pmr.nbPlayers = PoulpiciousServer.get().getRoom(0).getPlayerCount();
current.getConnection().sendTCP(pmr);
playersSearching.remove(0);
}
}
}
}
public void registerPlayer(ServerPlayer player) {
synchronized (playersSearching) {
this.playersSearching.add(player);
}
}
}
So in the main class I add a new Room, just for testing, so the rooms list contains at least 1 room.
In the matchmaking engine, in the run method, I want to print the size of this list but it doesn't, because the list is empty.
The problem is that I do not empty this list anywhere, and I don't understand why it is empty in the other thread.
I used synchronized, Collections.synchronizedList, even ConcurrentMap for testing, none worked...
How can I be sure that the list is really thread-safe and is not emptied for no reason ?
new PoulpiciousServer().run()in yourmainmethod, why aren't you usingPoulpiciousServer.get().run()? Surely thenPoulpiciousServerisn't a singleton?