private void addPlayer(EntityPlayerMP newPlayer) {
    if (!players.containsKey(newPlayer)) {
      players.put(newPlayer, 1);
      // playerSelections starts off null = no selection
      MultipartOneAtATimeReceiver newReceiver = new MultipartOneAtATimeReceiver();
      newReceiver.registerPacketCreator(new SelectionPacket.SelectionPacketCreator());
      newReceiver.registerLinkageFactory(new VoxelLinkageFactory(newPlayer));
      newReceiver.setPacketSender(new PacketSenderServer(packetHandlerRegistryServer, newPlayer));
      playerMOATreceivers.put(newPlayer, newReceiver);

      MultipartOneAtATimeSender newSender =
          new MultipartOneAtATimeSender(
              packetHandlerRegistryServer,
              null,
              Packet250Types.PACKET250_SELECTION_PACKET_ACKNOWLEDGE,
              Side.SERVER);
      newSender.setPacketSender(new PacketSenderServer(packetHandlerRegistryServer, newPlayer));
      playerMOATsenders.put(newPlayer, newSender);
      //      playerBlockVoxelMultiSelectors.put(newPlayer, new BlockVoxelMultiSelector());
    }
  }
  /**
   * handle timeouts etc
   *
   * @param maximumDurationInNS - the maximum amount of time to spend generating selections for
   *     clients. 0 = don't generate any.
   */
  public void tick(long maximumDurationInNS) {
    for (MultipartOneAtATimeReceiver receiver : playerMOATreceivers.values()) {
      receiver.onTick();
    }
    for (MultipartOneAtATimeSender sender : playerMOATsenders.values()) {
      sender.onTick();
    }

    if (maximumDurationInNS == 0) return;

    boolean foundSuitable = false;
    CommandQueueEntry currentCommand;
    do {
      currentCommand = commandQueue.peekFirst();
      if (currentCommand == null) return;
      if (currentCommand.entityPlayerMP.get() == null) {
        commandQueue.removeFirst();
      } else {
        foundSuitable = true;
      }
    } while (!foundSuitable);
    EntityPlayerMP entityPlayerMP = currentCommand.entityPlayerMP.get();
    World playerWorld = entityPlayerMP.getEntityWorld();
    Packet250ServerSelectionGeneration commandPacket = currentCommand.commandPacket;

    if (!currentCommand.hasStarted) {
      BlockVoxelMultiSelector blockVoxelMultiSelector = new BlockVoxelMultiSelector();
      playerBlockVoxelMultiSelectors.put(entityPlayerMP, blockVoxelMultiSelector);
      playerCommandStatus.put(entityPlayerMP, CommandStatus.EXECUTING);
      currentCommand.blockVoxelMultiSelector = blockVoxelMultiSelector;
      switch (commandPacket.getCommand()) {
        case ALL_IN_BOX:
          {
            blockVoxelMultiSelector.selectAllInBoxStart(
                playerWorld, commandPacket.getCorner1(), commandPacket.getCorner2());
            break;
          }
        case UNBOUND_FILL:
          {
            blockVoxelMultiSelector.selectUnboundFillStart(
                playerWorld, commandPacket.getFillAlgorithmSettings());
            break;
          }
        case BOUND_FILL:
          {
            blockVoxelMultiSelector.selectBoundFillStart(
                playerWorld,
                commandPacket.getFillAlgorithmSettings(),
                commandPacket.getCorner1(),
                commandPacket.getCorner2());
            break;
          }
        default:
          {
            ErrorLog.defaultLog()
                .severe("Invalid command in ServerVoxelSelections: " + commandPacket.getCommand());
            break;
          }
      }
      currentCommand.hasStarted = true;
    } else {
      BlockVoxelMultiSelector blockVoxelMultiSelector = currentCommand.blockVoxelMultiSelector;
      float progress =
          blockVoxelMultiSelector.continueSelectionGeneration(playerWorld, maximumDurationInNS);
      if (progress < 0) { // finished
        BlockPos origin = blockVoxelMultiSelector.getWorldOrigin();
        VoxelSelectionWithOrigin newSelection =
            new VoxelSelectionWithOrigin(
                origin.getX(),
                origin.getY(),
                origin.getZ(),
                blockVoxelMultiSelector.getSelection());
        //        System.out.println("New selection origin: ["  + newSelection.getWxOrigin()
        //                                   + ", " + newSelection.getWyOrigin()
        //                                   + ", " + newSelection.getWzOrigin()+"]");

        playerSelections.put(entityPlayerMP, newSelection);
        playerBlockVoxelMultiSelectors.remove(entityPlayerMP);
        playerCommandStatus.put(entityPlayerMP, CommandStatus.COMPLETED);

        MultipartOneAtATimeSender sender = playerMOATsenders.get(entityPlayerMP);
        if (sender != null) {
          SelectionPacket selectionPacket =
              SelectionPacket.createSenderPacket(blockVoxelMultiSelector, Side.SERVER);
          SenderLinkage newLinkage =
              new SenderLinkage(entityPlayerMP, selectionPacket.getUniqueID());
          playerSenderLinkages.put(entityPlayerMP, newLinkage);
          //          System.out.println("send new Multipart Selection from server to client, ID = "
          // + selectionPacket.getUniqueID()); // todo remove
          sender.sendMultipartPacket(newLinkage, selectionPacket);
        }
        assert (commandQueue.peekFirst() == currentCommand);
        commandQueue.removeFirst();
      }
    }
  }