org.damcode.web.c4webserver.Server.java Source code

Java tutorial

Introduction

Here is the source code for org.damcode.web.c4webserver.Server.java

Source

/*
 * Copyright 2014 dm.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.damcode.web.c4webserver;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import static org.damcode.web.c4webserver.Utils.printSysOut;
import org.json.JSONObject;

/**
 *
 * @author dm
 */
@ServerEndpoint(value = "/{id}/c4", decoders = MessageDecoder.class)
public class Server {

    static final boolean DEBUG = false;
    static final List<GameController> activeGames = Collections.synchronizedList(new ArrayList<GameController>());
    static final List<GameController> waitingGames = Collections.synchronizedList(new ArrayList<GameController>());

    @OnOpen
    public void onOpen(Session session, @PathParam("id") String gameId) throws IOException {
        printSysOut("new session: " + session.getId() + ", game id: " + gameId + "from ip: ");
        session.getUserProperties().put("gameid", gameId);
        session.getUserProperties().put("lobby", true);

        String connectedPlayers = "";
        int pCount = 0;
        for (Session s : session.getOpenSessions()) {
            if (!s.equals(session)) {
                String name = (String) s.getUserProperties().get("name");
                connectedPlayers += name + ", ";
                pCount++;
            }
        }
        if (pCount > 0) {
            printSysOut("Connected Players: " + connectedPlayers);
            session.getBasicRemote()
                    .sendText(Utils.assembleChatMessage("Server", connectedPlayers, "other players"));
        }

        for (GameController gc : waitingGames) {
            sendGameAvailMessage(session, gc.getId().toString(), gc.players.get(0));
        }
    }

    @OnClose
    public void onClose(Session s) {
        printSysOut("Closing session: " + s.getId());

        GameController g = getGame(s);
        if (g != null) {

            Player p = g.getPlayer(s);
            if (g.gameStatus == GameController.GAME_WAITING) {
                waitingGames.remove(g);
                printSysOut("waiting game removed");
            }

            if (g.gameStatus == GameController.GAME_ACTIVE || g.gameStatus == GameController.GAME_STARTED
                    || g.gameStatus == GameController.GAME_ENDED) {

                if (g.players.size() < 2) {
                    activeGames.remove(g);
                    printSysOut("active game removed");
                } else {
                    quitGame(s, MessageBean.MSG_PLAYER_DISC);
                    printSysOut("Quitting session, telling opponent");
                }

            }
        }
    }

    @OnMessage
    public void onMessage(MessageBean message, Session session, @PathParam("id") String gameId) {
        printSysOut("Current active games: " + activeGames.size());
        printSysOut("Current waiting games: " + waitingGames.size());
        String players = "";
        int pCount = 0;
        for (Session s : session.getOpenSessions()) {
            if (!s.equals(session)) {
                String name = (String) s.getUserProperties().get("name");
                players += name;
                pCount++;
            }
        }
        printSysOut("Connected Players: " + players + " / " + pCount);

        try {

            processMessage(message, session);

        } catch (IOException ex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    public void sendGameAvailMessage(Session s, String gameId, Player host) {
        try {
            JSONObject obj = new JSONObject().put("cmd", MessageBean.MSG_GAME_AVAILABLE).put("data",
                    new JSONObject().put("id", gameId).put("host", host.getName()));

            s.getBasicRemote().sendText(obj.toString());
        } catch (IOException ex) {
            Logger.getLogger(Player.class.getName()).log(Level.SEVERE, null, ex);
        }

    }

    private void processMessage(MessageBean m, Session s) throws IOException {
        Player p, o;
        GameController g;

        switch (m.getCommand()) {

        case MessageBean.MSG_CHAT:
            doChatMessage(m, s);
            break;

        case MessageBean.MSG_PASS_MOVE_TOKEN:
            getGame(s).passMoveToken(s);
            break;

        case MessageBean.MSG_MOVE_ACTION:
            int c = Integer.parseInt(m.getData());
            getGame(s).dropPiece(s, c);
            printSysOut("player move: " + m.getData());
            break;

        case MessageBean.MSG_START_GAME:
            if (isAlreadyPlaying(s)) {
                break;
            }
            GameController game = new GameController();
            game.addPlayer(s);
            s.getUserProperties().put("gameid", game.getId());
            waitingGames.add(game);
            game.gameStatus = GameController.GAME_WAITING;

            s.getBasicRemote().sendText(Utils.assembleChatMessage("Server",
                    "ok, started game, waiting for players to join.", "server"));

            game.getPlayer(s).sendDataMessage(MessageBean.MSG_START_GAME, game.getId().toString());
            //sendDataMessage(s, , );
            printSysOut("start game: " + m.getData());
            break;

        case MessageBean.MSG_PLAYER_NAME:
            String name = m.getData();
            s.getUserProperties().put("name", name);
            printSysOut("user with name: " + name);
            for (Session ss : s.getOpenSessions()) {
                if (ss.equals(s))
                    continue;
                ss.getBasicRemote()
                        .sendText(Utils.assembleChatMessage("Server", "Player join lobby: " + name, "server"));
            }
            break;

        case MessageBean.MSG_JOIN_GAME:
            if (isAlreadyPlaying(s)) {
                break;
            }

            printSysOut("joingame: " + m.getData());
            g = joinGame(s, m);
            if (g != null) {
                try {
                    waitingGames.remove(g);
                } catch (Exception e) {
                    printSysOut("JOIN FAILED");
                }
            } else {
                printSysOut("NO GAME MATCH FOUND: " + m.getData());
                Utils.sendDataMessage(MessageBean.MSG_PLAYER_QUIT, "Game has expired!", s);
            }
            break;

        case MessageBean.MSG_JOIN_LOBBY_CHAT:
            s.getUserProperties().put("lobby", Boolean.parseBoolean(m.getData()));
            break;

        case MessageBean.MSG_GAME_AVAILABLE:
            if (isAlreadyPlaying(s)) {
                break;
            }
            synchronized (waitingGames) {
                if (waitingGames.isEmpty()) {
                    s.getBasicRemote().sendText(
                            Utils.assembleChatMessage("Server", "No games available, try starting one!", "server"));
                }
                for (GameController gc : waitingGames) {
                    sendGameAvailMessage(s, gc.getId().toString(), gc.players.get(0));
                }
            }
            break;

        case MessageBean.MSG_PLAYER_READY:
            g = getGame(s);
            if (g == null || g.gameStatus == GameController.GAME_STARTED)
                break;
            printSysOut("gamestate = " + g.gameStatus);
            p = g.getPlayer(s);
            o = g.getOpponent(s);

            p.ready = true;

            if (g.readyCheck()) {
                p.sendDataMessage(MessageBean.MSG_PLAYER_READY, "rdy");
                o.sendDataMessage(MessageBean.MSG_PLAYER_READY, "rdy");
                g.start();
            }
            break;

        case MessageBean.MSG_PLAYER_QUIT:
            quitGame(s, MessageBean.MSG_PLAYER_QUIT);
            break;

        case MessageBean.MSG_PLAYER_SELECT:
            g = getGame(s);
            if (g == null)
                break;
            p = g.getPlayer(s);
            p.imageId = Integer.parseInt(m.getData());
            o = g.getOpponent(s);
            if (o != null) {
                printSysOut("SENT DISABLE MESSAGE: " + p.imageId + " to: " + o.session.getId());
                o.sendDataMessage(MessageBean.MSG_PLAYER_SELECT, m.getData());
            }
            break;

        default:
            break;

        }

    }

    private GameController getGame(Session s) {
        return (GameController) s.getUserProperties().get("game");
    }

    @OnError
    public void onError(Throwable t) {
        printSysOut("wtf error: " + t.getMessage() + Arrays.toString(t.getStackTrace()));
        t.printStackTrace();
    }

    private synchronized void doChatMessage(MessageBean message, Session session) {
        String name = (String) session.getUserProperties().get("name");
        if (name == null) {
            name = "unknown";
        }

        String data = message.getData().replace("\\", "");
        data = data.replace("\"", "\\\"");

        for (Session s : session.getOpenSessions()) {
            try {
                if (s == session)
                    continue;

                if (s.getUserProperties().get("gameid").equals(session.getUserProperties().get("gameid"))) { // only send messages to people in same "game"
                    s.getBasicRemote().sendText(Utils.assembleChatMessage(name, data));

                } else if ((Boolean) s.getUserProperties().get("lobby") == true
                        && (Boolean) session.getUserProperties().get("lobby") == true) {
                    if (!session.getUserProperties().get("gameid").equals("lobby")) {
                        s.getBasicRemote().sendText(Utils.assembleChatMessage(name, data, "playing"));
                    } else {
                        s.getBasicRemote().sendText(Utils.assembleChatMessage(name, data, "lobby"));
                    }
                }
            } catch (IOException ex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private GameController joinGame(Session s, MessageBean m) throws IOException {
        synchronized (waitingGames) {
            for (GameController g : waitingGames) {
                if (g.getId().equals(UUID.fromString(m.getData()))) {
                    printSysOut("found game match");
                    g.addPlayer(s);
                    s.getUserProperties().put("gameid", g.getId());
                    activeGames.add(g);
                    g.gameStatus = GameController.GAME_ACTIVE;

                    printSysOut("goplayer: " + g.getOpponent(s).getName());
                    g.getPlayer(s).sendDataMessage(MessageBean.MSG_PLAYER_SELECT,
                            String.valueOf(g.getOpponent(s).imageId));
                    printSysOut("send disable image id: " + String.valueOf(g.getOpponent(s).imageId));

                    return g;
                } else {
                    printSysOut("NO GAME MATCH FOUND: " + m.getData());
                }
            }
        }
        return null;
    }

    private boolean isAlreadyPlaying(Session s) throws IOException {
        GameController g = getGame(s);
        if (g != null) {
            if (g.gameStatus == GameController.GAME_ACTIVE) {
                s.getBasicRemote()
                        .sendText(Utils.assembleChatMessage("Server", "Error, already playing game", "server"));
                return true;
            } else if (g.gameStatus == GameController.GAME_WAITING) {
                s.getBasicRemote()
                        .sendText(Utils.assembleChatMessage("Server", "Error, already waiting for game", "server"));
                return true;

                //            } else if (g.gameStatus == GameController.GAME_STARTED) {
                //
            } else if (g.gameStatus == GameController.GAME_ENDED) {
                s.getBasicRemote()
                        .sendText(Utils.assembleChatMessage("Server", "Please quit current match first", "server"));
                return true;

            }
        }

        return false;
    }

    private void quitGame(Session s, int reason) {
        printSysOut("got quitgame from : " + s.getId());
        GameController g = getGame(s);

        // TODO : fix quitgame to destroy any games attached when players quit!
        if (g == null) {
            printSysOut("quitgame game was null");
            return;
        }

        Player p = g.getPlayer(s);
        Player opponent = g.getOpponent(s);

        if (opponent != null) {
            // could still retrieve game if player reconnects
            // destroy only the player object from the game;
            // TODO implement this later, for now just close the game object

            opponent.sendDataMessage(reason, "quit");
            printSysOut("Quitting player removed: " + (getGame(s).players.remove(p)));

        } else { // no opponent, shutdown game;
            if (g.gameStatus == GameController.GAME_ACTIVE || g.gameStatus == GameController.GAME_STARTED
                    || g.gameStatus == GameController.GAME_ENDED) {
                printSysOut("Last player removed: " + (getGame(s).players.remove(p)));
                printSysOut("quitgame: removed active game");
                activeGames.remove(g);

            } else if (g.gameStatus == GameController.GAME_WAITING) {
                printSysOut("Last waiting player removed: " + (getGame(s).players.remove(p)));
                printSysOut("quitgame: removed waiting game");
                waitingGames.remove(g);
            }
        }

        printSysOut("players size: " + g.players.size());
        s.getUserProperties().remove("game");
        s.getUserProperties().put("gameid", "lobby");

    }

}//eof