<commit_before>var Item = require('../item');
var assert = require('assert');
var Vec3 = require('vec3').Vec3;
var windows = require('../windows');

module.exports = inject;


// ms to wait before clicking on a tool so the server can send the new
// damage information
var DIG_CLICK_TIMEOUT = 500;


function inject(bot) {
  var nextActionNumber = 0;
  var windowClickQueue = [];

  // 0-8, null = uninitialized
  // which quick bar slot is selected
  bot.quickBarSlot = null;
  bot.inventory = new windows.InventoryWindow(0, "Inventory", 44);
  bot.currentWindow = null;
  bot.heldItem = null;

  function activateItem() {
    bot._client.write('block_place', {
      location:new Vec3(-1,255,-1),
      direction: -1,
      heldItem: Item.toNotch(bot.heldItem),
      cursorX: -1,
      cursorY: -1,
      cursorZ: -1
    });
  }

  function deactivateItem() {
    bot._client.write('block_dig', {
      status: 5,
      location:new Vec3(0,0,0),
      face: 5
    });
  }


  function putSelectedItemRange(start, end, window, slot, cb) {
    // put the selected item back indow the slot range in window

    // try to put it in an item that already exists and just increase
    // the count.
    tryToJoin();

    function tryToJoin() {
      if (! window.selectedItem) {
        cb();
        return;
      }
      var item = window.findItemRange(start, end, window.selectedItem.type,
          window.selectedItem.metadata, true);
      if (item) {
        clickWindow(item.slot, 0, 0, onClick);
      } else {
        tryToFindEmpty();
      }

      function onClick(err) {
        if (err) {
          cb(err);
        } else {
          tryToJoin();
        }
      }
    }
    function tryToFindEmpty() {
      var emptySlot = window.firstEmptySlotRange(start, end);
      if (emptySlot == null) {
        // if there is still some leftover and slot is not null, click slot
        if (slot == null) {
          tossLeftover();
        } else {
          clickWindow(slot, 0, 0, tossLeftover);
        }
      } else {
        clickWindow(emptySlot, 0, 0, cb);
      }
    }
    function tossLeftover() {
      if (window.selectedItem) {
        clickWindow(-999, 0, 0, cb);
      } else {
        cb();
      }
    }
  }

  function activateBlock(block) {
    // TODO: tell the server that we are not sneaking while doing this
    bot.lookAt(block.position);
    // swing arm animation
    bot._client.write('arm_animation', {
      entityId: bot.entity.id,
      animation: 1
    });
    // place block message
    bot._client.write('block_place', {
      location:block.position,
      direction: 1,
      heldItem: Item.toNotch(bot.heldItem),
      cursorX: 8,
      cursorY: 8,
      cursorZ: 8
    });
  }


  function transfer(options, cb) {
    var window = options.window || bot.currentWindow || bot.inventory;
    var itemType = options.itemType;
    var metadata = options.metadata;
    var count = options.count == null ? 1 : options.count;
    cb = cb || noop;
    var firstSourceSlot = null;

    // ranges
    var sourceStart = options.sourceStart;
    var destStart = options.destStart;
    assert.notEqual(sourceStart, null);
    assert.notEqual(destStart, null);
    var sourceEnd = options.sourceEnd == null ? sourceStart + 1 : options.sourceEnd;
    var destEnd = options.destEnd == null ? destStart + 1 : options.destEnd;

    transferOne();

    function transferOne() {
      if (count === 0) {
        putSelectedItemRange(sourceStart, sourceEnd, window, firstSourceSlot, cb);
        return;
      }
      if (!window.selectedItem || window.selectedItem.type !== itemType ||
        (metadata != null && window.selectedItem.metadata !== metadata))
      {
        // we are not holding the item we need. click it.
        var sourceItem = window.findItemRange(sourceStart, sourceEnd, itemType, metadata);
        if (!sourceItem) return cb(new Error("missing source item "+itemType+":"+metadata+" in ("+sourceStart+","+sourceEnd+")"));
        if (firstSourceSlot == null) firstSourceSlot = sourceItem.slot;
        clickWindow(sourceItem.slot, 0, 0, function(err) {
          if (err) {
            cb(err);
          } else {
            clickDest();
          }
        });
      } else {
        clickDest();
      }

      function clickDest() {
        assert.notEqual(window.selectedItem.type, null);
        assert.notEqual(window.selectedItem.metadata, null);
        var destItem, destSlot;
        // special case for tossing
        if (destStart === -999) {
          destSlot = -999;
        } else {
          // find a non full item that we can drop into
          destItem = window.findItemRange(destStart, destEnd,
              window.selectedItem.type, window.selectedItem.metadata, true);
          // if that didn't work find an empty slot to drop into
          destSlot = destItem ? destItem.slot :
            window.firstEmptySlotRange(destStart, destEnd);
          // if that didn't work, give up
          if (destSlot == null) {
            cb(new Error("destination full"));
            return;
          }
        }
        clickWindow(destSlot, 1, 0, function(err) {
          if (err) {
            cb(err);
          } else {
            count -= 1;
            transferOne();
          }
        });
      }
    }
  }

  function openBlock(block, Class) {
    var session = new Class();
    session.close = close;
    bot.once("windowOpen", onWindowOpen);
    bot.activateBlock(block);
    return session;
    function onWindowOpen(window) {
      if (window.type !== Class.windowType) return;<commit_msg>make bot.transfer fast : improve speed of tossing and other window movement (chest for example) by left clicking when possible instead of doing only right clicks see #129, thanks @Corgano<commit_after>var Item = require('../item');
var assert = require('assert');
var Vec3 = require('vec3').Vec3;
var windows = require('../windows');

module.exports = inject;


// ms to wait before clicking on a tool so the server can send the new
// damage information
var DIG_CLICK_TIMEOUT = 500;


function inject(bot) {
  var nextActionNumber = 0;
  var windowClickQueue = [];

  // 0-8, null = uninitialized
  // which quick bar slot is selected
  bot.quickBarSlot = null;
  bot.inventory = new windows.InventoryWindow(0, "Inventory", 44);
  bot.currentWindow = null;
  bot.heldItem = null;

  function activateItem() {
    bot._client.write('block_place', {
      location:new Vec3(-1,255,-1),
      direction: -1,
      heldItem: Item.toNotch(bot.heldItem),
      cursorX: -1,
      cursorY: -1,
      cursorZ: -1
    });
  }

  function deactivateItem() {
    bot._client.write('block_dig', {
      status: 5,
      location:new Vec3(0,0,0),
      face: 5
    });
  }


  function putSelectedItemRange(start, end, window, slot, cb) {
    // put the selected item back indow the slot range in window

    // try to put it in an item that already exists and just increase
    // the count.
    tryToJoin();

    function tryToJoin() {
      if (! window.selectedItem) {
        cb();
        return;
      }
      var item = window.findItemRange(start, end, window.selectedItem.type,
          window.selectedItem.metadata, true);
      if (item) {
        clickWindow(item.slot, 0, 0, onClick);
      } else {
        tryToFindEmpty();
      }

      function onClick(err) {
        if (err) {
          cb(err);
        } else {
          tryToJoin();
        }
      }
    }
    function tryToFindEmpty() {
      var emptySlot = window.firstEmptySlotRange(start, end);
      if (emptySlot == null) {
        // if there is still some leftover and slot is not null, click slot
        if (slot == null) {
          tossLeftover();
        } else {
          clickWindow(slot, 0, 0, tossLeftover);
        }
      } else {
        clickWindow(emptySlot, 0, 0, cb);
      }
    }
    function tossLeftover() {
      if (window.selectedItem) {
        clickWindow(-999, 0, 0, cb);
      } else {
        cb();
      }
    }
  }

  function activateBlock(block) {
    // TODO: tell the server that we are not sneaking while doing this
    bot.lookAt(block.position);
    // swing arm animation
    bot._client.write('arm_animation', {
      entityId: bot.entity.id,
      animation: 1
    });
    // place block message
    bot._client.write('block_place', {
      location:block.position,
      direction: 1,
      heldItem: Item.toNotch(bot.heldItem),
      cursorX: 8,
      cursorY: 8,
      cursorZ: 8
    });
  }


  function transfer(options, cb) {
    var window = options.window || bot.currentWindow || bot.inventory;
    var itemType = options.itemType;
    var metadata = options.metadata;
    var count = options.count == null ? 1 : options.count;
    cb = cb || noop;
    var firstSourceSlot = null;

    // ranges
    var sourceStart = options.sourceStart;
    var destStart = options.destStart;
    assert.notEqual(sourceStart, null);
    assert.notEqual(destStart, null);
    var sourceEnd = options.sourceEnd == null ? sourceStart + 1 : options.sourceEnd;
    var destEnd = options.destEnd == null ? destStart + 1 : options.destEnd;

    transferOne();

    function transferOne() {
      if (count === 0) {
        putSelectedItemRange(sourceStart, sourceEnd, window, firstSourceSlot, cb);
        return;
      }
      if (!window.selectedItem || window.selectedItem.type !== itemType ||
        (metadata != null && window.selectedItem.metadata !== metadata))
      {
        // we are not holding the item we need. click it.
        var sourceItem = window.findItemRange(sourceStart, sourceEnd, itemType, metadata);
        if (!sourceItem) return cb(new Error("missing source item "+itemType+":"+metadata+" in ("+sourceStart+","+sourceEnd+")"));
        if (firstSourceSlot == null) firstSourceSlot = sourceItem.slot;
        // number of item that can be moved from that slot
        var sourceItemCount = sourceItem.count;
        clickWindow(sourceItem.slot, 0, 0, function(err) {
          if (err) {
            cb(err);
          } else {
            clickDest();
          }
        });
      } else {
        clickDest();
      }

      function clickDest() {
        assert.notEqual(window.selectedItem.type, null);
        assert.notEqual(window.selectedItem.metadata, null);
        var destItem, destSlot;
        // special case for tossing
        if (destStart === -999) {
          destSlot = -999;
        } else {
          // find a non full item that we can drop into
          destItem = window.findItemRange(destStart, destEnd,
              window.selectedItem.type, window.selectedItem.metadata, true);
          // if that didn't work find an empty slot to drop into
          destSlot = destItem ? destItem.slot :
            window.firstEmptySlotRange(destStart, destEnd);
          // if that didn't work, give up
          if (destSlot == null) {
            cb(new Error("destination full"));
            return;
          }
        }
        // move the maximum number of item that can be moved
        var destSlotCount=destSlot.count ? destSlot.count : 0;
        var movedItems = Math.min(64-destSlotCount,sourceItemCount);
        // if the number of item the left click moves is less than the number of item we want to move
        // several at the same time (left click)
        if (movedItems <= count){
          clickWindow(destSlot, 0, 0, function(err) {
            if (err) {
              cb(err);
            } else {
              // update the number of item that can be moved at the source slot (sourceItemCount)
              sourceItemCount -= movedItems;
              // and the number of item we want to move (count)
              count -= movedItems;
              transferOne();
            }
          });
        }
        // one by one (right click)
        else {
          clickWindow(destSlot, 1, 0, function(err) {
            if (err) {
              cb(err);
            } else {
              count -= 1;
              transferOne();
            }
          });
        }
      }
    }
  }

  function openBlock(block, Class) {
    var session = new Class();
    session.close = close;
    bot.once("windowOpen", onWindowOpen);
    bot.activateBlock(block);
    return session;
    function onWindowOpen(window) {
      if (window.type !== Class.windowType) return;
{'fraction_non_alphanumeric': 0.11584672836499432, 'fraction_numerical': 0.010228933268387726, 'mean_word_length': 2.103022670025189, 'pattern_counts': {'":': 2, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4299016', 'n_tokens_mistral': 3648, 'n_tokens_neox': 3508, 'n_words': 1006}