Woodcutting.java 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package com.gmail.nossr50.skills.woodcutting;
  2. import com.gmail.nossr50.config.AdvancedConfig;
  3. import com.gmail.nossr50.config.Config;
  4. import com.gmail.nossr50.config.experience.ExperienceConfig;
  5. import com.gmail.nossr50.datatypes.skills.PrimarySkillType;
  6. import com.gmail.nossr50.mcMMO;
  7. import com.gmail.nossr50.util.BlockUtils;
  8. import com.gmail.nossr50.util.Misc;
  9. import com.gmail.nossr50.util.skills.SkillUtils;
  10. import org.bukkit.Material;
  11. import org.bukkit.block.BlockFace;
  12. import org.bukkit.block.BlockState;
  13. import org.bukkit.inventory.ItemStack;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. import java.util.Set;
  17. public final class Woodcutting {
  18. public static int treeFellerThreshold = Config.getInstance().getTreeFellerThreshold();
  19. protected static boolean treeFellerReachedThreshold = false;
  20. protected enum ExperienceGainMethod {
  21. DEFAULT,
  22. TREE_FELLER,
  23. }
  24. private Woodcutting() {}
  25. /**
  26. * Retrieves the experience reward from a log
  27. *
  28. * @param blockState Log being broken
  29. * @param experienceGainMethod How the log is being broken
  30. * @return Amount of experience
  31. */
  32. protected static int getExperienceFromLog(BlockState blockState, ExperienceGainMethod experienceGainMethod) {
  33. if (mcMMO.getModManager().isCustomLog(blockState)) {
  34. return mcMMO.getModManager().getBlock(blockState).getXpGain();
  35. }
  36. return ExperienceConfig.getInstance().getXp(PrimarySkillType.WOODCUTTING, blockState.getType());
  37. }
  38. /**
  39. * Checks for double drops
  40. *
  41. * @param blockState Block being broken
  42. */
  43. protected static void checkForDoubleDrop(BlockState blockState) {
  44. if (mcMMO.getModManager().isCustomLog(blockState) && mcMMO.getModManager().getBlock(blockState).isDoubleDropEnabled()) {
  45. Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
  46. }
  47. else {
  48. if (Config.getInstance().getWoodcuttingDoubleDropsEnabled(blockState.getBlockData())) {
  49. Misc.dropItems(Misc.getBlockCenter(blockState), blockState.getBlock().getDrops());
  50. }
  51. }
  52. }
  53. /**
  54. * The x/y differences to the blocks in a flat cylinder around the center
  55. * block, which is excluded.
  56. */
  57. private static final int[][] directions = {
  58. new int[] {-2, -1}, new int[] {-2, 0}, new int[] {-2, 1},
  59. new int[] {-1, -2}, new int[] {-1, -1}, new int[] {-1, 0}, new int[] {-1, 1}, new int[] {-1, 2},
  60. new int[] { 0, -2}, new int[] { 0, -1}, new int[] { 0, 1}, new int[] { 0, 2},
  61. new int[] { 1, -2}, new int[] { 1, -1}, new int[] { 1, 0}, new int[] { 1, 1}, new int[] { 1, 2},
  62. new int[] { 2, -1}, new int[] { 2, 0}, new int[] { 2, 1},
  63. };
  64. /**
  65. * Processes Tree Feller in a recursive manner
  66. *
  67. * @param blockState Block being checked
  68. * @param treeFellerBlocks List of blocks to be removed
  69. */
  70. /*
  71. * Algorithm: An int[][] of X/Z directions is created on static class
  72. * initialization, representing a cylinder with radius of about 2 - the
  73. * (0,0) center and all (+-2, +-2) corners are omitted.
  74. *
  75. * handleBlock() returns a boolean, which is used for the sole purpose of
  76. * switching between these two behaviors:
  77. *
  78. * (Call blockState "this log" for the below explanation.)
  79. *
  80. * [A] There is another log above this log (TRUNK)
  81. * Only the flat cylinder in the directions array is searched.
  82. * [B] There is not another log above this log (BRANCH AND TOP)
  83. * The cylinder in the directions array is extended up and down by 1
  84. * block in the Y-axis, and the block below this log is checked as
  85. * well. Due to the fact that the directions array will catch all
  86. * blocks on a red mushroom, the special method for it is eliminated.
  87. *
  88. * This algorithm has been shown to achieve a performance of 2-5
  89. * milliseconds on regular trees and 10-15 milliseconds on jungle trees
  90. * once the JIT has optimized the function (use the ability about 4 times
  91. * before taking measurements).
  92. */
  93. protected static void processTree(BlockState blockState, Set<BlockState> treeFellerBlocks) {
  94. List<BlockState> futureCenterBlocks = new ArrayList<BlockState>();
  95. // Check the block up and take different behavior (smaller search) if it's a log
  96. if (handleBlock(blockState.getBlock().getRelative(BlockFace.UP).getState(), futureCenterBlocks, treeFellerBlocks)) {
  97. for (int[] dir : directions) {
  98. handleBlock(blockState.getBlock().getRelative(dir[0], 0, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
  99. if (treeFellerReachedThreshold) {
  100. return;
  101. }
  102. }
  103. }
  104. else {
  105. // Cover DOWN
  106. handleBlock(blockState.getBlock().getRelative(BlockFace.DOWN).getState(), futureCenterBlocks, treeFellerBlocks);
  107. // Search in a cube
  108. for (int y = -1; y <= 1; y++) {
  109. for (int[] dir : directions) {
  110. handleBlock(blockState.getBlock().getRelative(dir[0], y, dir[1]).getState(), futureCenterBlocks, treeFellerBlocks);
  111. if (treeFellerReachedThreshold) {
  112. return;
  113. }
  114. }
  115. }
  116. }
  117. // Recursive call for each log found
  118. for (BlockState futureCenterBlock : futureCenterBlocks) {
  119. if (treeFellerReachedThreshold) {
  120. return;
  121. }
  122. processTree(futureCenterBlock, treeFellerBlocks);
  123. }
  124. }
  125. /**
  126. * Handles the durability loss
  127. *
  128. * @param treeFellerBlocks List of blocks to be removed
  129. * @param inHand tool being used
  130. * @return True if the tool can sustain the durability loss
  131. */
  132. protected static boolean handleDurabilityLoss(Set<BlockState> treeFellerBlocks, ItemStack inHand) {
  133. short durabilityLoss = 0;
  134. Material type = inHand.getType();
  135. for (BlockState blockState : treeFellerBlocks) {
  136. if (BlockUtils.isLog(blockState)) {
  137. durabilityLoss += Config.getInstance().getAbilityToolDamage();
  138. }
  139. }
  140. SkillUtils.handleDurabilityChange(inHand, durabilityLoss);
  141. return (inHand.getDurability() < (mcMMO.getRepairableManager().isRepairable(type) ? mcMMO.getRepairableManager().getRepairable(type).getMaximumDurability() : type.getMaxDurability()));
  142. }
  143. /**
  144. * Handle a block addition to the list of blocks to be removed and to the
  145. * list of blocks used for future recursive calls of
  146. * 'processTree()'
  147. *
  148. * @param blockState Block to be added
  149. * @param futureCenterBlocks List of blocks that will be used to call
  150. * 'processTree()'
  151. * @param treeFellerBlocks List of blocks to be removed
  152. * @return true if and only if the given blockState was a Log not already
  153. * in treeFellerBlocks.
  154. */
  155. private static boolean handleBlock(BlockState blockState, List<BlockState> futureCenterBlocks, Set<BlockState> treeFellerBlocks) {
  156. if (treeFellerBlocks.contains(blockState) || mcMMO.getPlaceStore().isTrue(blockState)) {
  157. return false;
  158. }
  159. // Without this check Tree Feller propagates through leaves until the threshold is hit
  160. if (treeFellerBlocks.size() > treeFellerThreshold) {
  161. treeFellerReachedThreshold = true;
  162. }
  163. if (BlockUtils.isLog(blockState)) {
  164. treeFellerBlocks.add(blockState);
  165. futureCenterBlocks.add(blockState);
  166. return true;
  167. }
  168. else if (BlockUtils.isLeaves(blockState)) {
  169. treeFellerBlocks.add(blockState);
  170. return false;
  171. }
  172. return false;
  173. }
  174. }