Thursday, April 30, 2015

Analysis of Ender Quarry Mechanics


Abstract: The code of the Ender Quarry mod is analyzed, paying particular attention to what affects mining speed. The fastest the quarry can mine is 180 blocks/second. It might take half a million RF/tick to power a quarry going that fast. If you are power limited, adding speed upgrades beyond Speed I will make your quarry slower, not faster.

The Ender Quarry is not open source, but with Java Decompiler it becomes such. The code is uncommented, but most of the variable names are still in place, so it is pretty easy to figure out what is going on. I am using ExtraUtilities 1.2.4b . The code is not obfuscated, except to the degree that interfacing with obfuscated Minecraft requires it. For deobfuscation when required, I used the tables for Minecraft 1.7.10 provided by ModCoderPack 9.08 (but just the tables, not the program).


There is a flag called overClock which is false most of the time, but when it is set, it makes the quarry run unreasonably fast. As far as I can tell, it can't be activated in normal game-play, but only by changing the code and recompiling. Since the flag is off most of the time, I will ignore it in the description below.

The most interesting thing is function func_145845_h(), which I believe is the tick handler. It does a lot of things, involving checking if it has a fence/area defined, checking if it has an inventory attached, etc. Where it starts getting interesting is the tick counter. This tick counter is incremented each time through, and if it is less than the value determined by getSpeedNo(), it returns immediately. getSpeedNo() is 3 if there are no speed upgrades attached, and 1 if any type of speed upgrade is attached. Therefore, the quarry will only check for blocks to harvest once every three ticks if there are no speed upgrades, and once every tick if there are any speed upgrades.

Next it does a bunch of stuff involving chunk loading, which is interesting in itself, but not for my present purposes.

Now that we have decided to try to mine this tick, we decide how many times to mine. If we are on speed 1 or no speed upgrade, we mine one block. Speed 2 mines 3 blocks, and speed 3 mines 9 blocks. In other words, each speed upgrade step triples the number of blocks mined per tick, from 1 in 3 to 1 to 3 to 9.

Next, we keep track of a variable called neededEnergy. This variable is set to -1 every 100 ticks or whenever a block is mined (defined by mineBlock() returning true, see below). If there is more energy than neededEnergy and at least a base amount of power can be drawn, then we try to mine the block. Whenever a block is attempted to mine, the neededEnergy value is set to the amount of power it takes to break that block. Therefore, in most instances, we won't try to break the next block until we have enough power stored to break the last block. We put a particle in the block we are mining, and try to mine it.

Now that we are trying to mine a block, we see if we were successful by running mineBlock(), which returns true if we need to skip to the next block. We run the following rules in order:


  • If it is an air block, skip to the next block, draw the base amount of power, but don't mine anything.
  • If it is on the block breaking blacklist, skip to the next block, draw the base amount of power and don't mine anything. However, if the block is fluid and we have a fluid drainer upgrade, we try to drain the fluid.
  • If we are replacing things with dirt, but this block is leaves, foliage, wood, plantable, or growable, then we skip to the next block, draw the base amount of power but don't mine anything.
  • If the block hardness is negative, (equivalent to infinite) we skip to the next block, draw the base amount of power, but don't mine anything.
  • Now we calculate how much power it takes to break the block. This is the base amount plus the product of the block hardness, the block hardness drain factor, and the products of the power multipliers of all the upgrades. 
  • If we have enough energy stored to break the block, we draw that amount of power and break the block. We call harvestBlock() to add things to the quarry's inventory, then replace the block with either dirt or air, depending on the world hole upgrade. If the block was dirt or grass and we are replacing with dirt, we have a chance to plant grass or flowers on the block.
So, we are at the interesting part of this analysis. The most important thing right off is that the power usage is not per tick, but per block. The table of power usage multipliers is as follows:

  • Nothing: 1.0
  • World hole (UPGRADE_VOID): 1.0 (it doesn't cost any extra power to world-hole or not)
  • Silk touch: 1.5
  • Fortune I: 5
  • Fortune II: 20
  • Fortune III: 80
  • Speed I: 1.0 (no extra power per block, but more blocks per tick, so it uses three times as much power per tick)
  • Speed II: 1.5 (This represents extra power on a per-block basis)
  • Speed III: 2.0 (Likewise)
  • Fluid: 1.0 (No extra cost to pump fluids. Fluids cost only the base amount to pump)
The base cost is 1800 RF, and the hardness factor is 200 RF/hardness unit. The effect of the base energy draw is that it takes that much energy to just move the quarry cutting head from one block to the next. It costs 1800RF/block to mine air.

So, as an example, smooth stone has a hardness of 1.5 . To mine pure stone, we see the following:

  • With no upgrades, we mine one stone every 3 ticks, for a cost of 1800+200*1.5 or 2100 RF, at 700 RF/tick average speed.
  • With speed 1, we mine one block every tick, same cost per block, but 2100RF/tick.
  • With speed 2, we mine three blocks per tick, at a cost of 1800+200*1.5*1.5 or 2250 RF/block, 6750/tick
  • With speed 3, we mine nine blocks, at a cost of 1800+200*1.5*2=2400 RF/block or 21600 RF/tick.
  • With speed 3 and fortune 1, we mine nine blocks, at a cost of 1800+200*1.5*2*5=4800 RF/block or 43200 RF/tick.
  • With speed 3 and fortune 2, we mine nine blocks, at a cost of 1800+200*1.5*2*20=13800 RF/block or 124200 RF/tick.
  • With speed 3 and fortune 3, we mine nine blocks, at a cost of 1800+200*1.5*2*80=49800 RF/block or 448200 RF/tick.
In other words, with the full upgrade, it takes about half a million RF/tick to mine stone (most ores are harder, but dirt is softer, so it works out). It makes sense to mine with fortune 3 to get the most out of a given chunk, but if you don't have enough power, it doesn't make sense to throw speed upgrades at it, since you will be limited by the power draw, not the tick rate. The maximum speed is 9 blocks per tick, or 180 blocks per second. Starting near sea level, this is about 3 columns of blocks per second. 

With fortune 3, we want to look at how much power is required for each speed upgrade, to compare to our power source:

  • Fortune 3, no speed upgrade: Cost is 1800+200*1.5*1*80=25800 RF/block, or 8600 RF/tick
  • Fortune 3, speed 1: Cost is 1800+200*1.5*1*80=25800 RF/block or 25800 RF/tick
  • Fortune 3, speed 2: Cost is 1800+200*1.5*1.5*80=37800 RF/block or 113400 RF/tick
  • Fortune 3, speed 3: Cost is 1800+200*1.5*2.0*80=49800 RF/block or 448200 RF/tick
If you can't supply the given RF/tick, you are wasting some of the speed upgrade. Your effective mining rate will be (RF supplied)/(RF required) times the maximum rate. So, suppose you have a BigReactor with 20000 RF/tick. You will mine at the following rate with each speed upgrade:

  • Fortune 3, no speed: Full rate, 1 block every 3 ticks, 0.333 blocks per tick
  • Fortune 3, speed 1: 77.5% of full rate, 0.775 blocks per tick
  • Fortune 3, speed 2: 17.6% of full rate, 0.529 blocks per tick
  • Fortune 3, speed 3: 4.5% of full rate, 0.401 blocks per tick
Note that in this case, adding too many speed upgrades makes your quarry slower due to the loss of efficiency. In this case, optimum mining is with speed 1.

No comments:

Post a Comment