Advertisement
Guest User

Untitled

a guest
Apr 26th, 2016
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 15.88 KB | None | 0 0
  1. /*
  2.  * This file is part of RuneSource.
  3.  *
  4.  * RuneSource is free software: you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation, either version 3 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * RuneSource is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with RuneSource.  If not, see <http://www.gnu.org/licenses/>.
  16.  */
  17.  
  18. import java.io.IOException;
  19. import java.nio.ByteBuffer;
  20. import java.nio.channels.SelectionKey;
  21. import java.nio.channels.SocketChannel;
  22. import java.security.SecureRandom;
  23. import java.util.Arrays;
  24.  
  25. /**
  26.  * The class behind a Player that handles all networking-related things.
  27.  *
  28.  * @author blakeman8192
  29.  */
  30. public abstract class Client {
  31.  
  32.     private final SelectionKey key;
  33.     private final ByteBuffer inData;
  34.     private final Player player = (Player) this;
  35.     private final Misc.Stopwatch timeoutStopwatch = new Misc.Stopwatch();
  36.     private SocketChannel socketChannel;
  37.  
  38.     private Stage stage;
  39.     private int packetOpcode = -1;
  40.     private int packetLength = -1;
  41.     private String username;
  42.     private String password;
  43.     private ISAACCipher encryptor;
  44.     private ISAACCipher decryptor;
  45.  
  46.     /**
  47.      * Creates a new Client.
  48.      *
  49.      * @param key
  50.      *            the SelectionKey of the client
  51.      */
  52.     public Client(SelectionKey key) {
  53.         this.key = key;
  54.         setStage(Stage.CONNECTED);
  55.         inData = ByteBuffer.allocateDirect(512);
  56.         if (key != null) {
  57.             socketChannel = (SocketChannel) key.channel();
  58.         }
  59.     }
  60.  
  61.     /**
  62.      * Called after the player finishes logging in.
  63.      *
  64.      * @throws Exception
  65.      */
  66.     public abstract void login() throws Exception;
  67.  
  68.     /**
  69.      * Called before the player disconnects.
  70.      *
  71.      * @throws Exception
  72.      */
  73.     public abstract void logout() throws Exception;
  74.  
  75.     /**
  76.      * Sends all skills to the client.
  77.      */
  78.     public void sendSkills() {
  79.         for (int i = 0; i < player.getSkills().length; i++) {
  80.             sendSkill(i, player.getSkills()[i], player.getExperience()[i]);
  81.         }
  82.     }
  83.  
  84.     /**
  85.      * Sends the skill to the client.
  86.      *
  87.      * @param skillID
  88.      *            the skill ID
  89.      * @param level
  90.      *            the skill level
  91.      * @param exp
  92.      *            the skill experience
  93.      */
  94.     public void sendSkill(int skillID, int level, int exp) {
  95.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(8);
  96.         out.writeHeader(getEncryptor(), 134);
  97.         out.writeByte(skillID);
  98.         out.writeInt(exp, StreamBuffer.ByteOrder.MIDDLE);
  99.         out.writeByte(level);
  100.         send(out.getBuffer());
  101.     }
  102.  
  103.     /**
  104.      * Sends all equipment.
  105.      */
  106.     public void sendEquipment() {
  107.         for (int i = 0; i < player.getEquipment().length; i++) {
  108.             sendEquipment(i, player.getEquipment()[i], player.getEquipmentN()[i]);
  109.         }
  110.     }
  111.  
  112.     /**
  113.      * Sends the equipment to the client.
  114.      *
  115.      * @param slot
  116.      *            the equipment slot
  117.      * @param itemID
  118.      *            the item ID
  119.      * @param itemAmount
  120.      *            the item amount
  121.      */
  122.     public void sendEquipment(int slot, int itemID, int itemAmount) {
  123.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(32);
  124.         out.writeVariableShortPacketHeader(getEncryptor(), 34);
  125.         out.writeShort(1688);
  126.         out.writeByte(slot);
  127.         out.writeShort(itemID + 1);
  128.         if (itemAmount > 254) {
  129.             out.writeByte(255);
  130.             out.writeShort(itemAmount);
  131.         } else {
  132.             out.writeByte(itemAmount);
  133.         }
  134.         out.finishVariableShortPacketHeader();
  135.         send(out.getBuffer());
  136.     }
  137.  
  138.     /**
  139.      * Sends the current full inventory.
  140.      */
  141.     public void sendInventory() {
  142.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(256);
  143.         out.writeVariableShortPacketHeader(getEncryptor(), 53);
  144.         out.writeShort(3214);
  145.         out.writeShort(player.getInventory().length);
  146.         for (int i = 0; i < player.getInventory().length; i++) {
  147.             if (player.getInventoryN()[i] > 254) {
  148.                 out.writeByte(255);
  149.                 out.writeInt(player.getInventoryN()[i], StreamBuffer.ByteOrder.INVERSE_MIDDLE);
  150.             } else {
  151.                 out.writeByte(player.getInventoryN()[i]);
  152.             }
  153.             out.writeShort(player.getInventory()[i] + 1, StreamBuffer.ValueType.A, StreamBuffer.ByteOrder.LITTLE);
  154.         }
  155.         out.finishVariableShortPacketHeader();
  156.         send(out.getBuffer());
  157.     }
  158.  
  159.     /**
  160.      * Sends a message to the players chat box.
  161.      *
  162.      * @param message
  163.      *            the message
  164.      */
  165.     public void sendMessage(String message) {
  166.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(message.length() + 3);
  167.         out.writeVariablePacketHeader(getEncryptor(), 253);
  168.         out.writeString(message);
  169.         out.finishVariablePacketHeader();
  170.         send(out.getBuffer());
  171.     }
  172.  
  173.     /**
  174.      * Sends a sidebar interface.
  175.      *
  176.      * @param menuId
  177.      *            the interface slot
  178.      * @param form
  179.      *            the interface ID
  180.      */
  181.     public void sendSidebarInterface(int menuId, int form) {
  182.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(4);
  183.         out.writeHeader(getEncryptor(), 71);
  184.         out.writeShort(form);
  185.         out.writeByte(menuId, StreamBuffer.ValueType.A);
  186.         send(out.getBuffer());
  187.     }
  188.  
  189.     /**
  190.      * Refreshes the map region.
  191.      */
  192.     public void sendMapRegion() {
  193.         player.getCurrentRegion().setAs(player.getPosition());
  194.         player.setNeedsPlacement(true);
  195.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(5);
  196.         out.writeHeader(getEncryptor(), 73);
  197.         out.writeShort(player.getPosition().getRegionX() + 6, StreamBuffer.ValueType.A);
  198.         out.writeShort(player.getPosition().getRegionY() + 6);
  199.         send(out.getBuffer());
  200.     }
  201.  
  202.     /**
  203.      * Disconnects the client.
  204.      */
  205.     public void disconnect() {
  206.         System.out.println(this + " disconnecting.");
  207.         try {
  208.             logout();
  209.             getSocketChannel().close();
  210.         } catch (Exception ex) {
  211.             ex.printStackTrace();
  212.         } finally {
  213.             HostGateway.exit(getSocketChannel().socket().getInetAddress().getHostAddress());
  214.             Server.getSingleton().getClientMap().remove(key);
  215.             key.cancel();
  216.         }
  217.     }
  218.  
  219.     /**
  220.      * Handles a clicked button.
  221.      *
  222.      * @param buttonId
  223.      *            the button ID
  224.      */
  225.     private void handleButton(int buttonId) {
  226.         switch (buttonId) {
  227.         case 9154:
  228.             sendLogout();
  229.             break;
  230.         case 153:
  231.             player.getMovementHandler().setRunToggled(true);
  232.             break;
  233.         case 152:
  234.             player.getMovementHandler().setRunToggled(false);
  235.             break;
  236.         default:
  237.             System.out.println("Unhandled button: " + buttonId);
  238.             break;
  239.         }
  240.     }
  241.  
  242.     /**
  243.      * Sends a packet that tells the client to log out.
  244.      */
  245.     public void sendLogout() {
  246.         StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(1);
  247.         out.writeHeader(getEncryptor(), 109);
  248.         send(out.getBuffer());
  249.     }
  250.  
  251.     /**
  252.      * Handles the current packet.
  253.      */
  254.     private void handlePacket() {
  255.         timeoutStopwatch.reset();
  256.         int positionBefore = inData.position();
  257.         StreamBuffer.InBuffer in = StreamBuffer.newInBuffer(inData);
  258.  
  259.         // Handle the packet.
  260.         try {
  261.             switch (packetOpcode) {
  262.             case 145: // Remove item.
  263.                 int interfaceID = in.readShort(StreamBuffer.ValueType.A);
  264.                 int slot = in.readShort(StreamBuffer.ValueType.A);
  265.                 in.readShort(StreamBuffer.ValueType.A); // Item ID.
  266.                 if (interfaceID == 1688) {
  267.                     player.unequip(slot);
  268.                 }
  269.                 break;
  270.             case 41: // Equip item.
  271.                 in.readShort(); // Item ID.
  272.                 slot = in.readShort(StreamBuffer.ValueType.A);
  273.                 in.readShort(); // Interface ID.
  274.                 player.equip(slot);
  275.                 break;
  276.             case 185: // Button clicking.
  277.                 handleButton(Misc.hexToInt(in.readBytes(2)));
  278.                 break;
  279.             case 4: // Player chat.
  280.                 int effects = in.readByte(false, StreamBuffer.ValueType.S);
  281.                 int color = in.readByte(false, StreamBuffer.ValueType.S);
  282.                 int chatLength = (packetLength - 2);
  283.                 byte[] text = in.readBytesReverse(chatLength, StreamBuffer.ValueType.A);
  284.                 player.setChatEffects(effects);
  285.                 player.setChatColor(color);
  286.                 player.setChatText(text);
  287.                 player.setChatUpdateRequired(true);
  288.                 break;
  289.             case 103: // Player command.
  290.                 String command = in.readString();
  291.                 String[] split = command.split(" ");
  292.                 player.handleCommand(split[0].toLowerCase(), Arrays.copyOfRange(split, 1, split.length));
  293.                 break;
  294.             case 248: // Movement.
  295.             case 164: // ^
  296.             case 98: // ^
  297.                 int length = packetLength;
  298.                 if (packetOpcode == 248) {
  299.                     length -= 14;
  300.                 }
  301.                 int steps = (length - 5) / 2;
  302.                 int[][] path = new int[steps][2];
  303.                 int firstStepX = in.readShort(StreamBuffer.ValueType.A, StreamBuffer.ByteOrder.LITTLE);
  304.                 for (int i = 0; i < steps; i++) {
  305.                     path[i][0] = in.readByte();
  306.                     path[i][1] = in.readByte();
  307.                 }
  308.                 int firstStepY = in.readShort(StreamBuffer.ByteOrder.LITTLE);
  309.  
  310.                 player.getMovementHandler().reset();
  311.                 player.getMovementHandler().setRunPath(in.readByte(StreamBuffer.ValueType.C) == 1);
  312.                 player.getMovementHandler().addToPath(new Position(firstStepX, firstStepY));
  313.                 for (int i = 0; i < steps; i++) {
  314.                     path[i][0] += firstStepX;
  315.                     path[i][1] += firstStepY;
  316.                     player.getMovementHandler().addToPath(new Position(path[i][0], path[i][1]));
  317.                 }
  318.                 player.getMovementHandler().finish();
  319.                 break;
  320.             default:
  321.                 break;
  322.             }
  323.         } catch (Exception ex) {
  324.             ex.printStackTrace();
  325.         } finally {
  326.             // Make sure we have finished reading all of this packet.
  327.             int read = inData.position() - positionBefore;
  328.             for (int i = read; i < packetLength; i++) {
  329.                 inData.get();
  330.             }
  331.         }
  332.     }
  333.  
  334.     /**
  335.      * Handles a received packet.
  336.      */
  337.     public final void handleIncomingData() {
  338.         try {
  339.             // Read the incoming data.
  340.             if (getSocketChannel().read(inData) == -1) {
  341.                 disconnect();
  342.                 return;
  343.             }
  344.  
  345.             // Handle the received data.
  346.             inData.flip();
  347.             while (inData.hasRemaining()) {
  348.  
  349.                 // Handle login if we need to.
  350.                 if (getStage() != Stage.LOGGED_IN) {
  351.                     handleLogin();
  352.                     break;
  353.                 }
  354.  
  355.                 // Decode the packet opcode.
  356.                 if (packetOpcode == -1) {
  357.                     packetOpcode = inData.get() & 0xff;
  358.                     packetOpcode = packetOpcode - getDecryptor().getNextValue() & 0xff;
  359.                 }
  360.  
  361.                 // Decode the packet length.
  362.                 if (packetLength == -1) {
  363.                     packetLength = Misc.packetLengths[packetOpcode];
  364.                     if (packetLength == -1) {
  365.                         if (!inData.hasRemaining()) {
  366.                             inData.flip();
  367.                             inData.compact();
  368.                             break;
  369.                         }
  370.                         packetLength = inData.get() & 0xff;
  371.                     }
  372.                 }
  373.  
  374.                 // Decode the packet payload.
  375.                 if (inData.remaining() >= packetLength) {
  376.                     handlePacket();
  377.  
  378.                     // Reset for the next packet.
  379.                     packetOpcode = -1;
  380.                     packetLength = -1;
  381.                 } else {
  382.                     inData.flip();
  383.                     inData.compact();
  384.                     break;
  385.                 }
  386.             }
  387.  
  388.             // Clear everything for the next read.
  389.             inData.clear();
  390.         } catch (Exception ex) {
  391.             ex.printStackTrace();
  392.             disconnect();
  393.         }
  394.     }
  395.  
  396.     /**
  397.      * Sends the buffer to the socket.
  398.      *
  399.      * @param buffer
  400.      *            the buffer
  401.      * @throws IOException
  402.      */
  403.     public void send(ByteBuffer buffer) {
  404.         // Prepare the buffer for writing.
  405.         buffer.flip();
  406.  
  407.         try {
  408.             // ...and write it!
  409.             getSocketChannel().write(buffer);
  410.         } catch (IOException ex) {
  411.             ex.printStackTrace();
  412.             disconnect();
  413.         }
  414.     }
  415.  
  416.     /**
  417.      * Handles the login process of the client.
  418.      */
  419.     private void handleLogin() throws Exception {
  420.         switch (getStage()) {
  421.         case CONNECTED:
  422.             if (inData.remaining() < 2) {
  423.                 inData.compact();
  424.                 return;
  425.             }
  426.  
  427.             // Validate the request.
  428.             int request = inData.get() & 0xff;
  429.             inData.get(); // Name hash.
  430.             if (request != 14) {
  431.                 System.err.println("Invalid login request: " + request);
  432.                 disconnect();
  433.                 return;
  434.             }
  435.  
  436.             // Write the response.
  437.             StreamBuffer.OutBuffer out = StreamBuffer.newOutBuffer(17);
  438.             out.writeLong(0); // First 8 bytes are ignored by the client.
  439.             out.writeByte(0); // The response opcode, 0 for logging in.
  440.             out.writeLong(new SecureRandom().nextLong()); // SSK.
  441.             send(out.getBuffer());
  442.  
  443.             setStage(Stage.LOGGING_IN);
  444.             break;
  445.         case LOGGING_IN:
  446.             if (inData.remaining() < 2) {
  447.                 inData.compact();
  448.                 return;
  449.             }
  450.  
  451.             // Validate the login type.
  452.             int loginType = inData.get();
  453.             if (loginType != 16 && loginType != 18) {
  454.                 System.err.println("Invalid login type: " + loginType);
  455.                 disconnect();
  456.                 return;
  457.             }
  458.  
  459.             // Ensure that we can read all of the login block.
  460.             int blockLength = inData.get() & 0xff;
  461.             if (inData.remaining() < blockLength) {
  462.                 inData.flip();
  463.                 inData.compact();
  464.                 return;
  465.             }
  466.  
  467.             // Read the login block.
  468.             StreamBuffer.InBuffer in = StreamBuffer.newInBuffer(inData);
  469.             in.readByte(); // Skip the magic ID value 255.
  470.  
  471.             // Validate the client version.
  472.             int clientVersion = in.readShort();
  473.             if (clientVersion != 317) {
  474.                 System.err.println("Invalid client version: " + clientVersion);
  475.                 disconnect();
  476.                 return;
  477.             }
  478.  
  479.             in.readByte(); // Skip the high/low memory version.
  480.  
  481.             // Skip the CRC keys.
  482.             for (int i = 0; i < 9; i++) {
  483.                 in.readInt();
  484.             }
  485.  
  486.             in.readByte(); // Skip RSA block length.
  487.             // If we wanted to, we would decode RSA at this point.
  488.  
  489.             // Validate that the RSA block was decoded properly.
  490.             int rsaOpcode = in.readByte();
  491.             if (rsaOpcode != 10) {
  492.                 System.err.println("Unable to decode RSA block properly!");
  493.                 disconnect();
  494.                 return;
  495.             }
  496.  
  497.             // Set up the ISAAC ciphers.
  498.             long clientHalf = in.readLong();
  499.             long serverHalf = in.readLong();
  500.             int[] isaacSeed = { (int) (clientHalf >> 32), (int) clientHalf, (int) (serverHalf >> 32), (int) serverHalf };
  501.             setDecryptor(new ISAACCipher(isaacSeed));
  502.             for (int i = 0; i < isaacSeed.length; i++) {
  503.                 isaacSeed[i] += 50;
  504.             }
  505.             setEncryptor(new ISAACCipher(isaacSeed));
  506.  
  507.             // Read the user authentication.
  508.             in.readInt(); // Skip the user ID.
  509.             String username = in.readString();
  510.             String password = in.readString();
  511.             setUsername(username);
  512.             setPassword(password);
  513.  
  514.             login();
  515.             setStage(Stage.LOGGED_IN);
  516.             break;
  517.         }
  518.     }
  519.  
  520.     /**
  521.      * Gets the remote host of the client.
  522.      *
  523.      * @return the host
  524.      */
  525.     public String getHost() {
  526.         return getSocketChannel().socket().getInetAddress().getHostAddress();
  527.     }
  528.  
  529.     /**
  530.      * Sets the username.
  531.      *
  532.      * @param username
  533.      *            the username
  534.      */
  535.     public void setUsername(String username) {
  536.         this.username = username;
  537.     }
  538.  
  539.     /**
  540.      * Gets the username.
  541.      *
  542.      * @return the username
  543.      */
  544.     public String getUsername() {
  545.         return username;
  546.     }
  547.  
  548.     /**
  549.      * Sets the password.
  550.      *
  551.      * @param password
  552.      *            the password
  553.      */
  554.     public void setPassword(String password) {
  555.         this.password = password;
  556.     }
  557.  
  558.     /**
  559.      * Gets the password.
  560.      *
  561.      * @return the password
  562.      */
  563.     public String getPassword() {
  564.         return password;
  565.     }
  566.  
  567.     /**
  568.      * Sets the encryptor.
  569.      *
  570.      * @param encryptor
  571.      *            the encryptor
  572.      */
  573.     public void setEncryptor(ISAACCipher encryptor) {
  574.         this.encryptor = encryptor;
  575.     }
  576.  
  577.     /**
  578.      * Gets the encryptor.
  579.      *
  580.      * @return the encryptor
  581.      */
  582.     public ISAACCipher getEncryptor() {
  583.         return encryptor;
  584.     }
  585.  
  586.     /**
  587.      * Sets the decryptor.
  588.      *
  589.      * @param decryptor
  590.      *            the decryptor.
  591.      */
  592.     public void setDecryptor(ISAACCipher decryptor) {
  593.         this.decryptor = decryptor;
  594.     }
  595.  
  596.     /**
  597.      * Gets the decryptor.
  598.      *
  599.      * @return the decryptor
  600.      */
  601.     public ISAACCipher getDecryptor() {
  602.         return decryptor;
  603.     }
  604.  
  605.     /**
  606.      * Gets the Player subclass implementation of this superclass.
  607.      *
  608.      * @return the player
  609.      */
  610.     public Player getPlayer() {
  611.         return player;
  612.     }
  613.  
  614.     /**
  615.      * Gets the SocketChannel.
  616.      *
  617.      * @return the SocketChannel
  618.      */
  619.     public SocketChannel getSocketChannel() {
  620.         return socketChannel;
  621.     }
  622.  
  623.     public void setStage(Stage stage) {
  624.         this.stage = stage;
  625.     }
  626.  
  627.     public Stage getStage() {
  628.         return stage;
  629.     }
  630.  
  631.     public Misc.Stopwatch getTimeoutStopwatch() {
  632.         return timeoutStopwatch;
  633.     }
  634.  
  635.     /**
  636.      * The current connection stage of the client.
  637.      *
  638.      * @author blakeman8192
  639.      */
  640.     protected enum Stage {
  641.         CONNECTED, LOGGING_IN, LOGGED_IN, LOGGED_OUT
  642.     }
  643.  
  644. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement