50
50
public class HerbalismManager extends SkillManager {
51
51
private final static HashMap <String , Integer > plantBreakLimits ;
52
52
53
+ private static final String CACTUS_STR = "cactus" ;
54
+ private static final String CACTUS_FLOWER_STR = "cactus_flower" ;
55
+
53
56
static {
54
57
plantBreakLimits = new HashMap <>();
55
- plantBreakLimits .put ("cactus" , 3 );
58
+ plantBreakLimits .put (CACTUS_STR , 3 );
56
59
plantBreakLimits .put ("bamboo" , 20 );
57
60
plantBreakLimits .put ("sugar_cane" , 3 );
58
61
plantBreakLimits .put ("kelp" , 26 );
@@ -68,10 +71,13 @@ public boolean canGreenThumbBlock(BlockState blockState) {
68
71
if (!RankUtils .hasUnlockedSubskill (getPlayer (), SubSkillType .HERBALISM_GREEN_THUMB ))
69
72
return false ;
70
73
71
- Player player = getPlayer ();
72
- ItemStack item = player .getInventory ().getItemInMainHand ();
74
+ final Player player = getPlayer ();
75
+ final ItemStack item = player .getInventory ().getItemInMainHand ();
73
76
74
- return item .getAmount () > 0 && item .getType () == Material .WHEAT_SEEDS && BlockUtils .canMakeMossy (blockState ) && Permissions .greenThumbBlock (player , blockState .getType ());
77
+ return item .getAmount () > 0
78
+ && item .getType () == Material .WHEAT_SEEDS
79
+ && BlockUtils .canMakeMossy (blockState .getBlock ())
80
+ && Permissions .greenThumbBlock (player , blockState .getType ());
75
81
}
76
82
77
83
public boolean canUseShroomThumb (BlockState blockState ) {
@@ -163,10 +169,6 @@ public boolean canUseHylianLuck() {
163
169
return Permissions .isSubSkillEnabled (getPlayer (), SubSkillType .HERBALISM_HYLIAN_LUCK );
164
170
}
165
171
166
- public boolean canGreenTerraBlock (BlockState blockState ) {
167
- return mmoPlayer .getAbilityMode (SuperAbilityType .GREEN_TERRA ) && BlockUtils .canMakeMossy (blockState );
168
- }
169
-
170
172
public boolean canActivateAbility () {
171
173
return mmoPlayer .getToolPreparationMode (ToolType .HOE ) && Permissions .greenTerra (getPlayer ());
172
174
}
@@ -222,9 +224,9 @@ public void processGreenTerraBlockConversion(Block block) {
222
224
* @param blockBreakEvent The Block Break Event to process
223
225
*/
224
226
public void processHerbalismBlockBreakEvent (BlockBreakEvent blockBreakEvent ) {
225
- Player player = getPlayer ();
227
+ final Player player = getPlayer ();
226
228
227
- Block block = blockBreakEvent .getBlock ();
229
+ final Block block = blockBreakEvent .getBlock ();
228
230
229
231
if (mcMMO .p .getGeneralConfig ().getHerbalismPreventAFK () && player .isInsideVehicle ()) {
230
232
if (block .hasMetadata (MetadataConstants .METADATA_KEY_REPLANT )) {
@@ -235,7 +237,7 @@ public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) {
235
237
236
238
//Check if the plant was recently replanted
237
239
if (block .getBlockData () instanceof Ageable ageableCrop ) {
238
- if (block .getMetadata (MetadataConstants .METADATA_KEY_REPLANT ).size () >= 1 ) {
240
+ if (! block .getMetadata (MetadataConstants .METADATA_KEY_REPLANT ).isEmpty () ) {
239
241
if (block .getMetadata (MetadataConstants .METADATA_KEY_REPLANT ).get (0 ).asBoolean ()) {
240
242
if (isAgeableMature (ageableCrop )) {
241
243
block .removeMetadata (MetadataConstants .METADATA_KEY_REPLANT , mcMMO .p );
@@ -254,9 +256,9 @@ public void processHerbalismBlockBreakEvent(BlockBreakEvent blockBreakEvent) {
254
256
*/
255
257
256
258
//Grab all broken blocks
257
- HashSet <Block > brokenBlocks = getBrokenHerbalismBlocks (blockBreakEvent );
259
+ final HashSet <Block > brokenBlocks = getBrokenHerbalismBlocks (blockBreakEvent );
258
260
259
- if (brokenBlocks .size () == 0 )
261
+ if (brokenBlocks .isEmpty () )
260
262
return ;
261
263
262
264
//Handle rewards, xp, ability interactions, etc
@@ -272,7 +274,8 @@ private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, Has
272
274
if (blockBreakEvent .isCancelled ())
273
275
return ;
274
276
275
- BlockState originalBreak = blockBreakEvent .getBlock ().getState ();
277
+ final BlockState originalBreak = blockBreakEvent .getBlock ().getState ();
278
+ // TODO: Storing this boolean for no reason, refactor
276
279
boolean greenThumbActivated = false ;
277
280
278
281
//TODO: The design of Green Terra needs to change, this is a mess
@@ -322,12 +325,12 @@ private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, Has
322
325
}
323
326
324
327
//Give out XP to the non-chorus blocks
325
- if (noDelayPlantBlocks .size () > 0 ) {
328
+ if (! noDelayPlantBlocks .isEmpty () ) {
326
329
//Note: Will contain 1 chorus block if the original block was a chorus block, this is to prevent delays for the XP bar
327
330
awardXPForPlantBlocks (noDelayPlantBlocks );
328
331
}
329
332
330
- if (delayedChorusBlocks .size () > 0 ) {
333
+ if (! delayedChorusBlocks .isEmpty () ) {
331
334
//Check XP for chorus blocks
332
335
DelayedHerbalismXPCheckTask delayedHerbalismXPCheckTask = new DelayedHerbalismXPCheckTask (mmoPlayer , delayedChorusBlocks );
333
336
@@ -356,15 +359,9 @@ public void checkDoubleDropsOnBrokenPlants(Player player, Collection<Block> brok
356
359
357
360
//Check for double drops
358
361
if (!mcMMO .getUserBlockTracker ().isIneligible (brokenPlant )) {
359
-
360
362
/*
361
- *
362
363
* Natural Blocks
363
- *
364
- *
365
- *
366
364
*/
367
-
368
365
//Not all things that are natural should give double drops, make sure its fully mature as well
369
366
if (plantData instanceof Ageable ageable ) {
370
367
@@ -378,13 +375,9 @@ public void checkDoubleDropsOnBrokenPlants(Player player, Collection<Block> brok
378
375
markForBonusDrops (brokenPlant );
379
376
}
380
377
} else {
381
-
382
378
/*
383
- *
384
379
* Unnatural Blocks
385
- *
386
380
*/
387
-
388
381
//If it's a crop, we need to reward XP when its fully grown
389
382
if (isAgeableAndFullyMature (plantData ) && !isBizarreAgeable (plantData )) {
390
383
//Add metadata to mark this block for double or triple drops
@@ -401,7 +394,7 @@ public void checkDoubleDropsOnBrokenPlants(Player player, Collection<Block> brok
401
394
*/
402
395
public boolean isBizarreAgeable (BlockData blockData ) {
403
396
if (blockData instanceof Ageable ) {
404
- //Catcus and Sugar Canes cannot be trusted
397
+ // Cactus and Sugar Canes cannot be trusted
405
398
return switch (blockData .getMaterial ()) {
406
399
case CACTUS , KELP , SUGAR_CANE , BAMBOO -> true ;
407
400
default -> false ;
@@ -440,12 +433,8 @@ public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) {
440
433
441
434
if (mcMMO .getUserBlockTracker ().isIneligible (brokenBlockNewState )) {
442
435
/*
443
- *
444
436
* Unnatural Blocks
445
- *
446
- *
447
437
*/
448
-
449
438
//If its a Crop we need to reward XP when its fully grown
450
439
if (isAgeableAndFullyMature (plantData ) && !isBizarreAgeable (plantData )) {
451
440
xpToReward += ExperienceConfig .getInstance ().getXp (PrimarySkillType .HERBALISM , brokenBlockNewState .getType ());
@@ -457,13 +446,9 @@ public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) {
457
446
mcMMO .getUserBlockTracker ().setEligible (brokenBlockNewState );
458
447
} else {
459
448
/*
460
- *
461
449
* Natural Blocks
462
- *
463
- *
464
450
*/
465
-
466
- //Calculate XP
451
+ // Calculate XP
467
452
if (plantData instanceof Ageable plantAgeable ) {
468
453
469
454
if (isAgeableMature (plantAgeable ) || isBizarreAgeable (plantData )) {
@@ -481,15 +466,14 @@ public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) {
481
466
}
482
467
483
468
if (mmoPlayer .isDebugMode ()) {
484
- mmoPlayer .getPlayer ().sendMessage ("Plants processed: " + brokenPlants .size ());
469
+ mmoPlayer .getPlayer ().sendMessage ("Plants processed: " + brokenPlants .size ());
485
470
}
486
471
487
472
//Reward XP
488
473
if (xpToReward > 0 ) {
489
474
// get first block from hash set using stream API
490
475
final Block firstBlock = brokenPlants .stream ().findFirst ().orElse (null );
491
476
if (firstBlock != null
492
- && firstXpReward != -1
493
477
&& ExperienceConfig .getInstance ().limitXPOnTallPlants ()
494
478
&& plantBreakLimits .containsKey (firstBlock .getType ().getKey ().getKey ())) {
495
479
int limit = plantBreakLimits .get (firstBlock .getType ().getKey ().getKey ()) * firstXpReward ;
@@ -501,16 +485,6 @@ public void awardXPForPlantBlocks(HashSet<Block> brokenPlants) {
501
485
}
502
486
}
503
487
504
- private int getNaturalGrowthLimit (Material brokenPlant ) {
505
- // This is an exploit counter-measure to prevent players from growing unnaturally tall plants and reaping XP
506
- if (plantBreakLimits .containsKey (brokenPlant .getKey ().getKey ())) {
507
- return plantBreakLimits .get (brokenPlant .getKey ().getKey ());
508
- } else {
509
- return 0 ;
510
- }
511
- }
512
-
513
-
514
488
public boolean isAgeableMature (Ageable ageable ) {
515
489
return ageable .getAge () == ageable .getMaximumAge ()
516
490
&& ageable .getAge () != 0 ;
@@ -529,7 +503,7 @@ public void awardXPForBlockSnapshots(ArrayList<BlockSnapshot> brokenPlants) {
529
503
int blocksGivingXP = 0 ;
530
504
531
505
for (BlockSnapshot blockSnapshot : brokenPlants ) {
532
- BlockState brokenBlockNewState = blockSnapshot .getBlockRef ().getState ();
506
+ final BlockState brokenBlockNewState = blockSnapshot .getBlockRef ().getState ();
533
507
534
508
//Remove metadata from the snapshot of blocks
535
509
if (brokenBlockNewState .hasMetadata (MetadataConstants .METADATA_KEY_BONUS_DROPS )) {
@@ -570,65 +544,66 @@ public void awardXPForBlockSnapshots(ArrayList<BlockSnapshot> brokenPlants) {
570
544
*/
571
545
private HashSet <Block > getBrokenHerbalismBlocks (@ NotNull BlockBreakEvent blockBreakEvent ) {
572
546
//Get an updated capture of this block
573
- BlockState originBlockState = blockBreakEvent .getBlock ().getState ();
574
- Material originBlockMaterial = originBlockState .getType ();
575
- HashSet <Block > blocksBroken = new HashSet <>(); //Blocks broken
547
+ final BlockState originBlockState = blockBreakEvent .getBlock ().getState ();
548
+ final Material originBlockMaterial = originBlockState .getType ();
549
+ final HashSet <Block > blocksBroken = new HashSet <>(); //Blocks broken
576
550
577
551
//Add the initial block
578
552
blocksBroken .add (originBlockState .getBlock ());
579
553
580
554
if (!isOneBlockPlant (originBlockMaterial )) {
581
555
//If the block is a multi-block structure, capture a set of all blocks broken and return that
582
- blocksBroken = getBrokenBlocksMultiBlockPlants (originBlockState );
556
+ addBrokenBlocksMultiBlockPlants (originBlockState , blocksBroken );
583
557
}
584
558
585
559
//Return all broken plant-blocks
586
560
return blocksBroken ;
587
561
}
588
562
589
- private HashSet <Block > getBrokenChorusBlocks (BlockState originalBreak ) {
590
- return grabChorusTreeBrokenBlocksRecursive (originalBreak .getBlock (), new HashSet <>());
591
- }
592
-
593
- private HashSet <Block > grabChorusTreeBrokenBlocksRecursive (Block currentBlock , HashSet <Block > traversed ) {
563
+ private void addChorusTreeBrokenBlocks (Block currentBlock , Set <Block > traversed ) {
594
564
if (!isChorusTree (currentBlock .getType ()))
595
- return traversed ;
565
+ return ;
596
566
597
567
// Prevent any infinite loops, who needs more than 256 chorus anyways
598
568
if (traversed .size () > 256 )
599
- return traversed ;
569
+ return ;
600
570
601
571
if (!traversed .add (currentBlock ))
602
- return traversed ;
572
+ return ;
603
573
604
574
//Grab all Blocks in the Tree
605
575
for (BlockFace blockFace : new BlockFace [] { BlockFace .UP , BlockFace .NORTH , BlockFace .SOUTH , BlockFace .EAST ,BlockFace .WEST })
606
- grabChorusTreeBrokenBlocksRecursive (currentBlock .getRelative (blockFace , 1 ), traversed );
607
-
608
- traversed .add (currentBlock );
609
-
610
- return traversed ;
576
+ addChorusTreeBrokenBlocks (currentBlock .getRelative (blockFace , 1 ), traversed );
611
577
}
612
578
613
- /**
614
- * Grab a set of all plant blocks that are broken as a result of this event
615
- * The method to grab these blocks is a bit hacky and does not hook into the API
616
- * Basically we expect the blocks to be broken if this event is not cancelled and we determine which block are broken on our end rather than any event state captures
617
- *
618
- * @return a set of plant-blocks broken from this event
619
- */
620
- protected HashSet <Block > getBrokenBlocksMultiBlockPlants (BlockState brokenBlock ) {
621
- //Track the broken blocks
622
- HashSet <Block > brokenBlocks ;
623
579
580
+ protected void addBrokenBlocksMultiBlockPlants (BlockState brokenBlock , Set <Block > brokenBlocks ) {
624
581
if (isChorusBranch (brokenBlock .getType ())) {
625
- brokenBlocks = getBrokenChorusBlocks (brokenBlock );
582
+ addChorusTreeBrokenBlocks (brokenBlock .getBlock (), brokenBlocks );
583
+ } else if (isCactus (brokenBlock .getType ())) {
584
+ addCactusBlocks (brokenBlock .getBlock (), brokenBlocks );
626
585
} else {
627
- brokenBlocks = getBlocksBrokenAboveOrBelow (
628
- brokenBlock , false , mcMMO .getMaterialMapStore ().isMultiBlockHangingPlant (brokenBlock .getType ()));
586
+ addBlocksBrokenAboveOrBelow (brokenBlock .getBlock (), brokenBlocks , mcMMO .getMaterialMapStore ().isMultiBlockHangingPlant (brokenBlock .getType ()));
629
587
}
588
+ }
589
+
590
+ private void addCactusBlocks (Block currentBlock , Set <Block > traversed ) {
591
+ if (!isCactus (currentBlock .getType ()))
592
+ return ;
593
+
594
+ if (traversed .size () > 4 ) // Max size 3 cactus + flower
595
+ return ;
630
596
631
- return brokenBlocks ;
597
+ if (!traversed .add (currentBlock ))
598
+ return ;
599
+
600
+ addCactusBlocks (currentBlock .getRelative (BlockFace .UP ), traversed );
601
+ addCactusBlocks (currentBlock .getRelative (BlockFace .DOWN ), traversed );
602
+ }
603
+
604
+ private boolean isCactus (Material material ) {
605
+ return material .getKey ().getKey ().equalsIgnoreCase (CACTUS_STR )
606
+ || material .getKey ().getKey ().equalsIgnoreCase (CACTUS_FLOWER_STR );
632
607
}
633
608
634
609
private boolean isChorusBranch (Material blockType ) {
@@ -639,43 +614,22 @@ private boolean isChorusTree(Material blockType) {
639
614
return blockType == Material .CHORUS_PLANT || blockType == Material .CHORUS_FLOWER ;
640
615
}
641
616
642
- /**
643
- * Grabs blocks upwards from a target block
644
- * A lot of Plants/Crops in Herbalism only break vertically from a broken block
645
- * The vertical search returns early if it runs into anything that is not a multi-block plant
646
- * Multi-block plants are hard-coded and kept in {@link MaterialMapStore}
647
- *
648
- * @param originBlock The point of the "break"
649
- * @param inclusive Whether to include the origin block
650
- * @param below Whether to search down instead of up.
651
- * @return A set of blocks above the target block which can be assumed to be broken
652
- */
653
- private HashSet <Block > getBlocksBrokenAboveOrBelow (BlockState originBlock , boolean inclusive , boolean below ) {
654
- HashSet <Block > brokenBlocks = new HashSet <>();
655
- Block block = originBlock .getBlock ();
656
-
657
- //Add the initial block to the set
658
- if (inclusive )
659
- brokenBlocks .add (block );
660
-
617
+ private void addBlocksBrokenAboveOrBelow (Block originBlock , Set <Block > brokenBlocks , boolean below ) {
661
618
//Limit our search
662
619
int maxHeight = 512 ;
663
620
664
621
final BlockFace relativeFace = below ? BlockFace .DOWN : BlockFace .UP ;
665
622
666
623
// Search vertically for multi-block plants, exit early if any non-multi block plants
667
624
for (int y = 0 ; y < maxHeight ; y ++) {
668
- //TODO: Should this grab state? It would be more expensive..
669
- Block relativeBlock = block .getRelative (relativeFace , y );
625
+ final Block relativeBlock = originBlock .getRelative (relativeFace , y );
670
626
671
627
//Abandon our search if the block isn't multi
672
628
if (isOneBlockPlant (relativeBlock .getType ()))
673
629
break ;
674
630
675
631
brokenBlocks .add (relativeBlock );
676
632
}
677
-
678
- return brokenBlocks ;
679
633
}
680
634
681
635
/**
0 commit comments