diff --git a/src/card/Card.java b/src/card/Card.java index 7deee28..96ade6e 100644 --- a/src/card/Card.java +++ b/src/card/Card.java @@ -109,41 +109,41 @@ return id; } - public JSONObject toJson() throws JSONException { - // TODO: handle dummy card - JSONObject root = new JSONObject(); - root.put("value", value); - root.put("id", id); - root.put("color", color); - root.put("cardInfos", cardInfosToJson()); - return root; - } +// public JSONObject toJson() throws JSONException { +// // TODO: handle dummy card +// JSONObject root = new JSONObject(); +// root.put("value", value); +// root.put("id", id); +// root.put("color", color); +// root.put("cardInfos", cardInfosToJson()); +// return root; +// } - private JSONArray cardInfosToJson() throws JSONException { - JSONArray infoArray = new JSONArray(); - if(cardInfos == null) return infoArray; - for(CardInfo ci : cardInfos){ - infoArray.put(ci.toJson()); - } - return infoArray; - } +// private JSONArray cardInfosToJson() throws JSONException { +// JSONArray infoArray = new JSONArray(); +// if(cardInfos == null) return infoArray; +// for(CardInfo ci : cardInfos){ +// infoArray.put(ci.toJson()); +// } +// return infoArray; +// } - private void fromJson(JSONObject jo) throws JSONException { - // TODO: handle dummy card - cardInfos = new ArrayList<>(); - int color = jo.getInt("color"); - int value = jo.getInt("value"); - int id = jo.getInt("id"); - JSONArray cardInfoArray = jo.getJSONArray("cardInfos"); - for(int i=0; i(); +// int color = jo.getInt("color"); +// int value = jo.getInt("value"); +// int id = jo.getInt("id"); +// JSONArray cardInfoArray = jo.getJSONArray("cardInfos"); +// for(int i=0; i 0 && b < MSG_FIRST_MSG) return MsgByteCat.MOVE; - if(b >= MSG_FIRST_MSG && b <= MSG_LAST_MSG) return MsgByteCat.MSG; - return MsgByteCat.INVALID; - } + /* MUST start with 0 and MUST end with MSG_LAST_MSG, and MUST be contiguous */ + public static final byte MSG_YOURTURN = 0; + public static final byte MSG_READY = 1; + public static final byte MSG_UNREADY = 2; + public static final byte MSG_INVALID = 3; //FIXME first, fix all other errors (META_MOVE_INVALID) + public static final byte MSG_VALID = 4; //FIXME first, fix all other errors (META_MOVE_VALID) + public static final byte MSG_WON = 5; + public static final byte MSG_LOST = 6; + public static final byte MSG_LEAVE = 7; + public static final byte MSG_CONNECTION_VALID = 8; + public static final byte MSG_CONNECTION_INVALID = 9; + public static final byte MSG_MOVE = 10; + public static final byte MSG_UPDATE = 11; + public static final byte MSG_LAST_MSG = MSG_UPDATE; - private static void throwOnWrongMsgByte(byte b, MsgByteCat shouldBe) { - MsgByteCat is = msgByteCat(b); - if(is != shouldBe) { - throw new InternalHanabiError("Message type is " + is + ", but it should be " + shouldBe + "."); - } + private static void throwOnInvalidMsgType(byte b) { + if(b < 0 || b > MSG_LAST_MSG) throw new RuntimeException("Invalid message Type " + b + "."); } - private int origin; private byte msgType; - private Move move; - //private JSONObject jo; - public Message(byte mT) { this(-1, mT); } - public Message(byte mT, Move m) { this(-1, mT, m); } - - public Message(int o, byte mT) { - throwOnWrongMsgByte(mT, MsgByteCat.MSG); - origin = o; - setMsgType(mT); + private Move move; + + private int ownId; + + public Message(byte msgType) { + throwOnInvalidMsgType(msgType); + setMsgType(msgType); } - public Message(int o, byte moveType, Move m) { - throwOnWrongMsgByte(moveType, MsgByteCat.MOVE); - origin = o; - setMsgType(moveType); - move = m; + public Message(Move m) { + setMsgType(MSG_MOVE); + move = m; // TODO: clone? } //public Message(JSONObject jo) throws JSONException { @@ -103,57 +80,57 @@ return msgType; } - public int getOrigin() { - return origin; +// public int getOrigin() { +// return origin; +//// try { +//// return jo.getInt("origin"); +//// } catch(JSONException ex) { +//// throw new InternalHanabiError(ex); +//// } +// } + +// public void setOrigin(int orig) { origin = orig; } + +// public int getHintType() { +// if(msgType != MSG_MOVE) { +// throw new RuntimeException("Internal Error: Hint type of non-hint move requested."); +// } +// return move.getHintType(); +// } +// +// public int getValue() { +// if(msgType != Move.HINT) { +// throw new RuntimeException("Internal Error: Hint value of non-hint message requested."); +// } // try { -// return jo.getInt("origin"); +// return jo.getInt("value"); // } catch(JSONException ex) { // throw new InternalHanabiError(ex); // } - } +// } +// public int getHintRecipient() { +// if(msgType != Move.HINT) { +// throw new RuntimeException("Internal Error: Target player ID of non-hint message requested."); +// } +// try { +// return jo.getInt("playerId"); +// } catch(JSONException ex) { +// throw new InternalHanabiError(ex); +// } +// } - public void setOrigin(int orig) { origin = orig; } - - public int getHintType() { - if(msgType != Move.HINT) { - throw new RuntimeException("Internal Error: Hint type of non-hint move requested."); - } - try { - return jo.getInt("type"); - } catch(JSONException ex) { - throw new InternalHanabiError(ex); - } - } - public int getValue() { - if(msgType != Move.HINT) { - throw new RuntimeException("Internal Error: Hint value of non-hint message requested."); - } - try { - return jo.getInt("value"); - } catch(JSONException ex) { - throw new InternalHanabiError(ex); - } - } - public int getHintRecipient() { - if(msgType != Move.HINT) { - throw new RuntimeException("Internal Error: Target player ID of non-hint message requested."); - } - try { - return jo.getInt("playerId"); - } catch(JSONException ex) { - throw new InternalHanabiError(ex); - } - } - public int getOwnId() { if(msgType != MSG_CONNECTION_VALID) { throw new RuntimeException("Internal Error: ownId of non-connection valid message requested."); } - try { - return jo.getInt("id"); - } catch(JSONException ex) { - throw new InternalHanabiError(ex); + return ownId; + } + + public void setOwnId(int id) { + if(msgType != MSG_CONNECTION_VALID) { + throw new RuntimeException("Internal Error: Attempt to set ownId of non-connection valid message."); } + ownId = id; } public static Message makeInvalidMoveAnswer(Message m) { @@ -165,19 +142,18 @@ } public boolean isNonMove() { - return msgByteCat(msgType) == MsgByteCat.MSG; - //return msgType >= MSG_FIRST_MSG; + return msgType != MSG_MOVE; } public void setMsgType(byte msgType) { this.msgType = msgType; - try { - jo.put("msgType", msgType); - } catch (JSONException ex) { - throw new InternalHanabiError(ex); - } } + public Move getMove() { return move; } -} + + public void setMove(Move move) { + this.move = move; // TODO clone? + } +} \ No newline at end of file diff --git a/src/server/Move.java b/src/server/Move.java new file mode 100644 index 0000000..02cdd90 --- /dev/null +++ b/src/server/Move.java @@ -0,0 +1,70 @@ +package server; + +public class Move { + public static final byte[] MAGIC = { 1, 3, 3, 7 }; + + public static final byte DRY = 1 << 5; + public static final byte PLACE_CARD = 3; + public static final byte TRASH_CARD = 4; + public static final byte HINT = 5; + + public static final byte HINT_COLOR = 0; + public static final byte HINT_VALUE = 1; + + private int moveType; + + private int hintType; + private int hintRecipient; + private int value; + private int color; + + public Move(byte mT) { + setMoveType(mT); + } + + public int getMoveType() { return moveType; } + + public int getHintType() { + if(moveType != HINT) { + throw new RuntimeException("Internal Error: Hint type of non-hint move requested."); + } + return hintType; + } + public int getValue() { + if(moveType == HINT && hintType == HINT_COLOR) { + throw new RuntimeException("Internal Error: Value of color hint requested."); + } + return value; + } + + public int getColor() { + if(moveType == HINT && hintType == HINT_VALUE) { + throw new RuntimeException("Internal Error: Color of value hint requested."); + } + return color; + } + + public int getHintRecipient() { + if(moveType != HINT) { + throw new RuntimeException("Internal Error: Target player ID of non-hint move requested."); + } + return hintRecipient; + } + + public void setMoveType(byte moveType) { + this.moveType = moveType; + } + + public void setHintType(int type) { + if(moveType != HINT) throw new InternalHanabiError("Attempt to set hint type of non-hint."); + hintType = type; + } + + public void setColor(int color) { + this.color = color; + } + + public void setValue(int value) { + this.value = value; + } +} diff --git a/src/server/ServerGame.java b/src/server/ServerGame.java index f28c362..d1b376b 100644 --- a/src/server/ServerGame.java +++ b/src/server/ServerGame.java @@ -296,15 +296,15 @@ return true; } - protected boolean giveHint(int type, int value, int playerId){ + protected boolean giveHint(int type, int value, int playerId) { if(!hintAvailable()) return false; if(currentPlayer == playerId) return false; Card[] cards = getPlayer(playerId).getCards(); - for(Card c : cards){ + for(Card c : cards) { boolean is = false; - if(type == Message.HINT_COLOR) is = c.getColorInt() == value; - else if(type == Message.HINT_VALUE) is = c.getValue() == value; - else throw new RuntimeException(); // TODO "vorerst" + if(type == Move.HINT_COLOR) is = c.getColorInt() == value; + else if(type == Move.HINT_VALUE) is = c.getValue() == value; + else throw new InternalHanabiError("Attempt to give hint which is neither color nor value hint."); c.addCardInfo(type, is, value, currentPlayer); } removeHint(); @@ -486,7 +486,7 @@ byte msgType = m.getMsgType(); if(m.isNonMove()) { switch(msgType) { - case Message.MAG_READY: { + case Message.MSG_READY: { Client client = clients.get(m.getOrigin()); synchronized (clients) { if(client.isReady) break; @@ -529,9 +529,10 @@ isMove = true; break; case Move.HINT: - int hintType = m.getHintType(); - int value = m.getValue(); - int player = m.getHintRecipient(); + Move move = m.getMove(); + int hintType = move.getHintType(); + int value = move.getValue(); + int player = move.getHintRecipient(); isValid = giveHint(hintType, value, player); isMove = true; break; diff --git a/src/server/VibeDumb.java b/src/server/VibeDumb.java index 148a1f5..90b2adf 100644 --- a/src/server/VibeDumb.java +++ b/src/server/VibeDumb.java @@ -27,13 +27,14 @@ byte version = 0; byte msgType = m.getMsgType(); byte[] unused = new byte[]{ 0, 0 }; - String msg = m.toJsonString(); outStream.write(MAGIC); outStream.write(version); outStream.write(msgType); outStream.write(unused); - outStream.writeUTF(msg); + if(msgType == Message.MSG_MOVE) outStream.writeUTF(moveToJsonString(m.getMove())); + else if(msgType == Message.MSG_CONNECTION_VALID) outStream.writeInt(m.getOwnId()); } + public Message receiveMsg() throws IOException { if(inStream == null) { inStream = conn.getInputStream(); @@ -44,33 +45,95 @@ byte[] unused = new byte[2]; inStream.read(magic); if(!isMagicCorrect(magic)) { - throw new InternalHanabiError(); // TODO + throw new InternalHanabiError("Malformed message (wrong magic number)."); } version = inStream.readByte(); switch(version) { case 0: // TODO magic number? break; default: - throw new InternalHanabiError(); // TODO + throw new InternalHanabiError("Version " + version + " of protocol doesn't exist."); } msgType = inStream.readByte(); inStream.read(unused); - String msg = inStream.readUTF(); // TODO ddos? - if(msg == null) throw new InternalHanabiError(); // TODO + Message m = new Message(msgType); + if(msgType == Message.MSG_MOVE) { + String msg = inStream.readUTF(); // TODO ddos? + if(msg == null) throw new InternalHanabiError("Purported move doesn't exist."); + try { + m.setMove(jsonToMove(new JSONObject(msg))); + } catch(JSONException ex) { + throw new InternalHanabiError(ex); + } + } else if(msgType == Message.MSG_CONNECTION_VALID) { + m.setOwnId(inStream.readInt()); + } + return m; + } + + private static String moveToJsonString(Move move) { try { - Message m; - if(msg.equals("")) { - m = new Message(msgType); - } else { - JSONObject jo = new JSONObject(msg); - m = new Message(jo); - m.setMsgType(msgType); - } - return m; + JSONObject jo = new JSONObject(); + byte moveType = (byte) move.getMoveType(); + jo.put(Keys.VibeDumb.MOVE_TYPE, moveType); + // TODO: dry moves + switch(moveType) { + case Move.HINT: + int type = move.getHintType(); + jo.put(Keys.VibeDumb.HINT_TYPE, type); + if(type == Move.HINT_COLOR) { + jo.put(Keys.VibeDumb.COLOR, move.getColor()); + } else if(type == Move.HINT_VALUE) { + jo.put(Keys.VibeDumb.VALUE, move.getValue()); + } else { + throw new InternalHanabiError("Unknown hint type."); + } + break; + case Move.PLACE_CARD: + case Move.TRASH_CARD: + jo.put(Keys.VibeDumb.COLOR, move.getColor()); + jo.put(Keys.VibeDumb.VALUE, move.getValue()); + break; + default: + throw new InternalHanabiError("Move is neither hint nor place nor trash."); + } + return jo.toString(); } catch(JSONException ex) { throw new InternalHanabiError(ex); } } + + private static Move jsonToMove(JSONObject jo) { + try { + byte moveType = (byte)jo.getInt(Keys.VibeDumb.MOVE_TYPE); + Move move = new Move(moveType); + // TODO: dry moves + switch(moveType) { + case Move.HINT: + int type = jo.getInt(Keys.VibeDumb.HINT_TYPE); + move.setHintType(type); + if(type == Move.HINT_COLOR) { + move.setColor(jo.getInt(Keys.VibeDumb.COLOR)); + } else if(type == Move.HINT_VALUE) { + move.setValue(jo.getInt(Keys.VibeDumb.VALUE)); + } else { + throw new InternalHanabiError("Unknown hint type."); + } + break; + case Move.PLACE_CARD: + case Move.TRASH_CARD: + move.setColor(jo.getInt(Keys.VibeDumb.COLOR)); + move.setValue(jo.getInt(Keys.VibeDumb.VALUE)); + break; + default: + throw new InternalHanabiError("Move is neither hint nor place nor trash."); + } + return move; + } catch(JSONException ex) { + throw new InternalHanabiError(ex); + } + } + public void establish() throws IOException { // FIXME conn.establishConnection();