2

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 ?

2
  • 2
    When you write new PoulpiciousServer().run() in your main method, why aren't you using PoulpiciousServer.get().run()? Surely then PoulpiciousServer isn't a singleton? Commented Mar 28, 2016 at 21:30
  • Oh my god... Thank you.. Commented Mar 28, 2016 at 21:33

1 Answer 1

2

PoulpiciousServer isn't a singleton:

  • You create one instance in the PoulpiciousServerHolder class
  • You create one instance in the PoulpiciousServer.main method

You only call PoulpiciousServer.run() on the one created in the main method.

You access the list of rooms in the instance returned by PoulpiciousServer.get(), which is the instance created by the PoulpiciousServerHolder class. This one never has any rooms added to it, since its run() method is never invoked.

Replace the use of new PoulpiciousServer() in your main method with PoulpiciousServer.get().

Sign up to request clarification or add additional context in comments.

1 Comment

I changed it and it worked. I really didn't see this ! Thank you very much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.