Game Server Source code overview
Tutorial Source code :
Remember the opening of this tutorial i mentioned that one of MMO principles is that the game
is played in the server and not in the client most of the times. to avoid cheating on the client and abusing the game .
In this class the data that is send from the client include events to invoke.
Those events are like "Protocol" between the client and the server both sides should understand them
in our case they are :
Config.java
1 2 3 4 5 6 7 | //when the websocket http handshake complete public static final int HANDSHAKE_COMPLETE_SUCCESS = 1; public static final int LOGIN = 2; public static final int LOGIN_DONE = 3; public static final int NEW_USER_LOGIN_DONE = 4; public static final int PLAY = 5; public static final int PLAY_DONE = 6; |
- Line 2 : when Websocket protocol is confirmed.
- Line 3: Login request form the client .
- Line 4: Login is handled , response to client that login is done
- Line 5: New User is joined the room
- Line 6: Player is done its turn and played.
- Line 7 :Response to all other player and the current player that the turn is done
This class will handle the game logic here is where the server "Plays" the game
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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | public class GameEventHandler { private final static Logger LOG = LoggerManager.GetLogger(GameEventHandler.class.getName()); private GameManager gameManager; private static int playerIdCounter = 0; private static int playerRegistretionCounter = 0; public GameEventHandler(GameManager _gameManager) { this.gameManager = _gameManager; } public int handleEvent(String _jsonRequest,Channel channel) { JSONObject jsonObject = new JSONObject(_jsonRequest); int Event = jsonObject.getInt("event"); int playerId = -1; String userName = jsonObject.getString("username"); switch(Event) { case Config.LOGIN: { Player newPlayer = setPlayerNewAttributes(userName,channel,Config.LOGIN_DONE); setPlayerInPlayersContainer(newPlayer); playerId = newPlayer.getId(); break; } case Config.PLAY: { playerId = invokePlayEvent(jsonObject); } } return playerId; } public boolean ResponseDispatcher(int _playerId,String _jsonRequest) { JSONObject jsonObject = new JSONObject(_jsonRequest); int Event = jsonObject.getInt("event"); boolean bDone = false; switch(Event) { case Config.LOGIN: { bDone = this.gameManager.getGameResponseDispatcher().ResponseDispatcheLoginDone(_playerId); break; } case Config.PLAY: { bDone = this.gameManager.getGameResponseDispatcher().ResponseDispatchePlayDone(_playerId); break; } } return bDone; } private int invokePlayEvent(JSONObject _jsonObject) { int activePlayerId = _jsonObject.getInt("id"); int currentPlayerID = this.gameManager.getPlayers().get(activePlayerId).getActiveplayerid(); //validation of turn if(activePlayerId==currentPlayerID) { //find out who is the previous player int playerInx = getPreviousePlayerIndex(currentPlayerID); String currentPlayerCardId = this.gameManager.getPlayers().get(activePlayerId).getActivecardid(); //check if the cards deck is active in there are cards in it if(this.gameManager.getCardsPlayDeck().size()>0) { String prevCardId = this.gameManager.getCardsPlayDeck().getFirst(); //check which card has greater value int prevCardValue = this.gameManager.getCardValueById(prevCardId); int currentCardValue = this.gameManager.getCardValueById(currentPlayerCardId); //check if previous card is greater if(prevCardValue > currentCardValue) { //set the cards to the winner which is previous player this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().addLast(currentPlayerCardId); this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().addLast(prevCardId); //set as winner this.gameManager.getPlayerByIndex(playerInx).setWinner(playerInx); this.gameManager.getPlayerByIndex(playerInx).setWinnercards(currentPlayerCardId+"_"+prevCardId); this.gameManager.getPlayerByIndex(currentPlayerID).setWinner(playerInx); this.gameManager.getPlayerByIndex(currentPlayerID).setWinnercards(currentPlayerCardId+"_"+prevCardId); String currentCartId = this.gameManager.getPlayers().get(activePlayerId).getPlayerCards().getFirst(); this.gameManager.getPlayers().get(activePlayerId).setActivecardid(currentCartId); String cardInDeck = this.gameManager.getCardsPlayDeck().getFirst(); this.gameManager.getPlayerByIndex(playerInx).setDeckcard(cardInDeck); this.gameManager.getCardsPlayDeck().clear(); } //check if current card is greater else if(prevCardValue < currentCardValue) { String prevPlayerCardId = this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().removeFirst(); this.gameManager.getPlayers().get(currentPlayerID).getPlayerCards().addLast(prevPlayerCardId); //set as winner this.gameManager.getPlayerByIndex(playerInx).setWinner(playerInx); this.gameManager.getPlayerByIndex(playerInx).setWinnercards(currentPlayerCardId+"_"+prevPlayerCardId); this.gameManager.getPlayerByIndex(currentPlayerID).setWinner(playerInx); this.gameManager.getPlayerByIndex(currentPlayerID).setWinnercards(currentPlayerCardId+"_"+prevPlayerCardId); String currentCartId = this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerInx).setActivecardid(currentCartId); String cardInDeck = this.gameManager.getCardsPlayDeck().getFirst(); this.gameManager.getPlayerByIndex(playerInx).setDeckcard(cardInDeck); this.gameManager.getCardsPlayDeck().clear(); } else if(prevCardValue == currentCardValue) { String PreviousePlayerCards[] = getWarCards(playerInx); String currentPlayerCards[] = getWarCards(currentPlayerID); int prevCardValue_4 = this.gameManager.getCardValueById(PreviousePlayerCards[3]); int currentCardValue_4 = this.gameManager.getCardValueById(currentPlayerCards[3]); //check who is the winner if(prevCardValue_4 > currentCardValue_4) { String result = CardsArrayToString(PreviousePlayerCards,currentPlayerCards); this.gameManager.getPlayerByIndex(playerInx).setWinner(1); this.gameManager.getPlayerByIndex(playerInx).setWinnercards(result); String currentCartId = this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerInx).setActivecardid(currentCartId); } else if(prevCardValue_4 < currentCardValue_4) { String result = CardsArrayToString(currentPlayerCards,PreviousePlayerCards); this.gameManager.getPlayerByIndex(currentPlayerID).setWinner(1); this.gameManager.getPlayerByIndex(currentPlayerID).setWinnercards(result); String currentCartId = this.gameManager.getPlayerByIndex(currentPlayerID).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(currentPlayerID).setActivecardid(currentCartId); } else if(prevCardValue_4 == currentCardValue_4) { //TODO int test =0; } this.gameManager.getCardsPlayDeck().clear(); } } else { this.gameManager.getCardsPlayDeck().addFirst(currentPlayerCardId); this.gameManager.getPlayers().get(activePlayerId).getPlayerCards().removeFirst(); String currentCartId = this.gameManager.getPlayers().get(activePlayerId).getPlayerCards().getFirst(); this.gameManager.getPlayers().get(activePlayerId).setActivecardid(currentCartId); String cardInDeck = this.gameManager.getCardsPlayDeck().getFirst(); this.gameManager.getPlayers().get(activePlayerId).setDeckcard(cardInDeck); } //Check if there are winners for this game int prevPlayerCardsSize = this.gameManager.getPlayerByIndex(playerInx).getPlayerCards().size(); if(prevPlayerCardsSize==0) { //game is ended this.gameManager.getPlayerByIndex(playerInx).setEndgame(currentPlayerID); this.gameManager.getPlayerByIndex(currentPlayerID).setEndgame(currentPlayerID); } } else { activePlayerId =-1; } return activePlayerId; } private String CardsArrayToString(String[] cardsPrev,String[] cardsCurrent) { String result =""; for (String s: cardsPrev) { //Do your stuff here result+=s; result+="_"; } for (String s: cardsCurrent) { //Do your stuff here result+=s; result+="_"; } result = result.substring(0, result.length()-1); return result; } private String[] getWarCards(int playerID) { String prevPlayerCardId_1 = this.gameManager.getPlayerByIndex(playerID).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerID).getPlayerCards().removeFirst(); String prevPlayerCardId_2 = this.gameManager.getPlayerByIndex(playerID).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerID).getPlayerCards().removeFirst(); String prevPlayerCardId_3 = this.gameManager.getPlayerByIndex(playerID).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerID).getPlayerCards().removeFirst(); //the fourth card is to play the war String prevPlayerCardId_4 = this.gameManager.getPlayerByIndex(playerID).getPlayerCards().getFirst(); this.gameManager.getPlayerByIndex(playerID).getPlayerCards().removeFirst(); return new String[]{prevPlayerCardId_1, prevPlayerCardId_2,prevPlayerCardId_3,prevPlayerCardId_4}; } private int getPreviousePlayerIndex(int _currentPlayerID) { //find out who is the previous player int playerInx = this.gameManager.getPlayerIndexByKey(_currentPlayerID); if(playerInx == 0) { int playerSize = this.gameManager.getPlayers().size(); playerInx = playerSize-1; } else { --playerInx; } return playerInx; } private Player setPlayerNewAttributes(String _userName,Channel channel,int nextEvent) { Player newPlayer = new Player(channel); newPlayer.setUserName(_userName); int id = GenerateUniqueId(); int count = getPlayerRegistretionCounter(); newPlayer.setRegistertionNum(count); newPlayer.setId(id); newPlayer.setEvent(nextEvent); setPlayerCards(newPlayer); setNewPlayerCardId(newPlayer); return newPlayer; } private void setPlayerInPlayersContainer(Player _player) { this.gameManager.getPlayers().put(_player.getId(), _player); } private void setPlayerCards(Player _player) { //this is only good for 2 players int len = this.gameManager.getCardsRandomize().length-1; if(_player.getId()==0) { for(int i=0;i<(len/2);i++) { _player.getPlayerCards().push(this.gameManager.getCardsRandomizeByIndex(i)); } } else if(_player.getId()==1) { for(int i=len;i>(len/2);i--) { _player.getPlayerCards().push(this.gameManager.getCardsRandomizeByIndex(i)); } } } private void setNewPlayerCardId(Player _player) { String cardId = _player.getPlayerCards().removeFirst(); _player.setActivecardid(cardId); } private int GenerateUniqueId() { int id = this.playerIdCounter; this.playerIdCounter++; return id; } private int getPlayerRegistretionCounter() { int count = this.playerRegistretionCounter; this.playerRegistretionCounter++; return count; } } |
- Lines 18 -24: In this simple card game we have 2 main events first is when player login to the game .
And the second is when player plays it turn .
This is where the first case get handled.the client sent the server LOGIN event .
And the Server do several things:
A. Creates new Player object
B. Updates the Player properties
C. Set the Player object into the Players Container ( in GameManger object ) .
D. Associate unique id to the player. - Lines 25 -29: The second event as mentioned in the previous section,is when the player makes
its turn . the client will send the PLAY event .
when this event triggered in the server , the server will play the game and update the game states for each other players in the game. - Lines 33 - 50: This function will dispatch the response according to the Event that is currently
get handled by the server. - Lines 56 -59: The invokePlayEvent is big function , it handles the game logic and updates The other players (in the server ) with the new game states .
First we need to know that the player which we handling is the one that playing now its turn.
in the JSON structure that is passing between the client and the server
and also on of the Player Member called : activeplayerid .This member will hold the id of the Player that is currently playing . - Lines 63 -66: Get the previous player. this is turn based game so we need to check what did the previous player done , and to compare between the current Player status and the previous Player Status.
- Lines 75 - 92: In our game there could be 2 states in the game:
First when the middle card deck is empty and one of the players should play its turn
Second is when there is already a card on the middle deck so the player now should:
A. Play its card.
B. Compare between this current player card and the previous player card .
Here we check if the previous card is greater then current player card .
Then the following actions are made in the server :
A.Update the winner player ( previous player ) with the winning cards.
B.Update the current player about the winner player.
C.Clear the middle card deck. - Lines 96 -116: Check if the current player is the winner by comparing the cards values
and doing the same as we did in section 6 above . but this time set current player as winner. - Lines 120 - 145: Check if the cards value are the same , in this case the War Card game rule
is that we take 4 cards from each player (lines: 123 -124). and the last (lines 126 -127 ) card
is the card that we are going to check .
Again like in sections 6. and 7. the cards values is compared to determine who is the winner . - Lines 146 -150: to keep this code simple as possible the game support only 1 level of WAR state . so if there is again WAR between the cards there is a need to implement the WAR handling again . maybe to separate it to sub-function and call it again .
i leave it to you as exercise ... - Lines 156 - 162: This is the case where the previous player didn't played , so the current player
is the one that play first. that means putting the card on the middle card deck.
A.Update the middle card deck with current player card.
B.Remove the played card from the player card stack.
C.Update the other player with the card which played. - Lines 168 -173: To determine who is the winner in the game the logic is to check if the previous players card stack is empty , if its empty so the current player is the winner .
and the game Ended.
of course we need to update the players and the server that the game is ended .
by setting the player member : endgame with the winning player id .
Now we are ready to learn how the response to clients is dispatched . in the next post:
Multiplayer Card Game using WebSockets,Java Netty Server ,Cocos2d-x-HTML5 - Part 5
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.