Пример #1
0
  /**
   * Disconnects the session with the specified reason. This causes a KickMessage to be sent. When
   * it has been delivered, the channel is closed.
   *
   * @param reason The reason for disconnection.
   * @param overrideKick Whether to skip the kick event.
   */
  public void disconnect(String reason, boolean overrideKick) {
    if (player != null && !overrideKick) {
      PlayerKickEvent event = EventFactory.onPlayerKick(player, reason);
      if (event.isCancelled()) {
        return;
      }

      reason = event.getReason();

      if (player.isOnline() && event.getLeaveMessage() != null) {
        server.broadcastMessage(event.getLeaveMessage());
      }
    }

    // log that the player was kicked
    if (player != null) {
      GlowServer.logger.info(player.getName() + " kicked: " + reason);
    } else {
      GlowServer.logger.info("[" + address + "] kicked: " + reason);
    }

    if (quitReason == null) {
      quitReason = "kicked";
    }

    // perform the kick, sending a kick message if possible
    if (isActive()
        && (getProtocol() instanceof LoginProtocol || getProtocol() instanceof PlayProtocol)) {
      // channel is both currently connected and in a protocol state allowing kicks
      sendWithFuture(new KickMessage(reason)).addListener(ChannelFutureListener.CLOSE);
    } else {
      getChannel().close();
    }
  }
Пример #2
0
  @Override
  public void handle(Session session, GlowPlayer player, KickMessage message) {

    String text = EventFactory.onPlayerQuit(player).getQuitMessage();
    if (message != null) {
      session.getServer().broadcastMessage(text);
    }

    session.disconnect("Goodbye!", true);
  }
Пример #3
0
 private void putVine(GlowBlock block, Vine vine, GlowBlock fromBlock) {
   GlowBlockState state = block.getState();
   state.setType(Material.VINE);
   state.setData(vine);
   if (fromBlock != null) {
     BlockSpreadEvent spreadEvent = new BlockSpreadEvent(block, fromBlock, state);
     EventFactory.callEvent(spreadEvent);
     if (!spreadEvent.isCancelled()) {
       state.update(true);
     }
   } else {
     state.update(true);
   }
 }
Пример #4
0
  /** Pulse this session, performing any updates needed. */
  void pulse() {
    // drop the previous placement if needed
    if (previousPlacementTicks > 0 && --previousPlacementTicks == 0) {
      previousPlacement = null;
    }

    // process messages
    Message message;
    while ((message = messageQueue.poll()) != null) {
      if (disconnected) {
        // disconnected, we are just seeing extra messages now
        continue;
      }

      super.messageReceived(message);
    }

    // check if the client is disconnected
    if (disconnected) {
      connectionManager.sessionInactivated(this);

      if (player == null) {
        return;
      }

      player.remove();

      Message userListMessage = UserListItemMessage.removeOne(player.getUniqueId());
      for (GlowPlayer player : server.getOnlinePlayers()) {
        if (player.canSee(this.player)) {
          player.getSession().send(userListMessage);
        } else {
          player.stopHidingDisconnectedPlayer(this.player);
        }
      }

      GlowServer.logger.info(player.getName() + " [" + address + "] lost connection");

      if (player.isSleeping()) {
        player.leaveBed(false);
      }

      final String text = EventFactory.onPlayerQuit(player).getQuitMessage();
      if (online && text != null && !text.isEmpty()) {
        server.broadcastMessage(text);
      }

      player = null; // in case we are disposed twice
    }
  }
Пример #5
0
 @Override
 public void updateBlock(GlowBlock block) {
   if (isNearWater(block) || GlowBiomeClimate.isRainy(block)) {
     block.setData((byte) 7); // set this block as fully wet
   } else if (block.getData() > 0) {
     block.setData((byte) (block.getData() - 1)); // if this block is wet, it becomes less wet
   } else if (!Arrays.asList(possibleCrops).contains(block.getRelative(BlockFace.UP).getType())) {
     // turns block back to dirt if nothing is planted on
     final GlowBlockState state = block.getState();
     state.setType(Material.DIRT);
     state.setRawData((byte) 0);
     BlockFadeEvent fadeEvent = new BlockFadeEvent(block, state);
     EventFactory.callEvent(fadeEvent);
     if (!fadeEvent.isCancelled()) {
       state.update(true);
     }
   }
 }
  @Override
  public void handle(GlowSession session, DiggingMessage message) {
    // Todo: Implement SHOOT_ARROW_FINISH_EATING
    // Todo: Implement SWAP_ITEM_IN_HAND
    GlowPlayer player = session.getPlayer();
    GlowWorld world = player.getWorld();
    GlowBlock block = world.getBlockAt(message.getX(), message.getY(), message.getZ());
    BlockFace face = BlockPlacementHandler.convertFace(message.getFace());
    ItemStack holding = player.getItemInHand();

    if (block.getRelative(face).getType() == Material.FIRE) {
      block.getRelative(face).breakNaturally();
      return; // returns to avoid breaking block in creative
    }

    boolean blockBroken = false;
    boolean revert = false;
    if (message.getState() == DiggingMessage.START_DIGGING || player.getDigging() == null) {
      // call interact event
      Action action = Action.LEFT_CLICK_BLOCK;
      Block eventBlock = block;
      if (player.getLocation().distanceSquared(block.getLocation()) > 36
          || block.getTypeId() == 0) {
        action = Action.LEFT_CLICK_AIR;
        eventBlock = null;
      }
      PlayerInteractEvent interactEvent =
          EventFactory.onPlayerInteract(player, action, eventBlock, face);

      // blocks don't get interacted with on left click, so ignore that
      // attempt to use item in hand, that is, dig up the block
      if (!BlockPlacementHandler.selectResult(interactEvent.useItemInHand(), true)) {
        // the event was cancelled, get out of here
        revert = true;
      } else if (player.getGameMode() != GameMode.SPECTATOR) {
        player.setDigging(null);
        // emit damage event - cancel by default if holding a sword
        boolean instaBreak =
            player.getGameMode() == GameMode.CREATIVE
                || block.getMaterialValues().getHardness() == 0;
        BlockDamageEvent damageEvent =
            new BlockDamageEvent(player, block, player.getItemInHand(), instaBreak);
        if (player.getGameMode() == GameMode.CREATIVE
            && holding != null
            && EnchantmentTarget.WEAPON.includes(holding.getType())) {
          damageEvent.setCancelled(true);
        }
        EventFactory.callEvent(damageEvent);

        // follow orders
        if (damageEvent.isCancelled()) {
          revert = true;
        } else {
          // in creative, break even if denied in the event, or the block
          // can never be broken (client does not send DONE_DIGGING).
          blockBroken = damageEvent.getInstaBreak();
          if (!blockBroken) {
            /// TODO: add a delay here based on hardness
            player.setDigging(block);
          }
        }
      }
    } else if (message.getState() == DiggingMessage.FINISH_DIGGING) {
      // shouldn't happen in creative mode

      // todo: verification against malicious clients
      blockBroken = block.equals(player.getDigging());

      if (blockBroken
          && holding.getType() != Material.AIR
          && holding.getDurability() != holding.getType().getMaxDurability()) {
        switch (block.getType()) {
          case GRASS:
          case DIRT:
          case SAND:
          case GRAVEL:
          case MYCEL:
          case SOUL_SAND:
            switch (holding.getType()) {
              case WOOD_SPADE:
              case STONE_SPADE:
              case IRON_SPADE:
              case GOLD_SPADE:
              case DIAMOND_SPADE:
                holding.setDurability((short) (holding.getDurability() + 1));
                break;
              default:
                holding.setDurability((short) (holding.getDurability() + 2));
                break;
            }
            break;
          case LOG:
          case LOG_2:
          case WOOD:
          case CHEST:
            switch (holding.getType()) {
              case WOOD_AXE:
              case STONE_AXE:
              case IRON_AXE:
              case GOLD_AXE:
              case DIAMOND_AXE:
                holding.setDurability((short) (holding.getDurability() + 1));
                break;
              default:
                holding.setDurability((short) (holding.getDurability() + 2));
                break;
            }
            break;
          case STONE:
          case COBBLESTONE:
            break;
          default:
            holding.setDurability((short) (holding.getDurability() + 2));
            break;
        }
        if (holding.getDurability() >= holding.getType().getMaxDurability()) {
          player.getInventory().remove(holding);
          // player.getItemInHand().setType(Material.AIR);
        }
      }
      player.setDigging(null);
    } else if (message.getState() == DiggingMessage.STATE_DROP_ITEM) {
      player.dropItemInHand(false);
      return;
    } else if (message.getState() == DiggingMessage.STATE_DROP_ITEMSTACK) {
      player.dropItemInHand(true);
      return;
    } else if (message.getState() == DiggingMessage.STATE_SHOT_ARROW_FINISH_EATING
        && player.getUsageItem() != null) {
      if (player.getUsageItem().equals(holding)) {
        ItemType type = ItemTable.instance().getItem(player.getUsageItem().getType());
        ((ItemTimedUsage) type).endUse(player, player.getUsageItem());
      } else {
        // todo: verification against malicious clients
        // todo: inform player their item is wrong
      }
      return;
    } else {
      return;
    }

    if (blockBroken && !revert) {
      // fire the block break event
      BlockBreakEvent breakEvent = EventFactory.callEvent(new BlockBreakEvent(block, player));
      if (breakEvent.isCancelled()) {
        BlockPlacementHandler.revert(player, block);
        return;
      }

      BlockType blockType = ItemTable.instance().getBlock(block.getType());
      if (blockType != null) {
        blockType.blockDestroy(player, block, face);
      }

      // destroy the block
      if (!block.isEmpty()
          && !block.isLiquid()
          && player.getGameMode() != GameMode.CREATIVE
          && world.getGameRuleMap().getBoolean("doTileDrops")) {
        for (ItemStack drop : block.getDrops(holding)) {
          GlowItem item = world.dropItemNaturally(block.getLocation(), drop);
          item.setPickupDelay(30);
          item.setBias(player);
        }
      }

      player.addExhaustion(0.025f);

      // STEP_SOUND actually is the block break particles
      world.playEffectExceptTo(
          block.getLocation(), Effect.STEP_SOUND, block.getTypeId(), 64, player);
      GlowBlockState state = block.getState();
      block.setType(Material.AIR);
      if (blockType != null) {
        blockType.afterDestroy(player, block, face, state);
      }
    } else if (revert) {
      // replace the block that wasn't really dug
      BlockPlacementHandler.revert(player, block);
    } else if (block.getType() != Material.AIR) {
      BlockType blockType = ItemTable.instance().getBlock(block.getType());
      blockType.leftClickBlock(player, block, holding);
    }
  }
Пример #7
0
  /**
   * Sets the player associated with this session.
   *
   * @param profile The player's profile with name and UUID information.
   * @throws IllegalStateException if there is already a player associated with this session.
   */
  public void setPlayer(PlayerProfile profile) {
    if (player != null) {
      throw new IllegalStateException("Cannot set player twice");
    }

    // isActive check here in case player disconnected during authentication
    if (!isActive()) {
      // no need to call onDisconnect() since it only does anything if there's a player set
      return;
    }

    // initialize the player
    PlayerDataService.PlayerReader reader =
        server.getPlayerDataService().beginReadingData(profile.getUniqueId());
    player = new GlowPlayer(this, profile, reader);

    // isActive check here in case player disconnected after authentication,
    // but before the GlowPlayer initialization was completed
    if (!isActive()) {
      onDisconnect();
      return;
    }

    // login event
    PlayerLoginEvent event = EventFactory.onPlayerLogin(player, hostname);
    if (event.getResult() != PlayerLoginEvent.Result.ALLOWED) {
      disconnect(event.getKickMessage(), true);
      return;
    }

    // joins the player
    player.join(this, reader);

    // Kick other players with the same UUID
    for (GlowPlayer other : getServer().getOnlinePlayers()) {
      if (other != player && other.getUniqueId().equals(player.getUniqueId())) {
        other.getSession().disconnect("You logged in from another location.", true);
        break;
      }
    }

    player.getWorld().getRawPlayers().add(player);

    online = true;

    GlowServer.logger.info(
        player.getName() + " [" + address + "] connected, UUID: " + player.getUniqueId());

    // message and user list
    String message = EventFactory.onPlayerJoin(player).getJoinMessage();
    if (message != null && !message.isEmpty()) {
      server.broadcastMessage(message);
    }

    // todo: display names are included in the outgoing messages here, but
    // don't show up on the client. A workaround or proper fix is needed.
    Message addMessage =
        new UserListItemMessage(UserListItemMessage.Action.ADD_PLAYER, player.getUserListEntry());
    List<UserListItemMessage.Entry> entries = new ArrayList<>();
    for (GlowPlayer other : server.getOnlinePlayers()) {
      if (other != player && other.canSee(player)) {
        other.getSession().send(addMessage);
      }
      if (player.canSee(other)) {
        entries.add(other.getUserListEntry());
      }
    }
    send(new UserListItemMessage(UserListItemMessage.Action.ADD_PLAYER, entries));
  }