Package simpleserver.bot

Source Code of simpleserver.bot.Bot$Tunneler

/*
* Copyright (c) 2010 SimpleServer authors (see CONTRIBUTORS)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package simpleserver.bot;

import static simpleserver.util.Util.print;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.locks.ReentrantLock;

import simpleserver.Coordinate.Dimension;
import simpleserver.Main;
import simpleserver.Position;
import simpleserver.Server;
import simpleserver.stream.Encryption.ServerEncryption;

public class Bot {
  protected String name;
  protected Server server;
  private boolean connected;
  private boolean expectDisconnect;
  protected boolean ready;
  protected boolean dead;
  protected int playerEntityId;

  private Socket socket;
  protected DataInputStream in;
  protected DataOutputStream out;

  ReentrantLock writeLock;
  protected Position position;
  protected BotController controller;
  protected boolean gotFirstPacket = false;
  private byte lastPacket;
  private float health;

  private ServerEncryption encryption = new ServerEncryption();

  public Bot(Server server, String name) {
    this.name = name;
    this.server = server;
    position = new Position();
  }

  void connect() throws UnknownHostException, IOException {

    try {
      InetAddress localAddress = InetAddress.getByName(Server.addressFactory.getNextAddress());
      socket = new Socket(InetAddress.getByName(null), server.options.getInt("internalPort"), localAddress, 0);
    } catch (Exception e) {
      socket = new Socket(InetAddress.getByName(null), server.options.getInt("internalPort"));
    }
    in = new DataInputStream(socket.getInputStream());
    out = new DataOutputStream(socket.getOutputStream());

    writeLock = new ReentrantLock();

    connected = true;
    new Tunneler().start();

    handshake();
  }

  boolean ninja() {
    return false;
  }

  protected void positionUpdate() throws IOException {
  }

  private void keepAlive(int keepAliveId) throws IOException {
    writeLock.lock();
    out.writeByte(0x0);
    out.writeInt(keepAliveId);
    writeLock.unlock();
  }

  private void handshake() throws IOException {
    writeLock.lock();
    out.writeByte(2);
    out.writeByte(Main.protocolVersion);
    write(name);
    write("localhost");
    out.writeInt(server.options.getInt("internalPort"));
    out.flush();
    writeLock.unlock();
  }

  public void logout() throws IOException {
    die();
    expectDisconnect = true;
    out.writeByte(0xff);
    write("quitting");
    out.flush();
  }

  protected void login() throws IOException {
    writeLock.lock();
    out.writeByte(0xcd);
    out.writeByte(0);
    writeLock.unlock();
  }

  private void sendSharedKey() throws IOException {
    writeLock.lock();
    out.writeByte(0xfc);
    byte[] key = encryption.getEncryptedSharedKey();
    out.writeShort(key.length);
    out.write(key);
    byte[] challengeTokenResponse = encryption.encryptChallengeToken();
    out.writeShort(challengeTokenResponse.length);
    out.write(challengeTokenResponse);
    out.flush();
    writeLock.unlock();
  }

  private void respawn() throws IOException {
    writeLock.lock();
    out.writeByte(0xcd);
    out.writeByte(1);
    writeLock.unlock();
  }

  protected void ready() throws IOException {
    ready = true;
  }

  protected void walk(double d) {
    double heading = position.yaw * Math.PI / 180;
    position.x -= Math.sin(heading) * d;
    position.z += Math.cos(heading) * d;
  }

  protected void ascend(double d) {
    position.y += d;
    position.stance += d;

    if (position.stance - position.y > 1.6 || position.stance - position.y < 0.15) {
      position.stance = position.y + 0.5;
    }
  }

  protected void sendPosition() throws IOException {
    writeLock.lock();
    position.send(out);
    writeLock.unlock();
  }

  protected boolean trashdat() {
    return true;
  }

  protected void handlePacket(byte packetId) throws IOException {
    // System.out.println("Packet: 0x" + Integer.toHexString(packetId));
    switch (packetId) {
      case 0x01: // Login Request
        int eid = in.readInt();
        if (playerEntityId == 0) {
          playerEntityId = eid;
        }

        readUTF16();
        in.readByte();
        position.dimension = Dimension.get(in.readByte());
        in.readByte();
        in.readByte();
        in.readByte();
        break;
      case 0x0d: // Player Position & Look
        double x = in.readDouble();
        double stance = in.readDouble();
        double y = in.readDouble();
        double z = in.readDouble();
        float yaw = in.readFloat();
        float pitch = in.readFloat();
        boolean onGround = in.readBoolean();
        position.updatePosition(x, y, z, stance);
        position.updateLook(yaw, pitch);
        position.updateGround(onGround);
        if (!ready) {
          sendPosition();
          ready();
        } else if (dead) {
          sendPosition();
          dead = false;
        }
        positionUpdate();
        break;
      case 0x0b: // Player Position
        double x2 = in.readDouble();
        double stance2 = in.readDouble();
        double y2 = in.readDouble();
        double z2 = in.readDouble();
        boolean onGround2 = in.readBoolean();
        position.updatePosition(x2, y2, z2, stance2);
        position.updateGround(onGround2);
        positionUpdate();
        break;
      case (byte) 0xff: // Disconnect/Kick
        String reason = readUTF16();
        error(reason);
        break;
      case 0x00: // Keep Alive
        keepAlive(in.readInt());
        break;
      case 0x03: // Chat Message
        readUTF16();
        break;
      case 0x04: // Time Update
        in.readLong();
        in.readLong();
        break;
      case 0x05: // Entity Equipment
        in.readInt();
        in.readShort();
        readItem();
        break;
      case 0x06: // Spawn Position
        readNBytes(12);
        break;
      case 0x07: // Use Entity
        in.readInt();
        in.readInt();
        in.readBoolean();
        break;
      case 0x08: // Update Health
        health = in.readFloat();
        in.readShort();
        in.readFloat();
        if (health <= 0) {
          dead = true;
          respawn();
        }
        break;
      case 0x09: // Respawn
        position.dimension = Dimension.get((byte) in.readInt());
        in.readByte();
        in.readByte();
        in.readShort();
        readUTF16();
        break;
      case 0x0a: // Player
        in.readBoolean();
        break;
      case 0x0c: // Player Look
        readNBytes(9);
        break;
      case 0x0e: // Player Digging
        in.readByte();
        in.readInt();
        in.readByte();
        in.readInt();
        in.readByte();
        break;
      case 0x0f: // Player Block Placement
        in.readInt();
        in.readByte();
        in.readInt();
        in.readByte();
        readItem();
        in.readByte();
        in.readByte();
        in.readByte();
        break;
      case 0x10: // Holding Change
        in.readShort();
        break;
      case 0x11: // Use Bed
        readNBytes(14);
        break;
      case 0x12: // Animation
        readNBytes(5);
        break;
      case 0x13: // Entity Action
        in.readInt();
        in.readByte();
        in.readInt();
        break;
      case 0x14: // Named Entity Spawn
        in.readInt();
        readUTF16();
        readNBytes(16);
        readUnknownBlob();
        break;
      case 0x16: // Collect Item
        readNBytes(8);
        break;
      case 0x17: // Add Object/Vehicle
        in.readInt();
        in.readByte();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readByte();
        in.readByte();
        int flag = in.readInt();
        if (flag > 0) {
          in.readShort();
          in.readShort();
          in.readShort();
        }
        break;
      case 0x18: // Mob Spawn
        in.readInt();
        in.readByte();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readByte();
        in.readByte();
        in.readByte();
        in.readShort();
        in.readShort();
        in.readShort();
        readUnknownBlob();
        break;
      case 0x19: // Entity: Painting
        in.readInt();
        readUTF16();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readInt();
        break;
      case 0x1a: // Experience Orb
        in.readInt();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readShort();
        break;
      case 0x1b: // Steer Vehicle
        in.readFloat();
        in.readFloat();
        in.readBoolean();
        in.readBoolean();
        break;
      case 0x1c: // Entity Velocity
        readNBytes(10);
        break;
      case 0x1d: // Destroy Entity
        byte destroyCount = in.readByte();
        if (destroyCount > 0) {
          readNBytes(destroyCount * 4);
        }
        break;
      case 0x1e: // Entity
        readNBytes(4);
        break;
      case 0x1f: // Entity Relative Move
        readNBytes(7);
        break;
      case 0x20: // Entity Look
        readNBytes(6);
        break;
      case 0x21: // Entity Look and Relative Move
        readNBytes(9);
        break;
      case 0x22: // Entity Teleport
        readNBytes(18);
        break;
      case 0x23: // ???, added in 12w03a
        in.readInt();
        in.readByte();
        break;
      case 0x26: // Entity Status
        readNBytes(5);
        break;
      case 0x27: // Attach Entity
        in.readInt();
        in.readInt();
        in.readBoolean();
        break;
      case 0x28: // Entity Metadata
        in.readInt();
        readUnknownBlob();
        break;
      case 0x29: // Entity Effect
        in.readInt();
        in.readByte();
        in.readByte();
        in.readShort();
        break;
      case 0x2a: // Remove Entity Effect
        in.readInt();
        in.readByte();
        break;
      case 0x2b: // Experience
        in.readFloat();
        in.readShort();
        in.readShort();
        break;
      case 0x2c: // Entity Properties
        in.readInt();
        int properties_count = in.readInt();
        short list_length = 0;

        // loop for every property key/value pair
        for (int i = 0; i < properties_count; i++) {
          readUTF16();
          in.readDouble();
          list_length = in.readShort();

          // loop for list_length
          if (list_length > 0) {
            for (int k = 0; k < list_length; k++) {
              in.readLong();
              in.readLong();
              in.readDouble();
              in.readByte();
            }
          }
        }
        break;
      case 0x33: // Map Chunk
        readNBytes(13);
        readNBytes(in.readInt());
        break;
      case 0x34: // Multi Block Change
        in.readInt();
        in.readInt();
        in.readShort();
        readNBytes(in.readInt());
        break;
      case 0x35: // Block Change
        in.readInt();
        in.readByte();
        in.readInt();
        in.readShort();
        in.readByte();
        break;
      case 0x36: // Block Action
        readNBytes(13);
        break;
      case 0x37: // Mining progress
        in.readInt();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readByte();
        break;
      case 0x38: // Chunk Bulk
        readNBytes(in.readShort() * 12 + in.readInt());
        short chunkCount = in.readShort();
        int dataLength = in.readInt();
        in.readBoolean();
        readNBytes(chunkCount * 12 + dataLength);
        break;
      case 0x3c: // Explosion
        readNBytes(28);
        int recordCount = in.readInt();
        readNBytes(recordCount * 3);
        readNBytes(12);
        break;
      case 0x3d: // Sound/Particle Effect
        in.readInt();
        in.readInt();
        in.readByte();
        in.readInt();
        in.readInt();
        in.readBoolean();
        break;
      case 0x3e: // Named Sound Effect
        readUTF16();
        in.readInt();
        in.readInt();
        in.readInt();
        in.readFloat();
        in.readByte();
        break;
      case 0x46: // New/Invalid State
        readNBytes(2);
        break;
      case 0x47: // Thunderbolt
        readNBytes(17);
        break;
      case 0x64: // Open Window
        in.readByte();
        byte invtype = in.readByte();
        readUTF16();
        in.readByte();
        in.readBoolean();
        if (invtype == 11) {
          in.readInt();
        }
        break;
      case 0x65: // Close Window
        in.readByte();
        break;
      case 0x66: // Window Click
        in.readByte();
        in.readShort();
        in.readByte();
        in.readShort();
        in.readByte();
        readItem();
        break;
      case 0x67: // Set Slot
        in.readByte();
        in.readShort();
        readItem();
        break;
      case 0x68: // Window Items
        in.readByte();
        short count = in.readShort();
        for (int c = 0; c < count; ++c) {
          readItem();
        }
        break;
      case 0x69: // Update Window Property
        in.readByte();
        in.readShort();
        in.readShort();
        break;
      case 0x6a: // Transaction
        in.readByte();
        in.readShort();
        in.readBoolean();
        break;
      case 0x6b: // Creative Inventory Action
        in.readShort();
        readItem();
        break;
      case (byte) 0x6c: // Enchant Item
        readNBytes(2);
        break;
      case (byte) 0x82: // Update Sign
        in.readInt();
        in.readShort();
        in.readInt();
        readUTF16();
        readUTF16();
        readUTF16();
        readUTF16();
        break;
      case (byte) 0x83: // Item Data
        in.readShort();
        in.readShort();
        short length = in.readShort();
        readNBytes(length);
        break;
      case (byte) 0x84: // added in 12w06a
        in.readInt();
        in.readShort();
        in.readInt();
        in.readByte();
        short nbtLenght = in.readShort();
        if (nbtLenght > 0) {
          readNBytes(nbtLenght);
        }
        break;
      case (byte) 0x85: // Sign Placement
        in.readByte();
        in.readInt();
        in.readInt();
        in.readInt();
        break;
      case (byte) 0xc8: // Increment Statistic
        in.readInt();
        in.readInt();
        break;
      case (byte) 0xc9: // Player List Item
        readUTF16();
        in.readBoolean();
        in.readShort();
        break;
      case (byte) 0xca: // Player Abilities
        in.readByte();
        in.readFloat();
        in.readFloat();
        break;
      case (byte) 0xcb: // Tab-Completion
        readUTF16();
        break;
      case (byte) 0xcc: // Locale and View Distance
        readUTF16();
        in.readByte();
        in.readByte();
        in.readByte();
        in.readBoolean();
        break;
      case (byte) 0xcd: // Login & Respawn
        in.readByte();
        break;
      case (byte) 0xce: // create scoreboard
        readUTF16();
        readUTF16();
        in.readByte();
        break;
      case (byte) 0xcf: // update score
        readUTF16();
        byte updateRemove = in.readByte();
        if (updateRemove == 0) {
          readUTF16();
          in.readInt();
        }
        break;
      case (byte) 0xd0: // display scoreboard
        in.readByte();
        readUTF16();
        break;
      case (byte) 0xd1: // teams
        readUTF16();
        byte mode = in.readByte();
        short playerCount = -1;

        if (mode == 2 || mode == 0) {
          readUTF16(); // team display name
          readUTF16(); // team prefix
          readUTF16(); // team suffix
          in.readByte(); // friendly fire
        }

        // only ran if 0,3,4
        if (mode == 0 || mode == 3 || mode == 4) {
          playerCount = in.readShort();

          if (playerCount != -1) {
            for (int i = 0; i < playerCount; i++) {
              readUTF16();
            }
          }
        }
        break;
      case (byte) 0xe6: // ModLoaderMP by SDK
        in.readInt(); // mod
        in.readInt(); // packet id
        readNBytes(in.readInt() * 4); // ints
        readNBytes(in.readInt() * 4); // floats
        int sizeString = in.readInt(); // strings
        for (int i = 0; i < sizeString; i++) {
          readNBytes(in.readInt());
        }
        break;
      case (byte) 0xfa: // Plugin Message
        readUTF16();
        short arrayLength = in.readShort();
        readNBytes(0xff & arrayLength);
        break;
      case (byte) 0xfc: // Encryption Key Response
        byte[] sharedKey = new byte[in.readShort()];
        in.readFully(sharedKey);
        byte[] challengeTokenResponse = new byte[in.readShort()];
        in.readFully(challengeTokenResponse);
        in = new DataInputStream(new BufferedInputStream(encryption.encryptedInputStream(socket.getInputStream())));
        out = new DataOutputStream(new BufferedOutputStream(encryption.encryptedOutputStream(socket.getOutputStream())));
        login();
        break;
      case (byte) 0xfd: // Encryption Key Request (server -> client)
        readUTF16();
        byte[] keyBytes = new byte[in.readShort()];
        in.readFully(keyBytes);
        byte[] challengeToken = new byte[in.readShort()];
        in.readFully(challengeToken);
        encryption.setPublicKey(keyBytes);
        encryption.setChallengeToken(challengeToken);
        sendSharedKey();
        break;
      case (byte) 0xfe: // Server List Ping
        break;
      default:
        error("Unable to handle packet 0x" + Integer.toHexString(packetId)
            + " after 0x" + Integer.toHexString(lastPacket));
    }
    lastPacket = packetId;
  }

  private void readItem() throws IOException {
    if (in.readShort() > 0) {
      in.readByte();
      in.readShort();
      short length;
      if ((length = in.readShort()) > 0) {
        readNBytes(length);
      }
    }
  }

  private void readUnknownBlob() throws IOException {
    byte unknown = in.readByte();

    while (unknown != 0x7f) {
      int type = (unknown & 0xE0) >> 5;

      switch (type) {
        case 0:
          in.readByte();
          break;
        case 1:
          in.readShort();
          break;
        case 2:
          in.readInt();
          break;
        case 3:
          in.readFloat();
          break;
        case 4:
          readUTF16();
          break;
        case 5:
          readItem();
          break;
        case 6:
          in.readInt();
          in.readInt();
          in.readInt();
      }
      unknown = in.readByte();
    }
  }

  protected String write(String s) throws IOException {
    byte[] bytes = s.getBytes("UTF-16");
    if (s.length() == 0) {
      out.write((byte) 0x00);
      out.write((byte) 0x00);
      return s;
    }
    bytes[0] = (byte) ((s.length() >> 8) & 0xFF);
    bytes[1] = (byte) ((s.length() & 0xFF));
    for (byte b : bytes) {
      out.write(b);
    }
    return s;
  }

  protected String readUTF16() throws IOException {
    short length = in.readShort();
    byte[] bytes = new byte[length * 2 + 2];
    for (short i = 0; i < length * 2; i++) {
      bytes[i + 2] = in.readByte();
    }
    bytes[0] = (byte) 0xfffffffe;
    bytes[1] = (byte) 0xffffffff;
    return new String(bytes, "UTF-16");
  }

  private void readNBytes(int bytes) throws IOException {
    for (int c = 0; c < bytes; ++c) {
      in.readByte();
    }
  }

  protected void die() {
    connected = false;
    if (controller != null) {
      controller.remove(this);
    }
    if (trashdat()) {
      File dat = server.getPlayerFile(name);
      if (controller != null) {
        controller.trash(dat);
      } else {
        dat.delete();
      }
    }
  }

  protected void error(String reason) {
    die();
    if (!expectDisconnect) {
      print("Bot " + name + " died (" + reason + ")\n");
    }
  }

  public void setController(BotController controller) {
    this.controller = controller;
  }

  private final class Tunneler extends Thread {
    @Override
    public void run() {
      while (connected) {
        try {
          handlePacket(in.readByte());
          out.flush();
          if (!gotFirstPacket) {
            gotFirstPacket = true;
          }
        } catch (IOException e) {
          if (!gotFirstPacket) {
            try {
              connect();
            } catch (Exception e2) {
              error("Socket closed on reconnect");
            }
            break;
          } else {
            error("Socket closed");
          }
        }
      }
    }
  }
}
TOP

Related Classes of simpleserver.bot.Bot$Tunneler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.