Immature crop replanting, green thumb tweaks, replant accidental break

protection
This commit is contained in:
nossr50 2020-02-19 15:58:53 -08:00
parent 8f26544188
commit e2073ff9f7
8 changed files with 179 additions and 27 deletions

View File

@ -1,4 +1,6 @@
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)
Fixed a bug where Salvage always gave the best results
Fixed an issue with arrows causing exceptions with players not yet having data loaded

View File

@ -12,4 +12,5 @@ public class OldName extends FixedMetadataValue {
{
super(plugin, oldName);
}
}

View File

@ -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);
}
}

View File

@ -107,6 +107,7 @@ public class mcMMO extends JavaPlugin {
private static boolean isRetroModeEnabled;
/* 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 DODGE_TRACKER = "mcMMO: Dodge Tracker";
public static final String CUSTOM_DAMAGE_METAKEY = "mcMMO: Custom Damage";

View File

@ -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);
}
}
}

View File

@ -7,6 +7,7 @@ import com.gmail.nossr50.datatypes.BlockSnapshot;
import com.gmail.nossr50.datatypes.experience.XPGainReason;
import com.gmail.nossr50.datatypes.experience.XPGainSource;
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.skills.PrimarySkillType;
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.treasure.HylianTreasure;
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.HerbalismBlockUpdaterTask;
import com.gmail.nossr50.skills.SkillManager;
@ -158,6 +160,13 @@ public class HerbalismManager extends SkillManager {
private void processHerbalismOnBlocksBroken(BlockBreakEvent blockBreakEvent, HashSet<Block> brokenPlants) {
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
if(Permissions.greenThumbPlant(getPlayer(), originalBreak.getType())) {
processGreenThumbPlants(originalBreak, blockBreakEvent, isGreenTerraActive());
@ -639,6 +648,18 @@ public class HerbalismManager extends SkillManager {
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.
*
@ -651,12 +672,13 @@ public class HerbalismManager extends SkillManager {
if (!(blockData instanceof Ageable))
return;
Ageable ageable = (Ageable) blockData;
//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;
}
Player player = getPlayer();
PlayerInventory playerInventory = player.getInventory();
Material seed = null;
@ -696,31 +718,36 @@ public class HerbalismManager extends SkillManager {
return;
}
if (!processGrowingPlants(blockState, blockBreakEvent, greenTerra)) {
if (!playerInventory.containsAtLeast(seedStack, 1)) {
return;
}
if(!ItemUtils.isHoe(getPlayer().getInventory().getItemInMainHand()))
{
if (!playerInventory.containsAtLeast(seedStack, 1)) {
return;
}
playerInventory.removeItem(seedStack);
player.updateInventory(); // Needed until replacement available
if (!processGrowingPlants(blockState, ageable, blockBreakEvent, greenTerra)) {
return;
}
playerInventory.removeItem(seedStack);
player.updateInventory(); // Needed until replacement available
new HerbalismBlockUpdaterTask(blockState).runTaskLater(mcMMO.p, 0);
}
private boolean processGrowingPlants(BlockState blockState, BlockBreakEvent blockBreakEvent, boolean greenTerra) {
Ageable crops = (Ageable) blockState.getBlockData();
private boolean processGrowingPlants(BlockState blockState, Ageable ageable, BlockBreakEvent blockBreakEvent, boolean greenTerra) {
//This check is needed
if(isBizarreAgeable(ageable)) {
return false;
}
int finalAge = 0;
int greenThumbStage = getGreenThumbStage();
//Immature plants will start over at 0
if(!isAgeableMature(crops)) {
crops.setAge(0);
if(!isAgeableMature(ageable)) {
blockBreakEvent.setCancelled(true);
startReplantTask(0, blockBreakEvent, blockState, true);
blockState.setType(Material.AIR);
blockState.update();
return true;
}
@ -733,10 +760,10 @@ public class HerbalismManager extends SkillManager {
case WHEAT:
if (greenTerra) {
crops.setAge(3);
finalAge = 3;
}
else {
crops.setAge(greenThumbStage);
finalAge = getGreenThumbStage();
}
break;
@ -744,30 +771,32 @@ public class HerbalismManager extends SkillManager {
case NETHER_WART:
if (greenTerra || greenThumbStage > 2) {
crops.setAge(2);
finalAge = 2;
}
else if (greenThumbStage == 2) {
crops.setAge(1);
finalAge = 1;
}
else {
crops.setAge(0);
finalAge = 0;
}
break;
case COCOA:
if (greenTerra || getGreenThumbStage() > 1) {
crops.setAge(1);
finalAge = 1;
}
else {
crops.setAge(0);
finalAge = 0;
}
break;
default:
return false;
}
blockState.setBlockData(crops);
//Start the delayed replant
startReplantTask(finalAge, blockBreakEvent, blockState, false);
return true;
}

View File

@ -1,6 +1,8 @@
package com.gmail.nossr50.util.skills;
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.Location;
import org.bukkit.Material;
@ -14,6 +16,12 @@ public final class 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) {
if (!Config.getInstance().getBleedEffectEnabled()) {
return;
@ -27,7 +35,7 @@ public final class ParticleEffectUtils {
return;
}
playSmokeEffect(player);
playSmokeEffect(player.getLocation());
}
public static void playFluxEffect(Location location) {
@ -38,9 +46,8 @@ public final class ParticleEffectUtils {
location.getWorld().playEffect(location, Effect.MOBSPAWNER_FLAMES, 1);
}
public static void playSmokeEffect(LivingEntity livingEntity) {
Location location = livingEntity.getEyeLocation();
World world = livingEntity.getWorld();
public static void playSmokeEffect(Location location) {
World world = location.getWorld();
// Have to do it this way, because not all block directions are valid for smoke
world.playEffect(location, Effect.SMOKE, BlockFace.SOUTH_EAST);

View File

@ -39,6 +39,11 @@ public class SoundManager {
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
* @param soundType target soundtype