Search in sources :

Example 16 with SOCGame

use of soc.game.SOCGame in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleSITDOWN.

/**
 * handle "sit down" message
 *
 * @param c  the connection that sent the message
 * @param mes  the message
 * @since 1.0.0
 */
private void handleSITDOWN(Connection c, SOCSitDown mes) {
    if (c == null)
        return;
    final String gaName = mes.getGame();
    SOCGame ga = gameList.getGameData(gaName);
    if (ga == null) {
        // Out of date client info, or may be observing a deleted game.
        // Already authenticated (c != null), so replying is OK by security.
        // "Game not found."
        srv.messageToPlayerKeyed(c, gaName, "reply.game.not.found");
        // <--- Early return: No active game found ---
        return;
    }
    /**
     * make sure this player isn't already sitting
     */
    boolean canSit = true;
    boolean gameIsFull = false, gameAlreadyStarted = false;
    /*
           for (int i = 0; i < SOCGame.MAXPLAYERS; i++) {
           if (ga.getPlayer(i).getName() == c.getData()) {
           canSit = false;
           break;
           }
           }
         */
    // D.ebugPrintln("ga.isSeatVacant(mes.getPlayerNumber()) = "+ga.isSeatVacant(mes.getPlayerNumber()));
    /**
     * if this is a robot, remove it from the request list
     */
    boolean isBotJoinRequest = false;
    {
        Hashtable<Connection, Object> joinRequests = srv.robotJoinRequests.get(gaName);
        if (joinRequests != null)
            isBotJoinRequest = (null != joinRequests.remove(c));
    }
    /**
     * make sure a person isn't sitting here already;
     * if a robot is sitting there, dismiss the robot.
     * Can't sit at a vacant seat after everyone has
     * placed 1st settlement+road (state >= START2A).
     *
     * If a human leaves after game is started, seat will appear vacant when the
     * requested bot sits to replace them, so let the bot sit at that vacant seat.
     */
    final int pn = mes.getPlayerNumber();
    ga.takeMonitor();
    try {
        if (ga.isSeatVacant(pn)) {
            gameAlreadyStarted = (ga.getGameState() >= SOCGame.START2A);
            if (!gameAlreadyStarted)
                gameIsFull = (1 > ga.getAvailableSeatCount());
            if (gameIsFull || (gameAlreadyStarted && !isBotJoinRequest))
                canSit = false;
        } else {
            SOCPlayer seatedPlayer = ga.getPlayer(pn);
            if (seatedPlayer.isRobot() && (ga.getSeatLock(pn) != SOCGame.SeatLockState.LOCKED) && (ga.getCurrentPlayerNumber() != pn)) {
                /**
                 * boot the robot out of the game
                 */
                Connection robotCon = srv.getConnection(seatedPlayer.getName());
                robotCon.put(SOCRobotDismiss.toCmd(gaName));
                /**
                 * this connection has to wait for the robot to leave
                 * and then it can sit down
                 */
                Vector<SOCReplaceRequest> disRequests = srv.robotDismissRequests.get(gaName);
                SOCReplaceRequest req = new SOCReplaceRequest(c, robotCon, mes);
                if (disRequests == null) {
                    disRequests = new Vector<SOCReplaceRequest>();
                    disRequests.addElement(req);
                    srv.robotDismissRequests.put(gaName, disRequests);
                } else {
                    disRequests.addElement(req);
                }
            }
            canSit = false;
        }
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception caught at handleSITDOWN");
    }
    ga.releaseMonitor();
    // D.ebugPrintln("canSit 2 = "+canSit);
    if (canSit) {
        srv.sitDown(ga, c, pn, mes.isRobot(), false);
    } else {
        /**
         * if the robot can't sit, tell it to go away.
         * otherwise if game is full, tell the player.
         */
        if (mes.isRobot()) {
            c.put(SOCRobotDismiss.toCmd(gaName));
        } else if (gameAlreadyStarted) {
            srv.messageToPlayerKeyed(c, gaName, "member.sit.game.started");
        // "This game has already started; to play you must take over a robot."
        } else if (gameIsFull) {
            srv.messageToPlayerKeyed(c, gaName, "member.sit.game.full");
        // "This game is full; you cannot sit down."
        }
    }
}
Also used : Hashtable(java.util.Hashtable) Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SOCPlayer(soc.game.SOCPlayer) SOCGame(soc.game.SOCGame) SQLException(java.sql.SQLException) MissingResourceException(java.util.MissingResourceException)

Example 17 with SOCGame

use of soc.game.SOCGame in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleLEAVEGAME_member.

/**
 * Handle a member leaving the game, from
 * {@link #handleLEAVEGAME(Connection, SOCLeaveGame)}.
 * @since 1.1.07
 */
private void handleLEAVEGAME_member(Connection c, final String gaName) {
    boolean gameDestroyed = false;
    if (!gameList.takeMonitorForGame(gaName)) {
        // <--- Early return: game not in gamelist ---
        return;
    }
    try {
        gameDestroyed = srv.leaveGame(c, gaName, true, false);
    } catch (Exception e) {
        D.ebugPrintStackTrace(e, "Exception in handleLEAVEGAME (leaveGame)");
    }
    gameList.releaseMonitorForGame(gaName);
    if (gameDestroyed) {
        srv.broadcast(SOCDeleteGame.toCmd(gaName));
    } else {
    /*
               SOCLeaveGame leaveMessage = new SOCLeaveGame(c.getData(), c.host(), gaName);
               messageToGame(gaName, leaveMessage);
               recordGameEvent(gaName, leaveMessage);
             */
    }
    /**
     * if it's a robot, remove it from the request list
     */
    Vector<SOCReplaceRequest> requests = srv.robotDismissRequests.get(gaName);
    if (requests != null) {
        Enumeration<SOCReplaceRequest> reqEnum = requests.elements();
        SOCReplaceRequest req = null;
        while (reqEnum.hasMoreElements()) {
            SOCReplaceRequest tempReq = reqEnum.nextElement();
            if (tempReq.getLeaving() == c) {
                req = tempReq;
                break;
            }
        }
        if (req != null) {
            requests.removeElement(req);
            /**
             * Taking over a robot spot: let the person replacing the robot sit down
             */
            SOCGame ga = gameList.getGameData(gaName);
            final int pn = req.getSitDownMessage().getPlayerNumber();
            final boolean isRobot = req.getSitDownMessage().isRobot();
            if (!isRobot) {
                // Don't keep the robot face icon
                ga.getPlayer(pn).setFaceId(1);
            }
            srv.sitDown(ga, req.getArriving(), pn, isRobot, false);
        }
    }
}
Also used : SOCGame(soc.game.SOCGame) SQLException(java.sql.SQLException) MissingResourceException(java.util.MissingResourceException)

Example 18 with SOCGame

use of soc.game.SOCGame in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleRESETBOARDVOTE.

/**
 * handle message of player's vote for a "reset-board" request.
 * Register the player's vote with {@link SOCServer#resetBoardVoteNotifyOne(SOCGame, int, String, boolean)}.
 * If all votes have now arrived and the vote is unanimous,
 * resets the game to a copy with same name and players, new layout.
 *
 * @param c  the connection
 * @param mes  the message
 * @see #handleRESETBOARDREQUEST(Connection, SOCResetBoardRequest)
 * @see SOCServer#resetBoardAndNotify(String, int)
 * @since 1.1.00
 */
private void handleRESETBOARDVOTE(Connection c, final SOCResetBoardVote mes) {
    final String gaName = mes.getGame();
    SOCGame ga = gameList.getGameData(gaName);
    if (ga == null)
        return;
    final String plName = c.getData();
    SOCPlayer reqPlayer = ga.getPlayer(plName);
    if (reqPlayer == null) {
        // Not playing in that game (security)
        return;
    }
    // Register this player's vote, and let game members know.
    // If vote succeeded, go ahead and reset the game.
    // If vote rejected, let everyone know.
    srv.resetBoardVoteNotifyOne(ga, reqPlayer.getPlayerNumber(), plName, mes.getPlayerVote());
}
Also used : SOCPlayer(soc.game.SOCPlayer) SOCGame(soc.game.SOCGame)

Example 19 with SOCGame

use of soc.game.SOCGame in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleRESETBOARDREQUEST.

/**
 * handle "reset-board request" message.
 * If {@link SOCGame#getResetVoteActive()} already or {@link SOCPlayer#hasAskedBoardReset()} this turn,
 * ignore. Otherwise: If multiple human players, start a vote with {@link SOCGame#resetVoteBegin(int)}.
 * If requester is sole human player, reset the game to a copy with same name and (copy of) same players,
 * new layout, by calling {@link SOCServer#resetBoardAndNotify(String, int)}.
 *<P>
 * The requesting player doesn't vote, but server still sends them a vote-request message to tell that client their
 * request was accepted and voting has begun.
 *<P>
 * If only one player remains (all other humans have left at end), ask them to start a new game instead.
 * This is a rare occurrence and we shouldn't bring in new robots and all,
 * since we already have an interface to set up a game.
 *<P>
 * If any human player's client is too old to vote for reset, assume they vote Yes.
 *
 * @param c  the connection
 * @param mes  the message
 * @see #handleRESETBOARDVOTE(Connection, SOCResetBoardVote)
 * @since 1.1.00
 */
private void handleRESETBOARDREQUEST(Connection c, final SOCResetBoardRequest mes) {
    final String gaName = mes.getGame();
    SOCGame ga = gameList.getGameData(gaName);
    if (ga == null)
        return;
    SOCPlayer reqPlayer = ga.getPlayer(c.getData());
    if (reqPlayer == null) {
        // Not playing in that game (Security)
        return;
    }
    /**
     * Is voting already active from another player?
     * Or, has this player already asked for voting this turn?
     */
    if (ga.getResetVoteActive() || reqPlayer.hasAskedBoardReset()) {
        // that would end the already-active round of voting.
        return;
    }
    /**
     * Is there more than one human player?
     * Grab connection information for humans and robots.
     */
    Connection[] humanConns = new Connection[ga.maxPlayers];
    Connection[] robotConns = new Connection[ga.maxPlayers];
    final int numHuman = SOCGameBoardReset.sortPlayerConnections(ga, null, gameList.getMembers(gaName), humanConns, robotConns);
    final int reqPN = reqPlayer.getPlayerNumber();
    if (numHuman < 2) {
        // Are there robots? Go ahead and reset if so.
        boolean hadRobot = false, hadUnlockedRobot = false;
        for (int i = robotConns.length - 1; i >= 0; --i) {
            if (robotConns[i] != null) {
                hadRobot = true;
                if (ga.getSeatLock(i) == SOCGame.SeatLockState.UNLOCKED) {
                    hadUnlockedRobot = true;
                    break;
                }
            }
        }
        if (hadUnlockedRobot) {
            srv.resetBoardAndNotify(gaName, reqPN);
        } else if (hadRobot) {
            srv.messageToPlayerKeyed(c, gaName, "resetboard.request.unlock.bot");
        // "Please unlock at least one bot, so you will have an opponent."
        } else {
            srv.messageToGameKeyed(ga, true, "resetboard.request.everyone.left");
        // "Everyone has left this game. Please start a new game with players or bots."
        }
    } else {
        // Probably put it to a vote.
        gameList.takeMonitorForGame(gaName);
        // First, Count number of other players who can vote (connected, version chk)
        int votingPlayers = 0;
        for (int i = ga.maxPlayers - 1; i >= 0; --i) {
            if ((i != reqPN) && !ga.isSeatVacant(i)) {
                Connection pc = srv.getConnection(ga.getPlayer(i).getName());
                if ((pc != null) && pc.isConnected() && (pc.getVersion() >= 1100))
                    ++votingPlayers;
            }
        }
        if (votingPlayers == 0) {
            // No one else is capable of voting.
            // Reset the game immediately.
            srv.messageToGameKeyed(ga, false, "resetboard.vote.request.alloldcli", c.getData());
            // ">>> {0} is resetting the game - other connected players are unable to vote (client too old)."
            gameList.releaseMonitorForGame(gaName);
            srv.resetBoardAndNotify(gaName, reqPN);
        } else {
            // Put it to a vote
            srv.messageToGameKeyed(ga, false, "resetboard.vote.request", c.getData());
            // "requests a board reset - other players please vote."
            String vrCmd = SOCResetBoardVoteRequest.toCmd(gaName, reqPN);
            ga.resetVoteBegin(reqPN);
            gameList.releaseMonitorForGame(gaName);
            for (int i = 0; i < ga.maxPlayers; ++i) if (humanConns[i] != null)
                if (humanConns[i].getVersion() >= 1100)
                    humanConns[i].put(vrCmd);
                else
                    ga.resetVoteRegister(ga.getPlayer(humanConns[i].getData()).getPlayerNumber(), true);
        }
    }
}
Also used : Connection(soc.server.genericServer.Connection) StringConnection(soc.server.genericServer.StringConnection) SOCPlayer(soc.game.SOCPlayer) SOCGame(soc.game.SOCGame)

Example 20 with SOCGame

use of soc.game.SOCGame in project JSettlers2 by jdmonin.

the class SOCServerMessageHandler method handleSTARTGAME.

/**
 * handle "start game" message.  Game state must be NEW, or this message is ignored.
 * {@link SOCServer#readyGameAskRobotsJoin(SOCGame, Connection[], int) Ask some robots} to fill
 * empty seats, or {@link GameHandler#startGame(SOCGame) begin the game} if no robots needed.
 *<P>
 * Called when clients have sat at a new game and a client asks to start it,
 * not called during game board reset.
 *<P>
 * For robot debugging, a client can start and observe a robots-only game if the
 * {@link SOCServer#PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL} property != 0 (including &lt; 0).
 *<P>
 * Visibility is package-level, not private, so {@link SOCServer} can start robot-only games.
 *
 * @param c  the connection that sent the message
 * @param mes  the message
 * @param botsOnly_maxBots  For bot debugging, maximum number of bots to add to the game,
 *     or 0 to fill all empty seats. This parameter is used only when requesting a new
 *     robots-only game using the *STARTBOTGAME* debug command; ignored otherwise.
 * @since 1.0.0
 */
void handleSTARTGAME(Connection c, final SOCStartGame mes, final int botsOnly_maxBots) {
    final String gn = mes.getGame();
    SOCGame ga = gameList.getGameData(gn);
    if (ga == null)
        return;
    ga.takeMonitor();
    try {
        if (ga.getGameState() == SOCGame.NEW) {
            boolean allowStart = true;
            boolean seatsFull = true;
            boolean anyLocked = false;
            int numEmpty = 0;
            int numPlayers = 0;
            // 
            for (int i = 0; i < ga.maxPlayers; i++) {
                if (ga.isSeatVacant(i)) {
                    if (ga.getSeatLock(i) == SOCGame.SeatLockState.UNLOCKED) {
                        seatsFull = false;
                        ++numEmpty;
                    } else {
                        anyLocked = true;
                    }
                } else {
                    ++numPlayers;
                }
            }
            // Check vs max-players allowed in game (option "PL").
            // Like seat locks, this can cause robots to be unwanted
            // in otherwise-empty seats.
            {
                final int numAvail = ga.getAvailableSeatCount();
                if (numAvail < numEmpty) {
                    numEmpty = numAvail;
                    if (numEmpty == 0)
                        seatsFull = true;
                }
            }
            if (numPlayers == 0) {
                if (0 == srv.getConfigIntProperty(SOCServer.PROP_JSETTLERS_BOTS_BOTGAMES_TOTAL, 0)) {
                    allowStart = false;
                    srv.messageToGameKeyed(ga, true, "start.player.must.sit");
                // "To start the game, at least one player must sit down."
                } else {
                    if ((botsOnly_maxBots != 0) && (botsOnly_maxBots < numEmpty))
                        numEmpty = botsOnly_maxBots;
                }
            }
            if (seatsFull && (numPlayers < 2)) {
                // Don't start the game; client must have more humans sit or unlock some seats for bots.
                allowStart = false;
                numEmpty = 3;
                srv.messageToGameKeyed(ga, true, "start.only.cannot.lock.all");
            // "The only player cannot lock all seats. To start the game, other players or robots must join."
            } else if (allowStart && !seatsFull) {
                // Look for some bots
                final int numBots = srv.getRobotCount();
                if (numBots == 0) {
                    if (numPlayers < SOCGame.MINPLAYERS)
                        srv.messageToGameKeyed(ga, true, "start.no.robots.on.server", SOCGame.MINPLAYERS);
                    else
                        // "No robots on this server, please fill at least {0} seats before starting."
                        // Enough players to start game.
                        seatsFull = true;
                } else {
                    // 
                    if (numEmpty > numBots) {
                        final String m;
                        if (anyLocked)
                            m = "start.not.enough.robots";
                        else
                            // "Not enough robots to fill all the seats. Only {0} robots are available."
                            m = "start.not.enough.robots.lock";
                        // "Not enough robots to fill all the seats. Lock some seats. Only {0} robots are available."
                        srv.messageToGameKeyed(ga, true, m, numBots);
                    } else {
                        ga.setGameState(SOCGame.READY);
                        /**
                         * Fill all the unlocked empty seats with robots.
                         * Build a Vector of Connections of robots asked
                         * to join, and add it to the robotJoinRequests table.
                         */
                        try {
                            srv.readyGameAskRobotsJoin(ga, null, numEmpty);
                        } catch (IllegalStateException e) {
                            System.err.println("Robot-join problem in game " + gn + ": " + e);
                            // recover, so that human players can still start a game
                            ga.setGameState(SOCGame.NEW);
                            allowStart = false;
                            gameList.takeMonitorForGame(gn);
                            srv.messageToGameKeyed(ga, false, "start.robots.cannot.join.problem", e.getMessage());
                            // "Sorry, robots cannot join this game: {0}"
                            srv.messageToGameKeyed(ga, false, "start.to.start.without.robots");
                            // "To start the game without robots, lock all empty seats."
                            gameList.releaseMonitorForGame(gn);
                        }
                    }
                }
            }
            /**
             * If this doesn't need robots, then start the game.
             * Otherwise wait for them to sit before starting the game.
             */
            if (seatsFull && allowStart) {
                GameHandler hand = gameList.getGameTypeHandler(gn);
                if (hand != null)
                    hand.startGame(ga);
            }
        }
    } catch (Throwable e) {
        D.ebugPrintStackTrace(e, "Exception caught");
    }
    ga.releaseMonitor();
}
Also used : SOCGame(soc.game.SOCGame)

Aggregations

SOCGame (soc.game.SOCGame)60 SOCPlayer (soc.game.SOCPlayer)17 Connection (soc.server.genericServer.Connection)7 SOCBoardLarge (soc.game.SOCBoardLarge)5 MissingResourceException (java.util.MissingResourceException)3 Vector (java.util.Vector)3 SOCBoard (soc.game.SOCBoard)3 StringConnection (soc.server.genericServer.StringConnection)3 SQLException (java.sql.SQLException)2 HashMap (java.util.HashMap)2 SOCResourceSet (soc.game.SOCResourceSet)2 SOCShip (soc.game.SOCShip)2 SOCTradeOffer (soc.game.SOCTradeOffer)2 SOCVillage (soc.game.SOCVillage)2 SOCGameBoardReset (soc.util.SOCGameBoardReset)2 Color (java.awt.Color)1 IOException (java.io.IOException)1 InterruptedIOException (java.io.InterruptedIOException)1 ArrayList (java.util.ArrayList)1 EnumMap (java.util.EnumMap)1