Saturday, January 23, 2016

Multiplayer Card Game using WebSockets,Java Netty Server ,Cocos2d-x-HTML5 - Part 3


Game Server Source code overview 


TextWebSocketFrameHandler.java


This class has 2 parts.the first part will invoke the WebSocket HandShake mechanism that send confirmation back to the client so the connection will be upgraded to open TCP  socket connection .
The second part will handle the WebSocket Request and decode the incoming text to massage text for the Game Server to handle.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class TextWebSocketFrameHandler  extends SimpleChannelInboundHandler<TextWebSocketFrame>{
  private final static Logger LOG = LoggerManager.GetLogger(GameServerMain.class.getName());      
     private  GameManager gameManager;
     private  GameEventHandler gameEventHandler;
     public TextWebSocketFrameHandler(GameManager _gameManager,GameEventHandler _gameEventHandler) {
         this.gameManager = _gameManager;
         this.gameEventHandler = _gameEventHandler;
     }
     public TextWebSocketFrameHandler()
     {
          ;
     }
     @Override
     public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
          if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {
             ctx.pipeline().remove(HttpRequestHandler.class);
             JSONObject responseJson = new JSONObject();
    responseJson.put("event",Config.HANDSHAKE_COMPLETE_SUCCESS);     
    LOG.severe("HANDSHAKE_COMPLETE "+responseJson.toString());
             ctx.channel().writeAndFlush(new TextWebSocketFrame(responseJson.toString()));
         } else {
             super.userEventTriggered(ctx, evt);
         }
     }
     @Override
     public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
      msg.retain();
      TextWebSocketFrame frame = (TextWebSocketFrame) msg;
      String jsonRequest = frame.text(); 
      LOG.severe("Recived from client :"+jsonRequest); 
         try {          
          int playerId = this.gameEventHandler.handleEvent(jsonRequest,ctx.channel());
          if(playerId !=-1)
          {
           this.gameEventHandler.ResponseDispatcher(playerId,jsonRequest);
           Iterator<Entry<Integer, Player>> it = this.gameManager.getPlayers().entrySet().iterator();
              while (it.hasNext()) {
               @SuppressWarnings("rawtypes")
            Map.Entry pair = (Map.Entry)it.next();
                  Player playerIt = ((Player)pair.getValue());
                  String PlayerMassage = playerIt.getPlayerJson().toString();
                  responseToClient(playerIt,PlayerMassage);
                  LOG.severe("Sending to client id:"+String.valueOf(playerIt.getId())+" name:"+playerIt.getUserName()+" json:" +PlayerMassage);
              }
          }
          else
          {
           LOG.severe("Sending to clients Failed playerId is -1");
          }
             
         } finally {
             frame.release();
         }
     }
     private void responseToClient(Player _player,String responseJson)
  {
   _player.getChannel().writeAndFlush(new TextWebSocketFrame(responseJson));
  }
}


  1. Lines 14 - 23 : this is the WebSocket Handshak , remember the WebSocket dialog sequence between the client and the server performed in this order :
    A .the client send HTTP request to see if the server support WebSocket
    and inform the server the future connection type is WebSocket ,
    B. if confirmed by the server  the connection is UPGRADED  to TCP open connection between the client and the server , 
  2. Lines 28 - 29: the incoming request from the client as string.
  3. Line 32: send the string to Game Event Handler , which is a object that handle events and according to the event type it constructing and sending the response's back to the clients.
  4. Lines 35 - 44 : handle the response and send them back to the clients which are connected .
  5. Lines 55 - 58 : write the actual WebSocket Frame to the open connection channel.
    WebSocket Frame is encapsolated Netty object that handle WebSocket data .
    this is helper function which using the player Channel member to send the data .
GameManager.java

This class Is the "glue" that connects all the game logic It holds the Cards Map.
And the players map container and the response dispatcher.
and it should also have the Game event Handler which will be done in the next version .


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
public class GameManager {
 private final static Logger LOG = LoggerManager.GetLogger(GameServerMain.class.getName());
 private final String[] cardsNotRandomBase = {"c1","c2","c3","c4","c5","c6","c7","c8","c9","c10","c11","c12","c13","c14","c15","c16","c17","c18","c19","c20","c21","c22","c23","c24","c25","c26","c27","c28","c29","c30","c31","c32","c33","c34","c35","c36","c37","c38","c39","c40","c41","c42","c43","c44","c45","c46","c47","c48","c49","c50","c51","c52","c53"};
 private final String[] cardsRandomize;
 public final HashMap<String, String> cardsMap;
 private volatile Map<Integer, Player> players; 
 private LinkedList<String> cardsPlayDeck;
 private final GameResponseDispatcher gameResponseDispatcher;
 public GameManager( )
 {  
  cardsMap =  new HashMap<String, String>();
  setCardsHash();
  final ResourceBundle configurationBundle = ResourceBundle.getBundle("configuration");
  //hashmap with predictable iteration order
  players = new LinkedHashMap<Integer, Player>();
  cardsPlayDeck = new LinkedList<String>();   
  this.cardsRandomize = Arrays.copyOf(cardsNotRandomBase , cardsNotRandomBase .length);
  Collections.shuffle(Arrays.asList(cardsRandomize));
  gameResponseDispatcher = new GameResponseDispatcher(this);
 }
 public GameResponseDispatcher getGameResponseDispatcher() {
  return gameResponseDispatcher;
 }

 public HashMap<String, String> getCardsMap() {
  return cardsMap;
 }
 public LinkedList<String> getCardsPlayDeck() {
  return cardsPlayDeck;
 }

 public void setCardsPlayDeck(LinkedList<String> cardsPlayDeck) {
  this.cardsPlayDeck = cardsPlayDeck;
 }
 public int getPlayerIndexByKey(int playerKey)
 {
  int pos = new ArrayList<Integer>(players.keySet()).indexOf(playerKey);
  return pos;
 }
 public Player getPlayerByIndex(int inx)
 {
  List<Player> l = new ArrayList<Player>(players.values());
  Player p = l.get(inx);
  return p;
 }
 public Map<Integer, Player> getPlayers() {
  return players;
 }
 public void setPlayers(Map<Integer, Player> players) {
  this.players = players;
 }
 public String[] getCardsRandomize() {
  return cardsRandomize;
 }
 public String getCardsRandomizeByIndex(int i) {
  return cardsRandomize[i];
 }
 public int getCardValueById(String cardId)
 {
  String card = this.cardsMap.get(cardId);
  String rightPart= card.split("_")[1];
  String number = rightPart.split(".png")[0];
  int cardIntVal = Integer.valueOf(number);
  return cardIntVal;
 }
 public int getNextActivePlayer(int currentActivePlayer)
 {
  int currentPlyInx = getPlayerIndexByKey(currentActivePlayer);
  int activePlayer = 0;
  if(currentPlyInx < (players.size()-1))
  {
   ++activePlayer;
  }
  return activePlayer;
 }
 private void setCardsHash()
 {
  cardsMap.put("c1","cardClubsA_20.png");
  cardsMap.put("c2","cardClubsJ_17.png");
  cardsMap.put("c3","cardClubsK_19.png");
  cardsMap.put("c4","cardClubsQ_18.png");
  cardsMap.put("c5","cardDiamonds10_10.png");
  cardsMap.put("c6","cardDiamonds2_2.png");
  cardsMap.put("c7","cardDiamonds3_3.png");
  cardsMap.put("c8","cardDiamonds4_4.png");
  cardsMap.put("c9","cardDiamonds5_5.png");
  cardsMap.put("c10","cardDiamonds6_6.png");
  cardsMap.put("c11","cardDiamonds7_7.png");
  cardsMap.put("c12","cardDiamonds8_8.png");
  cardsMap.put("c13","cardDiamonds9_9.png");
  cardsMap.put("c14","cardDiamondsA_20.png");
  cardsMap.put("c15","cardDiamondsJ_17.png");
  cardsMap.put("c16","cardDiamondsK_19.png");
  cardsMap.put("c17","cardDiamondsQ_18.png");
  cardsMap.put("c18","cardHearts10_10.png");
  cardsMap.put("c19","cardHearts2_2.png");
  cardsMap.put("c20","cardHearts3_3.png");
  cardsMap.put("c21","cardHearts4_4.png");
  cardsMap.put("c22","cardHearts5_5.png");
  cardsMap.put("c23","cardHearts6_6.png");
  cardsMap.put("c24","cardHearts7_7.png");
  cardsMap.put("c25","cardHearts8_8.png");
  cardsMap.put("c26","cardHearts9_9.png");
  cardsMap.put("c27","cardHeartsA_20.png");
  cardsMap.put("c28","cardHeartsJ_17.png");
  cardsMap.put("c29","cardHeartsK_19.png");
  cardsMap.put("c30","cardHeartsQ.png");
  cardsMap.put("c31","cardJoker_21.png");
  cardsMap.put("c32","cardSpades10_10.png");
  cardsMap.put("c33","cardSpades2_2.png");
  cardsMap.put("c34","cardSpades3_3.png");
  cardsMap.put("c35","cardSpades4_4.png");
  cardsMap.put("c36","cardSpades5_5.png");
  cardsMap.put("c37","cardSpades6_6.png");
  cardsMap.put("c38","cardSpades7_7.png");
  cardsMap.put("c39","cardSpades8_8.png");
  cardsMap.put("c40","cardSpades9_9.png");
  cardsMap.put("c41","cardSpadesA_20.png");
  cardsMap.put("c42","cardSpadesJ_17.png");
  cardsMap.put("c43","cardSpadesK_19.png");
  cardsMap.put("c44","cardSpadesQ_18.png");
  cardsMap.put("c45","cardClubs10_10.png");
  cardsMap.put("c46","cardClubs2_2.png");
  cardsMap.put("c47","cardClubs3_3.png");
  cardsMap.put("c48","cardClubs4_4.png");
  cardsMap.put("c49","cardClubs5_5.png");
  cardsMap.put("c50","cardClubs6_6.png");
  cardsMap.put("c51","cardClubs7_7.png");
  cardsMap.put("c52","cardClubs8_8.png");
  cardsMap.put("c53","cardClubs9_9.png");
 }
 }


  1. Line 3 : array of the cards. those are the key names of the game cards are sorted by order. 
  2. Line 5 : the map which maps between the cards names and the cards key names.
  3. Line 6 : the players container from type Ordered Map . the key set by the order the player login.
  4. Line 7: is the deck of cards in between the players,where each player show its cards in its turn.
  5. Lines 17-18:shuffle the cards .
  6. The rest are just simple small helper functions and getters and setters that are self explanatory.
We Are ready now to continue with the Game Server Code overview .
Next we going to analize the game logic continue to the next post :

Multiplayer Card Game using WebSockets,Java Netty Server ,Cocos2d-x-HTML5 - Part 4

No comments:

Post a Comment