mirror of
				https://github.com/mcMMO-Dev/mcMMO.git
				synced 2025-10-31 09:13:43 +01:00 
			
		
		
		
	Immature crop replanting, green thumb tweaks, replant accidental break
protection
This commit is contained in:
		| @@ -1,4 +1,6 @@ | |||||||
| Version 2.1.115 | Version 2.1.115 | ||||||
|  |     Hoes no longer give free replants | ||||||
|  |     There is now a feature in place to prevent breaking a newly automatically replanted (via green thumb) crop from being breakable for a few seconds after it appears | ||||||
|     Using a hoe on non-fully grown crops will replant them as a convenience feature for those who can't bother to wait for all of their plants to grow (put away the hoe to break non-fully grown crops) |     Using a hoe on non-fully grown crops will replant them as a convenience feature for those who can't bother to wait for all of their plants to grow (put away the hoe to break non-fully grown crops) | ||||||
|     Fixed a bug where Salvage always gave the best results |     Fixed a bug where Salvage always gave the best results | ||||||
|     Fixed an issue with arrows causing exceptions with players not yet having data loaded |     Fixed an issue with arrows causing exceptions with players not yet having data loaded | ||||||
|   | |||||||
| @@ -12,4 +12,5 @@ public class OldName extends FixedMetadataValue { | |||||||
|     { |     { | ||||||
|         super(plugin, oldName); |         super(plugin, oldName); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,17 @@ | |||||||
|  | package com.gmail.nossr50.datatypes.meta; | ||||||
|  |  | ||||||
|  | import org.bukkit.metadata.FixedMetadataValue; | ||||||
|  | import org.bukkit.plugin.Plugin; | ||||||
|  |  | ||||||
|  | public class RecentlyReplantedCropMeta extends FixedMetadataValue { | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Initializes a FixedMetadataValue with an Object | ||||||
|  |      * | ||||||
|  |      * @param owningPlugin the {@link Plugin} that created this metadata value | ||||||
|  |      */ | ||||||
|  |     public RecentlyReplantedCropMeta(Plugin owningPlugin) { | ||||||
|  |         super(owningPlugin, true); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -107,6 +107,7 @@ public class mcMMO extends JavaPlugin { | |||||||
|     private static boolean isRetroModeEnabled; |     private static boolean isRetroModeEnabled; | ||||||
|  |  | ||||||
|     /* Metadata Values */ |     /* Metadata Values */ | ||||||
|  |     public final static String REPLANT_META_KEY = "mcMMO: Recently Replanted"; | ||||||
|     public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; |     public static final String FISH_HOOK_REF_METAKEY = "mcMMO: Fish Hook Tracker"; | ||||||
|     public static final String DODGE_TRACKER        = "mcMMO: Dodge Tracker"; |     public static final String DODGE_TRACKER        = "mcMMO: Dodge Tracker"; | ||||||
|     public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage"; |     public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage"; | ||||||
|   | |||||||
| @@ -0,0 +1,90 @@ | |||||||
|  | package com.gmail.nossr50.runnables.skills; | ||||||
|  |  | ||||||
|  | import com.gmail.nossr50.mcMMO; | ||||||
|  | import com.gmail.nossr50.util.skills.ParticleEffectUtils; | ||||||
|  | import org.bukkit.Location; | ||||||
|  | import org.bukkit.Material; | ||||||
|  | import org.bukkit.block.Block; | ||||||
|  | import org.bukkit.block.BlockState; | ||||||
|  | import org.bukkit.block.data.Ageable; | ||||||
|  | import org.bukkit.event.block.BlockBreakEvent; | ||||||
|  | import org.bukkit.scheduler.BukkitRunnable; | ||||||
|  |  | ||||||
|  | public class DelayedCropReplant extends BukkitRunnable { | ||||||
|  |  | ||||||
|  |     private final int desiredCropAge; | ||||||
|  |     private final Location cropLocation; | ||||||
|  |     private final Material cropMaterial; | ||||||
|  |     private boolean wasImmaturePlant; | ||||||
|  |     private final BlockBreakEvent blockBreakEvent; | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Replants a crop after a delay setting the age to desiredCropAge | ||||||
|  |      * @param cropState target {@link BlockState} | ||||||
|  |      * @param desiredCropAge desired age of the crop | ||||||
|  |      */ | ||||||
|  |     public DelayedCropReplant(BlockBreakEvent blockBreakEvent, BlockState cropState, int desiredCropAge, boolean wasImmaturePlant) { | ||||||
|  |         //The plant was either immature or something cancelled the event, therefor we need to treat it differently | ||||||
|  |         this.blockBreakEvent = blockBreakEvent; | ||||||
|  |         this.wasImmaturePlant = wasImmaturePlant; | ||||||
|  |         this.cropMaterial = cropState.getType(); | ||||||
|  |         this.desiredCropAge = desiredCropAge; | ||||||
|  |         this.cropLocation = cropState.getLocation(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @Override | ||||||
|  |     public void run() { | ||||||
|  |         Block cropBlock = cropLocation.getBlock(); | ||||||
|  |         BlockState currentState = cropBlock.getState(); | ||||||
|  |  | ||||||
|  |         if(blockBreakEvent.isCancelled()) { | ||||||
|  |             wasImmaturePlant = true; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         //Two kinds of air in Minecraft | ||||||
|  |         if(currentState.getType().equals(Material.AIR) || currentState.getType().equals(Material.CAVE_AIR)) { | ||||||
|  |             //The space is not currently occupied by a block so we can fill it | ||||||
|  |             cropBlock.setType(cropMaterial); | ||||||
|  |  | ||||||
|  |             //Get new state (necessary?) | ||||||
|  |             BlockState newState = cropBlock.getState(); | ||||||
|  |             newState.setType(cropMaterial); | ||||||
|  |             newState.update(); | ||||||
|  |             Ageable ageable = (Ageable) newState.getBlockData(); | ||||||
|  |  | ||||||
|  |             //Crop age should always be 0 if the plant was immature | ||||||
|  |             if(wasImmaturePlant) { | ||||||
|  |                 ageable.setAge(0); | ||||||
|  |             } else { | ||||||
|  |                 //Otherwise make the plant the desired age | ||||||
|  |                 ageable.setAge(desiredCropAge); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             //Age the crop | ||||||
|  |             newState.setBlockData(ageable); | ||||||
|  |  | ||||||
|  |             //Play an effect | ||||||
|  |             ParticleEffectUtils.playGreenThumbEffect(cropLocation); | ||||||
|  |  | ||||||
|  |             //Remove the metadata marking the block as recently replanted | ||||||
|  |             new removePlantMeta(blockBreakEvent.getBlock().getLocation()).runTaskLater(mcMMO.p, 20); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private class removePlantMeta extends BukkitRunnable { | ||||||
|  |  | ||||||
|  |         private final Location cropLoc; | ||||||
|  |  | ||||||
|  |         public removePlantMeta(Location cropLoc) { | ||||||
|  |             this.cropLoc = cropLoc; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         @Override | ||||||
|  |         public void run() { | ||||||
|  |             Block cropBlock = cropLoc.getBlock(); | ||||||
|  |             cropBlock.removeMetadata(mcMMO.REPLANT_META_KEY, mcMMO.p); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -7,6 +7,7 @@ import com.gmail.nossr50.datatypes.BlockSnapshot; | |||||||
| import com.gmail.nossr50.datatypes.experience.XPGainReason; | import com.gmail.nossr50.datatypes.experience.XPGainReason; | ||||||
| import com.gmail.nossr50.datatypes.experience.XPGainSource; | import com.gmail.nossr50.datatypes.experience.XPGainSource; | ||||||
| import com.gmail.nossr50.datatypes.interactions.NotificationType; | import com.gmail.nossr50.datatypes.interactions.NotificationType; | ||||||
|  | import com.gmail.nossr50.datatypes.meta.RecentlyReplantedCropMeta; | ||||||
| import com.gmail.nossr50.datatypes.player.McMMOPlayer; | import com.gmail.nossr50.datatypes.player.McMMOPlayer; | ||||||
| import com.gmail.nossr50.datatypes.skills.PrimarySkillType; | import com.gmail.nossr50.datatypes.skills.PrimarySkillType; | ||||||
| import com.gmail.nossr50.datatypes.skills.SubSkillType; | import com.gmail.nossr50.datatypes.skills.SubSkillType; | ||||||
| @@ -14,6 +15,7 @@ import com.gmail.nossr50.datatypes.skills.SuperAbilityType; | |||||||
| import com.gmail.nossr50.datatypes.skills.ToolType; | import com.gmail.nossr50.datatypes.skills.ToolType; | ||||||
| import com.gmail.nossr50.datatypes.treasure.HylianTreasure; | import com.gmail.nossr50.datatypes.treasure.HylianTreasure; | ||||||
| import com.gmail.nossr50.mcMMO; | import com.gmail.nossr50.mcMMO; | ||||||
|  | import com.gmail.nossr50.runnables.skills.DelayedCropReplant; | ||||||
| import com.gmail.nossr50.runnables.skills.DelayedHerbalismXPCheckTask; | import com.gmail.nossr50.runnables.skills.DelayedHerbalismXPCheckTask; | ||||||
| import com.gmail.nossr50.runnables.skills.HerbalismBlockUpdaterTask; | import com.gmail.nossr50.runnables.skills.HerbalismBlockUpdaterTask; | ||||||
| import com.gmail.nossr50.skills.SkillManager; | import com.gmail.nossr50.skills.SkillManager; | ||||||
| @@ -158,6 +160,13 @@ public class HerbalismManager extends SkillManager { | |||||||
|     private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet<Block> brokenPlants) { |     private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet<Block> brokenPlants) { | ||||||
|         BlockState originalBreak = blockBreakEvent.getBlock().getState(); |         BlockState originalBreak = blockBreakEvent.getBlock().getState(); | ||||||
|  |  | ||||||
|  |         //Check if the plant was recently replanted | ||||||
|  |         if(blockBreakEvent.getBlock().getMetadata(mcMMO.REPLANT_META_KEY).size() >= 1) { | ||||||
|  |             //Crop is recently replanted to back out of destroying it | ||||||
|  |             blockBreakEvent.setCancelled(true); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         //TODO: The design of Green Terra needs to change, this is a mess |         //TODO: The design of Green Terra needs to change, this is a mess | ||||||
|         if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { |         if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) { | ||||||
|             processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); |             processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive()); | ||||||
| @@ -639,6 +648,18 @@ public class HerbalismManager extends SkillManager { | |||||||
|         return Herbalism.convertShroomThumb(blockState); |         return Herbalism.convertShroomThumb(blockState); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Starts the delayed replant task and turns | ||||||
|  |      * @param desiredCropAge the desired age of the crop | ||||||
|  |      * @param blockBreakEvent the {@link BlockBreakEvent} this crop was involved in | ||||||
|  |      * @param cropState the {@link BlockState} of the crop | ||||||
|  |      */ | ||||||
|  |     private void startReplantTask(int desiredCropAge, BlockBreakEvent blockBreakEvent, BlockState cropState, boolean isImmature) { | ||||||
|  |         //Mark the plant as recently replanted to avoid accidental breakage | ||||||
|  |         blockBreakEvent.getBlock().setMetadata(mcMMO.REPLANT_META_KEY, new RecentlyReplantedCropMeta(mcMMO.p)); | ||||||
|  |         new DelayedCropReplant(blockBreakEvent, cropState, desiredCropAge, isImmature).runTaskLater(mcMMO.p, 20 * 2); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * Process the Green Thumb ability for plants. |      * Process the Green Thumb ability for plants. | ||||||
|      * |      * | ||||||
| @@ -651,12 +672,13 @@ public class HerbalismManager extends SkillManager { | |||||||
|         if (!(blockData instanceof Ageable)) |         if (!(blockData instanceof Ageable)) | ||||||
|             return; |             return; | ||||||
|  |  | ||||||
|  |         Ageable ageable = (Ageable) blockData; | ||||||
|  |  | ||||||
|         //If the ageable is NOT mature and the player is NOT using a hoe, abort |         //If the ageable is NOT mature and the player is NOT using a hoe, abort | ||||||
|         if(!isAgeableMature((Ageable) blockData) && !ItemUtils.isHoe(getPlayer().getItemInHand())) { |         if(!isAgeableMature(ageable) && !ItemUtils.isHoe(getPlayer().getItemInHand())) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |  | ||||||
|         Player player = getPlayer(); |         Player player = getPlayer(); | ||||||
|         PlayerInventory playerInventory = player.getInventory(); |         PlayerInventory playerInventory = player.getInventory(); | ||||||
|         Material seed = null; |         Material seed = null; | ||||||
| @@ -696,31 +718,36 @@ public class HerbalismManager extends SkillManager { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if (!processGrowingPlants(blockState, blockBreakEvent, greenTerra)) { |  | ||||||
|  |         if (!playerInventory.containsAtLeast(seedStack, 1)) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         if(!ItemUtils.isHoe(getPlayer().getInventory().getItemInMainHand())) |         if (!processGrowingPlants(blockState, ageable, blockBreakEvent, greenTerra)) { | ||||||
|         { |  | ||||||
|             if (!playerInventory.containsAtLeast(seedStack, 1)) { |  | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         playerInventory.removeItem(seedStack); |         playerInventory.removeItem(seedStack); | ||||||
|         player.updateInventory(); // Needed until replacement available |         player.updateInventory(); // Needed until replacement available | ||||||
|         } |  | ||||||
|  |  | ||||||
|         new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0); |         new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     private boolean processGrowingPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) { |     private boolean processGrowingPlants(BlockState blockState, Ageable ageable, BlockBreakEvent blockBreakEvent, boolean greenTerra) { | ||||||
|         Ageable crops = (Ageable) blockState.getBlockData(); |         //This check is needed | ||||||
|  |         if(isBizarreAgeable(ageable)) { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         int finalAge = 0; | ||||||
|         int greenThumbStage = getGreenThumbStage(); |         int greenThumbStage = getGreenThumbStage(); | ||||||
|  |  | ||||||
|         //Immature plants will start over at 0 |         //Immature plants will start over at 0 | ||||||
|         if(!isAgeableMature(crops)) { |         if(!isAgeableMature(ageable)) { | ||||||
|             crops.setAge(0); |  | ||||||
|             blockBreakEvent.setCancelled(true); |             blockBreakEvent.setCancelled(true); | ||||||
|  |             startReplantTask(0, blockBreakEvent, blockState, true); | ||||||
|  |             blockState.setType(Material.AIR); | ||||||
|  |             blockState.update(); | ||||||
|             return true; |             return true; | ||||||
|         } |         } | ||||||
|  |  | ||||||
| @@ -733,10 +760,10 @@ public class HerbalismManager extends SkillManager { | |||||||
|             case WHEAT: |             case WHEAT: | ||||||
|  |  | ||||||
|                 if (greenTerra) { |                 if (greenTerra) { | ||||||
|                     crops.setAge(3); |                     finalAge = 3; | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     crops.setAge(greenThumbStage); |                     finalAge = getGreenThumbStage(); | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
| @@ -744,30 +771,32 @@ public class HerbalismManager extends SkillManager { | |||||||
|             case NETHER_WART: |             case NETHER_WART: | ||||||
|  |  | ||||||
|                 if (greenTerra || greenThumbStage > 2) { |                 if (greenTerra || greenThumbStage > 2) { | ||||||
|                     crops.setAge(2); |                     finalAge = 2; | ||||||
|                 } |                 } | ||||||
|                 else if (greenThumbStage == 2) { |                 else if (greenThumbStage == 2) { | ||||||
|                     crops.setAge(1); |                     finalAge = 1; | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     crops.setAge(0); |                     finalAge = 0; | ||||||
|                 } |                 } | ||||||
|                break; |                break; | ||||||
|  |  | ||||||
|             case COCOA: |             case COCOA: | ||||||
|  |  | ||||||
|                 if (greenTerra || getGreenThumbStage() > 1) { |                 if (greenTerra || getGreenThumbStage() > 1) { | ||||||
|                     crops.setAge(1); |                     finalAge = 1; | ||||||
|                 } |                 } | ||||||
|                 else { |                 else { | ||||||
|                     crops.setAge(0); |                     finalAge = 0; | ||||||
|                 } |                 } | ||||||
|                 break; |                 break; | ||||||
|  |  | ||||||
|             default: |             default: | ||||||
|                 return false; |                 return false; | ||||||
|         } |         } | ||||||
|         blockState.setBlockData(crops); |  | ||||||
|  |         //Start the delayed replant | ||||||
|  |         startReplantTask(finalAge, blockBreakEvent, blockState, false); | ||||||
|         return true; |         return true; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| package com.gmail.nossr50.util.skills; | package com.gmail.nossr50.util.skills; | ||||||
|  |  | ||||||
| import com.gmail.nossr50.config.Config; | import com.gmail.nossr50.config.Config; | ||||||
|  | import com.gmail.nossr50.util.sounds.SoundManager; | ||||||
|  | import com.gmail.nossr50.util.sounds.SoundType; | ||||||
| import org.bukkit.Effect; | import org.bukkit.Effect; | ||||||
| import org.bukkit.Location; | import org.bukkit.Location; | ||||||
| import org.bukkit.Material; | import org.bukkit.Material; | ||||||
| @@ -14,6 +16,12 @@ public final class ParticleEffectUtils { | |||||||
|  |  | ||||||
|     private ParticleEffectUtils() {}; |     private ParticleEffectUtils() {}; | ||||||
|  |  | ||||||
|  |     public static void playGreenThumbEffect(Location location) { | ||||||
|  |         World world = location.getWorld(); | ||||||
|  |         playSmokeEffect(location); | ||||||
|  |         SoundManager.worldSendSoundMaxPitch(world, location, SoundType.POP); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static void playBleedEffect(LivingEntity livingEntity) { |     public static void playBleedEffect(LivingEntity livingEntity) { | ||||||
|         if (!Config.getInstance().getBleedEffectEnabled()) { |         if (!Config.getInstance().getBleedEffectEnabled()) { | ||||||
|             return; |             return; | ||||||
| @@ -27,7 +35,7 @@ public final class ParticleEffectUtils { | |||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         playSmokeEffect(player); |         playSmokeEffect(player.getLocation()); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static void playFluxEffect(Location location) { |     public static void playFluxEffect(Location location) { | ||||||
| @@ -38,9 +46,8 @@ public final class ParticleEffectUtils { | |||||||
|         location.getWorld().playEffect(location, Effect.MOBSPAWNER_FLAMES, 1); |         location.getWorld().playEffect(location, Effect.MOBSPAWNER_FLAMES, 1); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     public static void playSmokeEffect(LivingEntity livingEntity) { |     public static void playSmokeEffect(Location location) { | ||||||
|         Location location = livingEntity.getEyeLocation(); |         World world = location.getWorld(); | ||||||
|         World world = livingEntity.getWorld(); |  | ||||||
|  |  | ||||||
|         // Have to do it this way, because not all block directions are valid for smoke |         // Have to do it this way, because not all block directions are valid for smoke | ||||||
|         world.playEffect(location, Effect.SMOKE, BlockFace.SOUTH_EAST); |         world.playEffect(location, Effect.SMOKE, BlockFace.SOUTH_EAST); | ||||||
|   | |||||||
| @@ -39,6 +39,11 @@ public class SoundManager { | |||||||
|             world.playSound(location, getSound(soundType), getVolume(soundType), getPitch(soundType)); |             world.playSound(location, getSound(soundType), getVolume(soundType), getPitch(soundType)); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static void worldSendSoundMaxPitch(World world, Location location, SoundType soundType) { | ||||||
|  |         if(SoundConfig.getInstance().getIsEnabled(soundType)) | ||||||
|  |             world.playSound(location, getSound(soundType), getVolume(soundType), 2.0F); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     /** |     /** | ||||||
|      * All volume is multiplied by the master volume to get its final value |      * All volume is multiplied by the master volume to get its final value | ||||||
|      * @param soundType target soundtype |      * @param soundType target soundtype | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 nossr50
					nossr50