From c6652372f61d5df6a42e974a3b6135eb5a30071a Mon Sep 17 00:00:00 2001 From: XiaoMoMi <972454774@qq.com> Date: Sat, 16 Mar 2024 11:17:01 +0800 Subject: [PATCH] 3.4.2.0 --- .../api/event/BoneMealDispenseEvent.java | 111 ++++++++ .../api/event/BoneMealUseEvent.java | 111 ++++++++ .../customcrops/api/event/CropBreakEvent.java | 11 +- .../api/event/FertilizerUseEvent.java | 96 +++++++ .../api/event/GreenhouseGlassBreakEvent.java | 44 ++- .../customcrops/api/event/PotBreakEvent.java | 24 +- .../api/event/ScarecrowBreakEvent.java | 44 ++- .../api/event/SprinklerBreakEvent.java | 35 ++- .../api/event/SprinklerPlaceEvent.java | 7 +- .../api/event/WateringCanFillEvent.java | 2 +- .../api/event/WateringCanWaterEvent.java | 16 +- .../api/integration/SeasonInterface.java | 16 ++ .../api/manager/IntegrationManager.java | 3 - .../api/mechanic/item/BoneMeal.java | 16 +- .../customcrops/api/mechanic/misc/Reason.java | 29 ++ .../mechanic/world/level/WorldSetting.java | 2 +- build.gradle.kts | 2 +- .../compatibility/IntegrationManagerImpl.java | 6 - .../season/AdvancedSeasonsImpl.java | 16 ++ .../compatibility/season/InBuiltSeason.java | 19 ++ .../season/RealisticSeasonsImpl.java | 28 +- .../customcrops/manager/CommandManager.java | 75 +++-- .../manager/ConfigManagerImpl.java | 2 +- .../mechanic/action/ActionManagerImpl.java | 7 +- .../mechanic/item/ItemManagerImpl.java | 266 +++++++++++++++--- .../item/custom/AbstractCustomListener.java | 71 ++++- .../requirement/RequirementManagerImpl.java | 23 ++ .../customcrops/mechanic/world/CChunk.java | 4 +- .../customcrops/mechanic/world/CWorld.java | 6 +- .../customcrops/utils/ConfigUtils.java | 1 + .../main/resources/contents/crops/default.yml | 2 + 31 files changed, 953 insertions(+), 142 deletions(-) create mode 100644 api/src/main/java/net/momirealms/customcrops/api/event/BoneMealDispenseEvent.java create mode 100644 api/src/main/java/net/momirealms/customcrops/api/event/BoneMealUseEvent.java create mode 100644 api/src/main/java/net/momirealms/customcrops/api/event/FertilizerUseEvent.java create mode 100644 api/src/main/java/net/momirealms/customcrops/api/mechanic/misc/Reason.java diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealDispenseEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealDispenseEvent.java new file mode 100644 index 0000000..786efa3 --- /dev/null +++ b/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealDispenseEvent.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) <2022> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.momirealms.customcrops.api.event; + +import net.momirealms.customcrops.api.mechanic.item.BoneMeal; +import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * An event that triggered when a player interacts a crop with a bone meal + */ +public class BoneMealDispenseEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Location location; + private final BoneMeal boneMeal; + private final WorldCrop crop; + private final ItemStack boneMealItem; + private final Block dispenser; + + public BoneMealDispenseEvent( + @NotNull Block dispenser, + @NotNull ItemStack boneMealItem, + @NotNull Location location, + @NotNull BoneMeal boneMeal, + @NotNull WorldCrop crop + ) { + this.location = location; + this.crop = crop; + this.boneMeal = boneMeal; + this.boneMealItem = boneMealItem; + this.dispenser = dispenser; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return getHandlerList(); + } + + /** + * Get the crop location + * @return location + */ + @NotNull + public Location getLocation() { + return location; + } + + /** + * Get the item in player's hand + * If there's nothing in hand, it would return AIR + * @return item in hand + */ + @NotNull + public ItemStack getBoneMealItem() { + return boneMealItem; + } + + @NotNull + public WorldCrop getCrop() { + return crop; + } + + @NotNull + public BoneMeal getBoneMeal() { + return boneMeal; + } + + @NotNull + public Block getDispenser() { + return dispenser; + } +} diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealUseEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealUseEvent.java new file mode 100644 index 0000000..2c0e4ef --- /dev/null +++ b/api/src/main/java/net/momirealms/customcrops/api/event/BoneMealUseEvent.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) <2022> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.momirealms.customcrops.api.event; + +import net.momirealms.customcrops.api.mechanic.item.BoneMeal; +import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * An event that triggered when a player interacts a crop with a bone meal + */ +public class BoneMealUseEvent extends Event implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final Location location; + private final BoneMeal boneMeal; + private final WorldCrop crop; + private final ItemStack itemInHand; + private final Player player; + + public BoneMealUseEvent( + @NotNull Player player, + @NotNull ItemStack itemInHand, + @NotNull Location location, + @NotNull BoneMeal boneMeal, + @NotNull WorldCrop crop + ) { + this.location = location; + this.crop = crop; + this.boneMeal = boneMeal; + this.itemInHand = itemInHand; + this.player = player; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + this.cancelled = cancel; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + + @NotNull + @Override + public HandlerList getHandlers() { + return getHandlerList(); + } + + /** + * Get the crop location + * @return location + */ + @NotNull + public Location getLocation() { + return location; + } + + /** + * Get the item in player's hand + * If there's nothing in hand, it would return AIR + * @return item in hand + */ + @NotNull + public ItemStack getItemInHand() { + return itemInHand; + } + + @NotNull + public WorldCrop getCrop() { + return crop; + } + + @NotNull + public BoneMeal getBoneMeal() { + return boneMeal; + } + + @NotNull + public Player getPlayer() { + return player; + } +} diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java index 40a9a90..80791f5 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/CropBreakEvent.java @@ -17,6 +17,7 @@ package net.momirealms.customcrops.api.event; +import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -37,15 +38,18 @@ public class CropBreakEvent extends Event implements Cancellable { private final Location location; private final WorldCrop worldCrop; private final Entity entity; + private final Reason reason; public CropBreakEvent( @Nullable Entity entity, @NotNull Location location, - @Nullable WorldCrop worldCrop + @NotNull WorldCrop worldCrop, + @NotNull Reason reason ) { this.entity = entity; this.location = location; this.worldCrop = worldCrop; + this.reason = reason; } @Override @@ -99,4 +103,9 @@ public class CropBreakEvent extends Event implements Cancellable { } return null; } + + @NotNull + public Reason getReason() { + return reason; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/FertilizerUseEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/FertilizerUseEvent.java new file mode 100644 index 0000000..2154799 --- /dev/null +++ b/api/src/main/java/net/momirealms/customcrops/api/event/FertilizerUseEvent.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) <2022> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.momirealms.customcrops.api.event; + +import net.momirealms.customcrops.api.mechanic.item.Fertilizer; +import net.momirealms.customcrops.api.mechanic.world.level.WorldPot; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.Cancellable; +import org.bukkit.event.HandlerList; +import org.bukkit.event.player.PlayerEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +/** + * An event that triggered when player tries adding fertilizer to pot + */ +public class FertilizerUseEvent extends PlayerEvent implements Cancellable { + + private static final HandlerList handlers = new HandlerList(); + private boolean cancelled; + private final ItemStack itemInHand; + private final Location location; + private final WorldPot pot; + private final Fertilizer fertilizer; + + public FertilizerUseEvent( + @NotNull Player player, + @NotNull ItemStack itemInHand, + @NotNull Fertilizer fertilizer, + @NotNull Location location, + @NotNull WorldPot pot + ) { + super(player); + this.cancelled = false; + this.itemInHand = itemInHand; + this.fertilizer = fertilizer; + this.location = location; + this.pot = pot; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + @Override + public @NotNull HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } + + @NotNull + public ItemStack getItemInHand() { + return itemInHand; + } + + @NotNull + public Location getLocation() { + return location; + } + + @NotNull + public WorldPot getPot() { + return pot; + } + + @NotNull + public Fertilizer getFertilizer() { + return fertilizer; + } +} diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/GreenhouseGlassBreakEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/GreenhouseGlassBreakEvent.java index 5a4254a..1423b54 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/GreenhouseGlassBreakEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/GreenhouseGlassBreakEvent.java @@ -17,28 +17,39 @@ package net.momirealms.customcrops.api.event; +import net.momirealms.customcrops.api.mechanic.misc.Reason; +import net.momirealms.customcrops.api.mechanic.world.level.WorldGlass; import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * An event that triggered when breaking greenhouse glass */ -public class GreenhouseGlassBreakEvent extends PlayerEvent implements Cancellable { +public class GreenhouseGlassBreakEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private boolean cancelled; private final Location location; + private final Entity entity; + private final Reason reason; + private final WorldGlass glass; public GreenhouseGlassBreakEvent( - @NotNull Player who, - @NotNull Location location + @Nullable Entity entity, + @NotNull Location location, + @NotNull WorldGlass glass, + @NotNull Reason reason ) { - super(who); + this.entity = entity; this.location = location; + this.reason = reason; + this.glass = glass; } @Override @@ -70,4 +81,27 @@ public class GreenhouseGlassBreakEvent extends PlayerEvent implements Cancellabl public Location getLocation() { return location; } + + @Nullable + public Entity getEntity() { + return entity; + } + + @Nullable + public Player getPlayer() { + if (entity instanceof Player player) { + return player; + } + return null; + } + + @NotNull + public Reason getReason() { + return reason; + } + + @NotNull + public WorldGlass getGlass() { + return glass; + } } \ No newline at end of file diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/PotBreakEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/PotBreakEvent.java index 8815520..a0ea77b 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/PotBreakEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/PotBreakEvent.java @@ -17,9 +17,11 @@ package net.momirealms.customcrops.api.event; +import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.world.level.WorldPot; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; @@ -36,15 +38,18 @@ public class PotBreakEvent extends Event implements Cancellable { private final Location location; private final WorldPot pot; private final Entity entity; + private final Reason reason; public PotBreakEvent( @Nullable Entity entity, @NotNull Location location, - @NotNull WorldPot pot + @NotNull WorldPot pot, + @NotNull Reason reason ) { this.entity = entity; this.location = location; this.pot = pot; + this.reason = reason; } @Override @@ -87,12 +92,21 @@ public class PotBreakEvent extends Event implements Cancellable { return pot; } - /** - * It would be null if the event is not triggered by an entity - * @return entity - */ @Nullable public Entity getEntity() { return entity; } + + @Nullable + public Player getPlayer() { + if (entity instanceof Player player) { + return player; + } + return null; + } + + @NotNull + public Reason getReason() { + return reason; + } } \ No newline at end of file diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/ScarecrowBreakEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/ScarecrowBreakEvent.java index 1e64a32..57e412d 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/ScarecrowBreakEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/ScarecrowBreakEvent.java @@ -17,28 +17,39 @@ package net.momirealms.customcrops.api.event; +import net.momirealms.customcrops.api.mechanic.misc.Reason; +import net.momirealms.customcrops.api.mechanic.world.level.WorldScarecrow; import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * An event that triggered when breaking a scarecrow */ -public class ScarecrowBreakEvent extends PlayerEvent implements Cancellable { +public class ScarecrowBreakEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private boolean cancelled; private final Location location; + private final Entity entity; + private final Reason reason; + private final WorldScarecrow scarecrow; public ScarecrowBreakEvent( - @NotNull Player who, - @NotNull Location location + @Nullable Entity entity, + @NotNull Location location, + @NotNull WorldScarecrow scarecrow, + @NotNull Reason reason ) { - super(who); this.location = location; + this.reason = reason; + this.entity = entity; + this.scarecrow = scarecrow; } @Override @@ -70,4 +81,27 @@ public class ScarecrowBreakEvent extends PlayerEvent implements Cancellable { public Location getLocation() { return location; } + + @Nullable + public Entity getEntity() { + return entity; + } + + @Nullable + public Player getPlayer() { + if (entity instanceof Player player) { + return player; + } + return null; + } + + @NotNull + public Reason getReason() { + return reason; + } + + @NotNull + public WorldScarecrow getScarecrow() { + return scarecrow; + } } \ No newline at end of file diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerBreakEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerBreakEvent.java index a8bf779..586be8f 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerBreakEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerBreakEvent.java @@ -17,31 +17,38 @@ package net.momirealms.customcrops.api.event; +import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.world.level.WorldSprinkler; import org.bukkit.Location; +import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.bukkit.event.player.PlayerEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * An event that triggered when breaking a sprinkler */ -public class SprinklerBreakEvent extends PlayerEvent implements Cancellable { +public class SprinklerBreakEvent extends Event implements Cancellable { private static final HandlerList handlers = new HandlerList(); private boolean cancelled; private final Location location; private final WorldSprinkler sprinkler; + private final Entity entity; + private final Reason reason; public SprinklerBreakEvent( - @NotNull Player who, + @Nullable Entity entity, @NotNull Location location, - @NotNull WorldSprinkler sprinkler + @NotNull WorldSprinkler sprinkler, + @NotNull Reason reason ) { - super(who); + this.entity = entity; this.location = location; + this.reason = reason; this.sprinkler = sprinkler; } @@ -83,4 +90,22 @@ public class SprinklerBreakEvent extends PlayerEvent implements Cancellable { public WorldSprinkler getSprinkler() { return sprinkler; } + + @Nullable + public Entity getEntity() { + return entity; + } + + @Nullable + public Player getPlayer() { + if (entity instanceof Player player) { + return player; + } + return null; + } + + @NotNull + public Reason getReason() { + return reason; + } } \ No newline at end of file diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerPlaceEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerPlaceEvent.java index 547a3f6..dec4943 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerPlaceEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/SprinklerPlaceEvent.java @@ -37,7 +37,12 @@ public class SprinklerPlaceEvent extends PlayerEvent implements Cancellable { private final Location location; private final Sprinkler sprinkler; - public SprinklerPlaceEvent(@NotNull Player who, ItemStack itemInHand, Location location, Sprinkler sprinkler) { + public SprinklerPlaceEvent( + @NotNull Player who, + @NotNull ItemStack itemInHand, + @NotNull Location location, + @NotNull Sprinkler sprinkler + ) { super(who); this.itemInHand = itemInHand; this.location = location; diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanFillEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanFillEvent.java index c23bf4b..4275aee 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanFillEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanFillEvent.java @@ -42,8 +42,8 @@ public class WateringCanFillEvent extends PlayerEvent implements Cancellable { public WateringCanFillEvent( @NotNull Player player, @NotNull ItemStack itemInHand, - @NotNull WateringCan wateringCan, @NotNull Location location, + @NotNull WateringCan wateringCan, @NotNull PositiveFillMethod fillMethod ) { super(player); diff --git a/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanWaterEvent.java b/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanWaterEvent.java index f810d59..37b8e30 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanWaterEvent.java +++ b/api/src/main/java/net/momirealms/customcrops/api/event/WateringCanWaterEvent.java @@ -17,8 +17,8 @@ package net.momirealms.customcrops.api.event; -import net.momirealms.customcrops.api.common.item.KeyItem; import net.momirealms.customcrops.api.mechanic.item.WateringCan; +import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; @@ -27,6 +27,8 @@ import org.bukkit.event.player.PlayerEvent; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; +import java.util.Set; + /** * An event that triggered when player tries to use watering-can to add water to pots/sprinklers */ @@ -36,15 +38,15 @@ public class WateringCanWaterEvent extends PlayerEvent implements Cancellable { private boolean cancelled; private final ItemStack itemInHand; private final WateringCan wateringCan; - private final KeyItem potOrSprinkler; - private final Location location; + private final CustomCropsBlock potOrSprinkler; + private final Set location; public WateringCanWaterEvent( @NotNull Player player, @NotNull ItemStack itemInHand, + @NotNull Set location, @NotNull WateringCan wateringCan, - @NotNull Location location, - @NotNull KeyItem potOrSprinkler + @NotNull CustomCropsBlock potOrSprinkler ) { super(player); this.cancelled = false; @@ -85,12 +87,12 @@ public class WateringCanWaterEvent extends PlayerEvent implements Cancellable { } @NotNull - public Location getLocation() { + public Set getLocation() { return location; } @NotNull - public KeyItem getPotOrSprinkler() { + public CustomCropsBlock getPotOrSprinkler() { return potOrSprinkler; } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/integration/SeasonInterface.java b/api/src/main/java/net/momirealms/customcrops/api/integration/SeasonInterface.java index 10c4df5..9522902 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/integration/SeasonInterface.java +++ b/api/src/main/java/net/momirealms/customcrops/api/integration/SeasonInterface.java @@ -38,4 +38,20 @@ public interface SeasonInterface { * @return date */ int getDate(World world); + + /** + * Set a world's season + * + * @param world world + * @param season season + */ + void setSeason(World world, Season season); + + /** + * Set a world's date + * + * @param world world + * @param date date + */ + void setDate(World world, int date); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/manager/IntegrationManager.java b/api/src/main/java/net/momirealms/customcrops/api/manager/IntegrationManager.java index 4f33ae5..b983eb8 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/manager/IntegrationManager.java +++ b/api/src/main/java/net/momirealms/customcrops/api/manager/IntegrationManager.java @@ -22,7 +22,6 @@ import net.momirealms.customcrops.api.integration.LevelInterface; import net.momirealms.customcrops.api.integration.SeasonInterface; import net.momirealms.customcrops.api.mechanic.world.season.Season; import org.bukkit.World; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; public interface IntegrationManager extends Initable { @@ -57,6 +56,4 @@ public interface IntegrationManager extends Initable { Season getSeason(World world); int getDate(World world); - - ItemStack build(String itemID); } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/BoneMeal.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/BoneMeal.java index 2a988c2..6839679 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/BoneMeal.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/item/BoneMeal.java @@ -32,14 +32,24 @@ public class BoneMeal { private final int returnedAmount; private final List> pointGainList; private final Action[] actions; + private final boolean dispenserAllowed; - public BoneMeal(String item, int usedAmount, String returned, int returnedAmount, List> pointGainList, Action[] actions) { + public BoneMeal( + String item, + int usedAmount, + String returned, + int returnedAmount, + boolean dispenserAllowed, + List> pointGainList, + Action[] actions + ) { this.item = item; this.returned = returned; this.pointGainList = pointGainList; this.actions = actions; this.usedAmount = usedAmount; this.returnedAmount = returnedAmount; + this.dispenserAllowed = dispenserAllowed; } public String getItem() { @@ -70,4 +80,8 @@ public class BoneMeal { public int getReturnedAmount() { return returnedAmount; } + + public boolean isDispenserAllowed() { + return dispenserAllowed; + } } diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/misc/Reason.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/misc/Reason.java new file mode 100644 index 0000000..eae2386 --- /dev/null +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/misc/Reason.java @@ -0,0 +1,29 @@ +/* + * Copyright (C) <2022> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.momirealms.customcrops.api.mechanic.misc; + +public enum Reason { + // Player break + BREAK, + // Trampling + TRAMPLE, + // Block explosion and entity explosion + EXPLODE, + // Action "break" + ACTION +} diff --git a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java index 868b3b5..0ca9614 100644 --- a/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java +++ b/api/src/main/java/net/momirealms/customcrops/api/mechanic/world/level/WorldSetting.java @@ -112,7 +112,7 @@ public class WorldSetting implements Cloneable { ); } - public boolean isEnableScheduler() { + public boolean isSchedulerEnabled() { return enableScheduler; } diff --git a/build.gradle.kts b/build.gradle.kts index 42090d3..fd1a46b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -8,7 +8,7 @@ plugins { allprojects { project.group = "net.momirealms" - project.version = "3.4.1.1" + project.version = "3.4.2.0" apply() apply(plugin = "java") diff --git a/plugin/src/main/java/net/momirealms/customcrops/compatibility/IntegrationManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/compatibility/IntegrationManagerImpl.java index 0997811..7c22e21 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/compatibility/IntegrationManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/compatibility/IntegrationManagerImpl.java @@ -32,7 +32,6 @@ import net.momirealms.customcrops.compatibility.season.AdvancedSeasonsImpl; import net.momirealms.customcrops.compatibility.season.InBuiltSeason; import net.momirealms.customcrops.compatibility.season.RealisticSeasonsImpl; import org.bukkit.World; -import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; import java.util.HashMap; @@ -161,9 +160,4 @@ public class IntegrationManagerImpl implements IntegrationManager { public int getDate(World world) { return seasonInterface.getDate(world); } - - @Override - public ItemStack build(String itemID) { - return null; - } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/AdvancedSeasonsImpl.java b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/AdvancedSeasonsImpl.java index 86dc198..f46538c 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/AdvancedSeasonsImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/AdvancedSeasonsImpl.java @@ -45,4 +45,20 @@ public class AdvancedSeasonsImpl implements SeasonInterface { public int getDate(World world) { return 0; } + + @Override + public void setSeason(World world, Season season) { + String seasonName = switch (season) { + case AUTUMN -> "FALL"; + case WINTER -> "WINTER"; + case SUMMER -> "SUMMER"; + case SPRING -> "SPRING"; + }; + api.setSeason(seasonName, world); + } + + @Override + public void setDate(World world, int date) { + + } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/InBuiltSeason.java b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/InBuiltSeason.java index 91d568a..5e713f0 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/InBuiltSeason.java +++ b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/InBuiltSeason.java @@ -21,6 +21,7 @@ import net.momirealms.customcrops.api.integration.SeasonInterface; import net.momirealms.customcrops.api.manager.ConfigManager; import net.momirealms.customcrops.api.manager.WorldManager; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; +import net.momirealms.customcrops.api.mechanic.world.level.WorldInfoData; import net.momirealms.customcrops.api.mechanic.world.season.Season; import org.bukkit.World; import org.jetbrains.annotations.Nullable; @@ -52,4 +53,22 @@ public class InBuiltSeason implements SeasonInterface { .map(cropsWorld -> cropsWorld.getInfoData().getDate()) .orElse(0); } + + @Override + public void setSeason(World world, Season season) { + worldManager.getCustomCropsWorld(world) + .ifPresent(customWorld -> { + WorldInfoData infoData = customWorld.getInfoData(); + infoData.setSeason(season); + }); + } + + @Override + public void setDate(World world, int date) { + worldManager.getCustomCropsWorld(world) + .ifPresent(customWorld -> { + WorldInfoData infoData = customWorld.getInfoData(); + infoData.setDate(date); + }); + } } \ No newline at end of file diff --git a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/RealisticSeasonsImpl.java b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/RealisticSeasonsImpl.java index d722f05..9703511 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/RealisticSeasonsImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/compatibility/season/RealisticSeasonsImpl.java @@ -18,6 +18,7 @@ package net.momirealms.customcrops.compatibility.season; import me.casperge.realisticseasons.api.SeasonsAPI; +import me.casperge.realisticseasons.calendar.Date; import net.momirealms.customcrops.api.integration.SeasonInterface; import net.momirealms.customcrops.api.mechanic.world.season.Season; import org.bukkit.World; @@ -25,9 +26,15 @@ import org.jetbrains.annotations.Nullable; public class RealisticSeasonsImpl implements SeasonInterface { + private final SeasonsAPI api; + + public RealisticSeasonsImpl() { + this.api = SeasonsAPI.getInstance(); + } + @Override public @Nullable Season getSeason(World world) { - return switch (SeasonsAPI.getInstance().getSeason(world)) { + return switch (api.getSeason(world)) { case WINTER -> Season.WINTER; case SPRING -> Season.SPRING; case SUMMER -> Season.SUMMER; @@ -38,6 +45,23 @@ public class RealisticSeasonsImpl implements SeasonInterface { @Override public int getDate(World world) { - return SeasonsAPI.getInstance().getDate(world).getDay(); + return api.getDate(world).getDay(); + } + + @Override + public void setSeason(World world, Season season) { + me.casperge.realisticseasons.season.Season rsSeason = switch (season) { + case AUTUMN -> me.casperge.realisticseasons.season.Season.FALL; + case SUMMER -> me.casperge.realisticseasons.season.Season.SUMMER; + case WINTER -> me.casperge.realisticseasons.season.Season.WINTER; + case SPRING -> me.casperge.realisticseasons.season.Season.SPRING; + }; + api.setSeason(world, rsSeason); + } + + @Override + public void setDate(World world, int date) { + Date rsDate = api.getDate(world); + api.setDate(world, new Date(date, rsDate.getMonth(), rsDate.getYear())); } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java b/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java index 1de3420..8edb501 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/CommandManager.java @@ -26,6 +26,10 @@ import net.momirealms.customcrops.api.CustomCropsPlugin; import net.momirealms.customcrops.api.common.Initable; import net.momirealms.customcrops.api.integration.SeasonInterface; import net.momirealms.customcrops.api.manager.MessageManager; +import net.momirealms.customcrops.api.mechanic.item.ItemType; +import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; +import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsChunk; +import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsSection; import net.momirealms.customcrops.api.mechanic.world.level.CustomCropsWorld; import net.momirealms.customcrops.api.mechanic.world.season.Season; import net.momirealms.customcrops.compatibility.season.InBuiltSeason; @@ -54,8 +58,8 @@ public class CommandManager implements Initable { getReloadCommand(), getAboutCommand(), getSeasonCommand(), - getDateCommand() - //getStressTest() + getDateCommand(), + getForceTickCommand() ) .register(); } @@ -85,6 +89,32 @@ public class CommandManager implements Initable { }); } + private CommandAPICommand getForceTickCommand() { + return new CommandAPICommand("force-tick") + .withArguments(new WorldArgument("world")) + .withArguments(new StringArgument("type").replaceSuggestions(ArgumentSuggestions.strings("sprinkler", "crop", "pot", "scarecrow", "greenhouse"))) + .executes((sender, args) -> { + World world = (World) args.get("world"); + ItemType itemType = ItemType.valueOf(((String) args.get("type")).toUpperCase(Locale.ENGLISH)); + Optional customCropsWorld = plugin.getWorldManager().getCustomCropsWorld(world); + if (customCropsWorld.isEmpty()) { + plugin.getAdventure().sendMessageWithPrefix(sender, "CustomCrops is not enabled in that world"); + return; + } + plugin.getScheduler().runTaskAsync(() -> { + for (CustomCropsChunk chunk : customCropsWorld.get().getChunkStorage()) { + for (CustomCropsSection section : chunk.getSections()) { + for (CustomCropsBlock block : section.getBlocks()) { + if (block.getType() == itemType) { + block.tick(1); + } + } + } + } + }); + }); + } + private CommandAPICommand getDateCommand() { return new CommandAPICommand("date") .withSubcommands( @@ -176,45 +206,4 @@ public class CommandManager implements Initable { }) ); } - -// private CommandAPICommand getStressTest() { -// return new CommandAPICommand("test").executes((sender, args) -> { -// for (int i = 0; i < 16; i++) { -// for (int j = 0; j < 16; j++) { -// for (int k = -64; k < 0; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "tomato", 0), location); -// } -// for (int k = 1; k < 64; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "tomato", 1), location); -// } -// for (int k = 65; k < 128; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "tomato", 2), location); -// } -// for (int k = 129; k < 165; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addPotAt(new MemoryPot(location, "default"), location); -// } -// for (int k = 166; k < 190; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addPotAt(new MemoryPot(location, "sprinkler"), location); -// } -// for (int k = 191; k < 250; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "tomato", 3), location); -// } -// for (int k = 251; k < 300; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "sbsbssbsb", 3), location); -// } -// for (int k = 301; k < 320; k++) { -// SimpleLocation location = new SimpleLocation("world", 1024 + i, k, 1024 + j); -// plugin.getWorldManager().addCropAt(new MemoryCrop(location, "sbsbssbsb", 2), location); -// } -// } -// } -// }); -// } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java index 84ceca4..65a742f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/manager/ConfigManagerImpl.java @@ -133,7 +133,7 @@ public class ConfigManagerImpl extends ConfigManager { syncSeasons = mechanics.getBoolean("sync-season.enable", true); if (syncSeasons) { - referenceWorld = new WeakReference<>(Bukkit.getWorld(Objects.requireNonNull(mechanics.getString("sync-season.reference")))); + referenceWorld = new WeakReference<>(Bukkit.getWorld(mechanics.getString("sync-season.reference", "world"))); } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java index 58580d5..1ec8bd6 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/action/ActionManagerImpl.java @@ -38,6 +38,7 @@ import net.momirealms.customcrops.api.mechanic.item.fertilizer.QualityCrop; import net.momirealms.customcrops.api.mechanic.item.fertilizer.Variation; import net.momirealms.customcrops.api.mechanic.item.fertilizer.YieldIncrease; import net.momirealms.customcrops.api.mechanic.misc.CRotation; +import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.misc.Value; import net.momirealms.customcrops.api.mechanic.requirement.Requirement; import net.momirealms.customcrops.api.mechanic.world.ChunkCoordinate; @@ -696,7 +697,7 @@ public class ActionManagerImpl implements ActionManager { switch (removed.get().getType()) { case SPRINKLER -> { WorldSprinkler sprinkler = (WorldSprinkler) removed.get(); - SprinklerBreakEvent event = new SprinklerBreakEvent(state.getPlayer(), state.getLocation(), sprinkler); + SprinklerBreakEvent event = new SprinklerBreakEvent(state.getPlayer(), state.getLocation(), sprinkler, Reason.ACTION); if (EventUtils.fireAndCheckCancel(event)) return; if (arg) sprinkler.getConfig().trigger(ActionTrigger.BREAK, state); @@ -705,7 +706,7 @@ public class ActionManagerImpl implements ActionManager { } case CROP -> { WorldCrop crop = (WorldCrop) removed.get(); - CropBreakEvent event = new CropBreakEvent(state.getPlayer(), state.getLocation(), crop); + CropBreakEvent event = new CropBreakEvent(state.getPlayer(), state.getLocation(), crop, Reason.ACTION); if (EventUtils.fireAndCheckCancel(event)) return; Crop cropConfig = crop.getConfig(); @@ -718,7 +719,7 @@ public class ActionManagerImpl implements ActionManager { } case POT -> { WorldPot pot = (WorldPot) removed.get(); - PotBreakEvent event = new PotBreakEvent(state.getPlayer(), state.getLocation(), pot); + PotBreakEvent event = new PotBreakEvent(state.getPlayer(), state.getLocation(), pot, Reason.ACTION); if (EventUtils.fireAndCheckCancel(event)) return; if (arg) pot.getConfig().trigger(ActionTrigger.BREAK, state); diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java index 8aee2c8..9889794 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/ItemManagerImpl.java @@ -32,12 +32,12 @@ import net.momirealms.customcrops.api.mechanic.item.*; import net.momirealms.customcrops.api.mechanic.item.water.PassiveFillMethod; import net.momirealms.customcrops.api.mechanic.item.water.PositiveFillMethod; import net.momirealms.customcrops.api.mechanic.misc.CRotation; +import net.momirealms.customcrops.api.mechanic.misc.Reason; import net.momirealms.customcrops.api.mechanic.misc.image.WaterBar; import net.momirealms.customcrops.api.mechanic.requirement.State; +import net.momirealms.customcrops.api.mechanic.world.CustomCropsBlock; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; -import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; -import net.momirealms.customcrops.api.mechanic.world.level.WorldPot; -import net.momirealms.customcrops.api.mechanic.world.level.WorldSprinkler; +import net.momirealms.customcrops.api.mechanic.world.level.*; import net.momirealms.customcrops.api.util.LogUtils; import net.momirealms.customcrops.mechanic.item.custom.AbstractCustomListener; import net.momirealms.customcrops.mechanic.item.custom.itemsadder.ItemsAdderListener; @@ -70,6 +70,7 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.ItemFrame; import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; @@ -629,12 +630,23 @@ public class ItemManagerImpl implements ItemManager { if (!(conditionWrapper instanceof BreakWrapper breakWrapper)) { return FunctionResult.PASS; } + + // get or fix + Location location = breakWrapper.getLocation(); + SimpleLocation simpleLocation = SimpleLocation.of(location); + Optional optionalWorldGlass = plugin.getWorldManager().getGlassAt(simpleLocation); + if (optionalWorldGlass.isEmpty()) { + WorldGlass glass = new MemoryGlass(simpleLocation); + optionalWorldGlass = Optional.of(glass); + plugin.getWorldManager().addGlassAt(glass, simpleLocation); + } + // fire event - GreenhouseGlassBreakEvent event = new GreenhouseGlassBreakEvent(breakWrapper.getPlayer(), breakWrapper.getLocation()); + GreenhouseGlassBreakEvent event = new GreenhouseGlassBreakEvent(breakWrapper.getPlayer(), location, optionalWorldGlass.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(event)) return FunctionResult.CANCEL_EVENT_AND_RETURN; - plugin.getWorldManager().removeGlassAt(SimpleLocation.of(breakWrapper.getLocation())); + plugin.getWorldManager().removeGlassAt(simpleLocation); return FunctionResult.RETURN; }, CFunction.FunctionPriority.NORMAL) ); @@ -661,12 +673,23 @@ public class ItemManagerImpl implements ItemManager { if (!(conditionWrapper instanceof BreakWrapper breakWrapper)) { return FunctionResult.PASS; } + + // get or fix + Location location = breakWrapper.getLocation(); + SimpleLocation simpleLocation = SimpleLocation.of(location); + Optional optionalWorldScarecrow = plugin.getWorldManager().getScarecrowAt(simpleLocation); + if (optionalWorldScarecrow.isEmpty()) { + WorldScarecrow scarecrow = new MemoryScarecrow(simpleLocation); + optionalWorldScarecrow = Optional.of(scarecrow); + plugin.getWorldManager().addScarecrowAt(scarecrow, simpleLocation); + } + // fire event - ScarecrowBreakEvent event = new ScarecrowBreakEvent(breakWrapper.getPlayer(), breakWrapper.getLocation()); + ScarecrowBreakEvent event = new ScarecrowBreakEvent(breakWrapper.getPlayer(), location, optionalWorldScarecrow.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(event)) return FunctionResult.CANCEL_EVENT_AND_RETURN; - plugin.getWorldManager().removeScarecrowAt(SimpleLocation.of(breakWrapper.getLocation())); + plugin.getWorldManager().removeScarecrowAt(simpleLocation); return FunctionResult.RETURN; }, CFunction.FunctionPriority.NORMAL) ); @@ -740,8 +763,20 @@ public class ItemManagerImpl implements ItemManager { int waterInCan = wateringCan.getCurrentWater(itemStack); if (waterInCan > 0 || wateringCan.isInfinite()) { + + Collection pots = getPotInRange(clicked, wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); + // get or fix pot + SimpleLocation simpleLocation = SimpleLocation.of(clicked); + Optional worldPot = plugin.getWorldManager().getPotAt(simpleLocation); + if (worldPot.isEmpty()) { + plugin.debug("Found pot data not exists at " + simpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(simpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, simpleLocation); + worldPot = Optional.of(memoryPot); + } + // fire the event - WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, wateringCan, clicked, pot); + WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, new HashSet<>(pots), wateringCan, worldPot.get()); if (EventUtils.fireAndCheckCancel(waterEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -750,8 +785,8 @@ public class ItemManagerImpl implements ItemManager { state.setArg("{water_bar}", wateringCan.getWaterBar() == null ? "" : wateringCan.getWaterBar().getWaterBar(waterInCan - 1, wateringCan.getStorage())); wateringCan.updateItem(player, itemStack, waterInCan - 1, state.getArgs()); wateringCan.trigger(ActionTrigger.CONSUME_WATER, state); - Collection pots = getPotInRange(clicked, wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); - for (Location location : pots) { + + for (Location location : waterEvent.getLocation()) { plugin.getWorldManager().addWaterToPot(pot, SimpleLocation.of(location), wateringCan.getWater()); pot.trigger(ActionTrigger.ADD_WATER, new State(player, itemStack, location)); } @@ -809,8 +844,21 @@ public class ItemManagerImpl implements ItemManager { int waterInCan = wateringCan.getCurrentWater(itemStack); if (waterInCan > 0 || wateringCan.isInfinite()) { + + Collection pots = getPotInRange(potBlock.getLocation(), wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); + + // get or fix pot + SimpleLocation simpleLocation = SimpleLocation.of(potBlock.getLocation()); + Optional worldPot = plugin.getWorldManager().getPotAt(simpleLocation); + if (worldPot.isEmpty()) { + plugin.debug("Found pot data not exists at " + simpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(simpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, simpleLocation); + worldPot = Optional.of(memoryPot); + } + // fire the event - WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, wateringCan, potBlock.getLocation(), pot); + WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, new HashSet<>(pots), wateringCan, worldPot.get()); if (EventUtils.fireAndCheckCancel(waterEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -819,8 +867,8 @@ public class ItemManagerImpl implements ItemManager { state.setArg("{water_bar}", wateringCan.getWaterBar() == null ? "" : wateringCan.getWaterBar().getWaterBar(waterInCan - 1, wateringCan.getStorage())); wateringCan.updateItem(player, itemStack, waterInCan - 1, state.getArgs()); wateringCan.trigger(ActionTrigger.CONSUME_WATER, state); - Collection pots = getPotInRange(potBlock.getLocation(), wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); - for (Location location : pots) { + + for (Location location : waterEvent.getLocation()) { plugin.getWorldManager().addWaterToPot(pot, SimpleLocation.of(location), wateringCan.getWater()); pot.trigger(ActionTrigger.ADD_WATER, new State(player, itemStack, location)); } @@ -875,8 +923,21 @@ public class ItemManagerImpl implements ItemManager { int waterInCan = wateringCan.getCurrentWater(itemStack); if (waterInCan > 0 || wateringCan.isInfinite()) { + + Collection pots = getPotInRange(potBlock.getLocation(), wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); + + // get or fix pot + SimpleLocation simpleLocation = SimpleLocation.of(potBlock.getLocation()); + Optional worldPot = plugin.getWorldManager().getPotAt(simpleLocation); + if (worldPot.isEmpty()) { + plugin.debug("Found pot data not exists at " + simpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(simpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, simpleLocation); + worldPot = Optional.of(memoryPot); + } + // fire the event - WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, wateringCan, clicked, pot); + WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemStack, new HashSet<>(pots), wateringCan, worldPot.get()); if (EventUtils.fireAndCheckCancel(waterEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -885,8 +946,8 @@ public class ItemManagerImpl implements ItemManager { state.setArg("{water_bar}", wateringCan.getWaterBar() == null ? "" : wateringCan.getWaterBar().getWaterBar(waterInCan - 1, wateringCan.getStorage())); wateringCan.updateItem(player, itemStack, waterInCan - 1, state.getArgs()); wateringCan.trigger(ActionTrigger.CONSUME_WATER, state); - Collection pots = getPotInRange(potBlock.getLocation(), wateringCan.getWidth(), wateringCan.getLength(), player.getLocation().getYaw(), pot.getKey()); - for (Location location : pots) { + + for (Location location : waterEvent.getLocation()) { plugin.getWorldManager().addWaterToPot(pot, SimpleLocation.of(location), wateringCan.getWater()); pot.trigger(ActionTrigger.ADD_WATER, new State(player, itemStack, location)); } @@ -936,6 +997,9 @@ public class ItemManagerImpl implements ItemManager { Optional worldSprinkler = plugin.getWorldManager().getSprinklerAt(simpleLocation); if (worldSprinkler.isEmpty()) { plugin.debug("Player " + player.getName() + " tried to interact a sprinkler which not exists in memory. Fixing the data..."); + WorldSprinkler sp = new MemorySprinkler(simpleLocation, sprinkler.getKey(), 0); + plugin.getWorldManager().addSprinklerAt(sp, simpleLocation); + worldSprinkler = Optional.of(sp); } else { if (sprinkler.getStorage() <= worldSprinkler.get().getWater()) { return FunctionResult.RETURN; @@ -943,7 +1007,7 @@ public class ItemManagerImpl implements ItemManager { } // fire the event - WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemInHand, wateringCan, location, sprinkler); + WateringCanWaterEvent waterEvent = new WateringCanWaterEvent(player, itemInHand, new HashSet<>(Set.of(location)), wateringCan, worldSprinkler.get()); if (EventUtils.fireAndCheckCancel(waterEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -969,7 +1033,7 @@ public class ItemManagerImpl implements ItemManager { if (method.getId().equals(clickedFurnitureID)) { if (method.canFill(state)) { // fire the event - WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, wateringCan, location, method); + WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, location, wateringCan, method); if (EventUtils.fireAndCheckCancel(fillEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -1029,7 +1093,7 @@ public class ItemManagerImpl implements ItemManager { if (method.canFill(state)) { if (water < wateringCan.getStorage()) { // fire the event - WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, wateringCan, state.getLocation(), method); + WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, state.getLocation(), wateringCan, method); if (EventUtils.fireAndCheckCancel(fillEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -1083,7 +1147,7 @@ public class ItemManagerImpl implements ItemManager { if (method.canFill(state)) { if (water < wateringCan.getStorage()) { // fire the event - WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, wateringCan, state.getLocation(), method); + WateringCanFillEvent fillEvent = new WateringCanFillEvent(player, itemInHand, state.getLocation(), wateringCan, method); if (EventUtils.fireAndCheckCancel(fillEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; @@ -1367,7 +1431,7 @@ public class ItemManagerImpl implements ItemManager { return FunctionResult.RETURN; } // fire event - SprinklerBreakEvent breakEvent = new SprinklerBreakEvent(breakFurnitureWrapper.getPlayer(), location, optionalSprinkler.get()); + SprinklerBreakEvent breakEvent = new SprinklerBreakEvent(breakFurnitureWrapper.getPlayer(), location, optionalSprinkler.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(breakEvent)) { return FunctionResult.CANCEL_EVENT_AND_RETURN; } @@ -1487,10 +1551,17 @@ public class ItemManagerImpl implements ItemManager { Optional worldPot = plugin.getWorldManager().getPotAt(simpleLocation); boolean hasWater = false; if (worldPot.isEmpty()) { - plugin.debug("Found pot data not exists at " + simpleLocation); + plugin.debug("Found pot data not exists at " + simpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(simpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, simpleLocation); + worldPot = Optional.of(memoryPot); } else { hasWater = worldPot.get().getWater() > 0; } + // fire the event + FertilizerUseEvent useEvent = new FertilizerUseEvent(state.getPlayer(), itemInHand, fertilizer, location, worldPot.get()); + if (EventUtils.fireAndCheckCancel(useEvent)) + return FunctionResult.CANCEL_EVENT_AND_RETURN; // add data plugin.getWorldManager().addFertilizerToPot(pot, fertilizer, simpleLocation); @@ -1548,10 +1619,17 @@ public class ItemManagerImpl implements ItemManager { Optional worldPot = plugin.getWorldManager().getPotAt(simpleLocation); boolean hasWater = false; if (worldPot.isEmpty()) { - plugin.debug("Found pot data not exists at " + potLocation); + plugin.debug("Found pot data not exists at " + simpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(simpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, simpleLocation); + worldPot = Optional.of(memoryPot); } else { hasWater = worldPot.get().getWater() > 0; } + // fire the event + FertilizerUseEvent useEvent = new FertilizerUseEvent(state.getPlayer(), itemInHand, fertilizer, location, worldPot.get()); + if (EventUtils.fireAndCheckCancel(useEvent)) + return FunctionResult.CANCEL_EVENT_AND_RETURN; // add data plugin.getWorldManager().addFertilizerToPot(pot, fertilizer, simpleLocation); @@ -1808,6 +1886,11 @@ public class ItemManagerImpl implements ItemManager { if (optionalCrop.get().getPoint() < crop.getMaxPoints()) { for (BoneMeal boneMeal : crop.getBoneMeals()) { if (boneMeal.getItem().equals(itemID)) { + // fire the event + BoneMealUseEvent useEvent = new BoneMealUseEvent(player, itemInHand, cropLocation, boneMeal, optionalCrop.get()); + if (EventUtils.fireAndCheckCancel(useEvent)) + return FunctionResult.CANCEL_EVENT_AND_RETURN; + if (player.getGameMode() != GameMode.CREATIVE) { itemInHand.setAmount(itemAmount - boneMeal.getUsedAmount()); if (boneMeal.getReturned() != null) { @@ -1852,6 +1935,9 @@ public class ItemManagerImpl implements ItemManager { SimpleLocation simpleLocation = SimpleLocation.of(cropLocation); Optional optionalWorldCrop = plugin.getWorldManager().getCropAt(simpleLocation); if (optionalWorldCrop.isEmpty()) { + WorldCrop worldCrop = new MemoryCrop(simpleLocation, crop.getKey(), stage.getPoint()); + plugin.getWorldManager().addCropAt(worldCrop, simpleLocation); + optionalWorldCrop = Optional.of(worldCrop); plugin.debug("Found a crop without data broken by " + player.getName() + " at " + cropLocation + ". " + "You can safely ignore this if the crop is spawned in the wild."); } else { @@ -1862,7 +1948,7 @@ public class ItemManagerImpl implements ItemManager { } } // fire event - CropBreakEvent breakEvent = new CropBreakEvent(player, cropLocation, optionalWorldCrop.orElse(null)); + CropBreakEvent breakEvent = new CropBreakEvent(player, cropLocation, optionalWorldCrop.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(breakEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; // trigger actions @@ -2036,23 +2122,27 @@ public class ItemManagerImpl implements ItemManager { if (!RequirementManager.isRequirementMet(cropState, stage.getBreakRequirements())) { return FunctionResult.CANCEL_EVENT_AND_RETURN; } - Optional optionalWorldCrop = plugin.getWorldManager().getCropAt(SimpleLocation.of(cropLocation)); + SimpleLocation simpleLocation = SimpleLocation.of(cropLocation); + Optional optionalWorldCrop = plugin.getWorldManager().getCropAt(simpleLocation); if (optionalWorldCrop.isPresent()) { if (!optionalWorldCrop.get().getKey().equals(crop.getKey())) { LogUtils.warn("Found a crop having inconsistent data broken by " + player.getName() + " at " + cropLocation + "."); } } else { + WorldCrop worldCrop = new MemoryCrop(simpleLocation, crop.getKey(), stage.getPoint()); + optionalWorldCrop = Optional.of(worldCrop); + plugin.getWorldManager().addCropAt(worldCrop, simpleLocation); plugin.debug("Found a crop without data broken by " + player.getName() + " at " + cropLocation + ". " + "You can safely ignore this if the crop is spawned in the wild."); } // fire event - CropBreakEvent breakEvent = new CropBreakEvent(player, cropLocation, optionalWorldCrop.orElse(null)); + CropBreakEvent breakEvent = new CropBreakEvent(player, cropLocation, optionalWorldCrop.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(breakEvent)) return FunctionResult.CANCEL_EVENT_AND_RETURN; // trigger actions stage.trigger(ActionTrigger.BREAK, cropState); crop.trigger(ActionTrigger.BREAK, cropState); - plugin.getWorldManager().removeCropAt(SimpleLocation.of(cropLocation)); + plugin.getWorldManager().removeCropAt(simpleLocation); customProvider.removeAnythingAt(cropLocation); } else { LogUtils.warn("Invalid crop stage: " + cropStageID); @@ -2076,7 +2166,7 @@ public class ItemManagerImpl implements ItemManager { return FunctionResult.RETURN; } // fire event - PotBreakEvent breakEvent = new PotBreakEvent(blockWrapper.getPlayer(), location, optionalPot.get()); + PotBreakEvent breakEvent = new PotBreakEvent(blockWrapper.getPlayer(), location, optionalPot.get(), Reason.BREAK); if (EventUtils.fireAndCheckCancel(breakEvent)) { return FunctionResult.CANCEL_EVENT_AND_RETURN; } @@ -2297,47 +2387,139 @@ public class ItemManagerImpl implements ItemManager { if (entity instanceof Player player) { handlePlayerBreakBlock(player, block, event); } else { + // if the block is a pot Pot pot = getPotByBlock(block); if (pot != null) { - // prevent entities from breaking pots with requirements - if (pot.getBreakRequirements().length != 0) { + Location potLocation = block.getLocation(); + // get or fix pot + SimpleLocation potSimpleLocation = SimpleLocation.of(potLocation); + Optional worldPot = plugin.getWorldManager().getPotAt(potSimpleLocation); + if (worldPot.isEmpty()) { + plugin.debug("Found pot data not exists at " + potSimpleLocation + ". Fixing it."); + MemoryPot memoryPot = new MemoryPot(potSimpleLocation, pot.getKey()); + plugin.getWorldManager().addPotAt(memoryPot, potSimpleLocation); + worldPot = Optional.of(memoryPot); + } + // fire the event + PotBreakEvent potBreakEvent = new PotBreakEvent(entity, potLocation, worldPot.get(), Reason.TRAMPLE); + if (EventUtils.fireAndCheckCancel(potBreakEvent)) { event.setCancelled(true); return; } + plugin.getWorldManager().removePotAt(SimpleLocation.of(block.getLocation())); + pot.trigger(ActionTrigger.BREAK, new State(null, new ItemStack(Material.AIR), block.getLocation())); + Location cropLocation = block.getLocation().clone().add(0,1,0); String cropStageID = customProvider.getSomethingAt(cropLocation); Crop.Stage stage = stage2CropStageMap.get(cropStageID); if (stage != null) { - //State state = new State(null, new ItemStack(Material.AIR), cropLocation); - // if crops are above, check the break requirements for crops Crop crop = getCropByStageID(cropStageID); - if (crop.getBreakRequirements().length != 0 || stage.getBreakRequirements().length != 0) { - event.setCancelled(true); - return; - } - Optional optionalWorldCrop = plugin.getWorldManager().getCropAt(SimpleLocation.of(cropLocation)); + SimpleLocation simpleLocation = SimpleLocation.of(cropLocation); + Optional optionalWorldCrop = plugin.getWorldManager().getCropAt(simpleLocation); if (optionalWorldCrop.isPresent()) { if (!optionalWorldCrop.get().getKey().equals(crop.getKey())) { LogUtils.warn("Found a crop having inconsistent data broken by " + entity.getType() + " at " + cropLocation + "."); } } else { + WorldCrop worldCrop = new MemoryCrop(simpleLocation, crop.getKey(), stage.getPoint()); + plugin.getWorldManager().addCropAt(worldCrop, simpleLocation); + optionalWorldCrop = Optional.of(worldCrop); plugin.debug("Found a crop without data broken by " + entity.getType() + " at " + cropLocation + ". " + "You can safely ignore this if the crop is spawned in the wild."); } + // fire the event + CropBreakEvent breakEvent = new CropBreakEvent(entity, cropLocation, optionalWorldCrop.get(), Reason.TRAMPLE); + if (EventUtils.fireAndCheckCancel(breakEvent)) { + event.setCancelled(true); + return; + } + + State state = new State(null, new ItemStack(Material.AIR), cropLocation); // trigger actions - //stage.trigger(ActionTrigger.BREAK, state); - //crop.trigger(ActionTrigger.BREAK, state); - plugin.getWorldManager().removeCropAt(SimpleLocation.of(cropLocation)); + stage.trigger(ActionTrigger.BREAK, state); + crop.trigger(ActionTrigger.BREAK, state); + plugin.getWorldManager().removeCropAt(simpleLocation); customProvider.removeAnythingAt(cropLocation); } if (deadCrops.contains(cropStageID)) { customProvider.removeAnythingAt(cropLocation); } + } + } + } - plugin.getWorldManager().removePotAt(SimpleLocation.of(block.getLocation())); - //pot.trigger(ActionTrigger.BREAK, new State(null, new ItemStack(Material.AIR), block.getLocation())); + public void handleExplosion(Entity entity, List blocks, Cancellable event) { + List locationsToRemove = new ArrayList<>(); + List locationsToRemoveBlock = new ArrayList<>(); + HashSet blockLocations = new HashSet<>(blocks.stream().map(Block::getLocation).toList()); + List aboveLocations = new ArrayList<>(); + for (Location location : blockLocations) { + Optional optionalCustomCropsBlock = plugin.getWorldManager().getBlockAt(SimpleLocation.of(location)); + if (optionalCustomCropsBlock.isPresent()) { + Event customEvent = null; + CustomCropsBlock customCropsBlock = optionalCustomCropsBlock.get(); + switch (customCropsBlock.getType()) { + case POT -> { + customEvent = new PotBreakEvent(entity, location, (WorldPot) customCropsBlock, Reason.EXPLODE); + Location above = location.clone().add(0,1,0); + if (!blockLocations.contains(above)) { + aboveLocations.add(above); + } + } + case SPRINKLER -> customEvent = new SprinklerBreakEvent(entity, location, (WorldSprinkler) customCropsBlock, Reason.EXPLODE); + case CROP -> customEvent = new CropBreakEvent(entity, location, (WorldCrop) customCropsBlock, Reason.EXPLODE); + case GREENHOUSE -> customEvent = new GreenhouseGlassBreakEvent(entity, location, (WorldGlass) customCropsBlock, Reason.EXPLODE); + case SCARECROW -> customEvent = new ScarecrowBreakEvent(entity, location, (WorldScarecrow) customCropsBlock, Reason.EXPLODE); + } + if (customEvent != null && EventUtils.fireAndCheckCancel(customEvent)) { + event.setCancelled(true); + return; + } + locationsToRemove.add(location); + } + } + + for (Location location : aboveLocations) { + Optional optionalCustomCropsBlock = plugin.getWorldManager().getBlockAt(SimpleLocation.of(location)); + if (optionalCustomCropsBlock.isPresent()) { + CustomCropsBlock customCropsBlock = optionalCustomCropsBlock.get(); + if (customCropsBlock.getType() == ItemType.CROP) { + if (EventUtils.fireAndCheckCancel(new CropBreakEvent(entity, location, (WorldCrop) customCropsBlock, Reason.EXPLODE))) { + event.setCancelled(true); + return; + } + locationsToRemove.add(location); + locationsToRemoveBlock.add(location); + } + } + } + + for (Location location : locationsToRemoveBlock) { + removeAnythingAt(location); + } + + for (Location location : locationsToRemove) { + CustomCropsBlock customCropsBlock = plugin.getWorldManager().removeAnythingAt(SimpleLocation.of(location)); + if (customCropsBlock != null) { + State state = new State(null, new ItemStack(Material.AIR), location); + switch (customCropsBlock.getType()) { + case POT -> { + Pot pot = ((WorldPot) customCropsBlock).getConfig(); + pot.trigger(ActionTrigger.BREAK, state); + } + case CROP -> { + Crop crop = ((WorldCrop) customCropsBlock).getConfig(); + Crop.Stage stage = crop.getStageByItemID(crop.getStageItemByPoint(((WorldCrop) customCropsBlock).getPoint())); + crop.trigger(ActionTrigger.BREAK, state); + stage.trigger(ActionTrigger.BREAK, state); + } + case SPRINKLER -> { + Sprinkler sprinkler = ((WorldSprinkler) customCropsBlock).getConfig(); + sprinkler.trigger(ActionTrigger.BREAK, state); + } + } } } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java index 5fbce50..e6127ba 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/item/custom/AbstractCustomListener.java @@ -18,17 +18,19 @@ package net.momirealms.customcrops.mechanic.item.custom; import net.momirealms.customcrops.api.CustomCropsPlugin; +import net.momirealms.customcrops.api.event.BoneMealDispenseEvent; import net.momirealms.customcrops.api.manager.ConfigManager; import net.momirealms.customcrops.api.manager.WorldManager; -import net.momirealms.customcrops.api.mechanic.item.Crop; -import net.momirealms.customcrops.api.mechanic.item.Pot; -import net.momirealms.customcrops.api.mechanic.item.Sprinkler; -import net.momirealms.customcrops.api.mechanic.item.WateringCan; +import net.momirealms.customcrops.api.mechanic.item.*; +import net.momirealms.customcrops.api.mechanic.requirement.State; import net.momirealms.customcrops.api.mechanic.world.SimpleLocation; +import net.momirealms.customcrops.api.mechanic.world.level.WorldCrop; import net.momirealms.customcrops.mechanic.item.ItemManagerImpl; +import net.momirealms.customcrops.utils.EventUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.Dispenser; import org.bukkit.entity.Entity; import org.bukkit.entity.Item; import org.bukkit.entity.Player; @@ -38,13 +40,17 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.*; import org.bukkit.event.entity.EntityChangeBlockEvent; +import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerItemDamageEvent; import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.Nullable; +import java.util.Optional; + public abstract class AbstractCustomListener implements Listener { protected ItemManagerImpl itemManager; @@ -195,19 +201,76 @@ public abstract class AbstractCustomListener implements Listener { } } + @EventHandler (ignoreCancelled = true) + public void onExplosion(EntityExplodeEvent event) { + this.itemManager.handleExplosion(event.getEntity(), event.blockList(), event); + } + + @EventHandler (ignoreCancelled = true) + public void onExplosion(BlockExplodeEvent event) { + this.itemManager.handleExplosion(null, event.blockList(), event); + } + + @EventHandler (ignoreCancelled = true) + public void onDispenser(BlockDispenseEvent event) { + Block block = event.getBlock(); + if (block.getBlockData() instanceof org.bukkit.block.data.type.Dispenser directional) { + Block relative = block.getRelative(directional.getFacing()); + Location location = relative.getLocation(); + SimpleLocation simpleLocation = SimpleLocation.of(location); + Optional worldCropOptional = CustomCropsPlugin.get().getWorldManager().getCropAt(simpleLocation); + if (worldCropOptional.isPresent()) { + WorldCrop crop = worldCropOptional.get(); + Crop config = crop.getConfig(); + ItemStack itemStack = event.getItem(); + String itemID = itemManager.getItemID(itemStack); + if (crop.getPoint() < config.getMaxPoints()) { + for (BoneMeal boneMeal : config.getBoneMeals()) { + if (boneMeal.getItem().equals(itemID)) { + // fire the event + if (EventUtils.fireAndCheckCancel(new BoneMealDispenseEvent(block, itemStack, location, boneMeal, crop))) { + event.setCancelled(true); + return; + } + + if (block.getState() instanceof Dispenser dispenser) { + event.setCancelled(true); + Inventory inventory = dispenser.getInventory(); + for (ItemStack storage : inventory.getStorageContents()) { + if (storage == null) continue; + String id = itemManager.getItemID(storage); + if (id.equals(itemID)) { + storage.setAmount(storage.getAmount() - 1); + boneMeal.trigger(new State(null, itemStack, location)); + CustomCropsPlugin.get().getWorldManager().addPointToCrop(config, simpleLocation, boneMeal.getPoint()); + } + } + } + return; + } + } + } + } + } + } + public void onPlaceBlock(Player player, Block block, String blockID, Cancellable event) { + if (player == null) return; this.itemManager.handlePlayerPlaceBlock(player, block, blockID, event); } public void onBreakFurniture(Player player, Location location, String id, Cancellable event) { + if (player == null) return; this.itemManager.handlePlayerBreakFurniture(player, location, id, event); } public void onPlaceFurniture(Player player, Location location, String id, Cancellable event) { + if (player == null) return; this.itemManager.handlePlayerPlaceFurniture(player, location, id, event); } public void onInteractFurniture(Player player, Location location, String id, @Nullable Entity baseEntity, Cancellable event) { + if (player == null) return; this.itemManager.handlePlayerInteractFurniture(player, location, id, baseEntity, event); } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java index 82525a1..2f87b14 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/requirement/RequirementManagerImpl.java @@ -125,6 +125,7 @@ public class RequirementManagerImpl implements RequirementManager { this.registerTemperatureRequirement(); this.registerFertilizerRequirement(); this.registerLightRequirement(); + this.registerGameModeRequirement(); } @NotNull @@ -228,6 +229,21 @@ public class RequirementManagerImpl implements RequirementManager { }); } + private void registerGameModeRequirement() { + registerRequirement("gamemode", (args, actions, advanced) -> { + List modes = ConfigUtils.stringListArgs(args); + return condition -> { + if (condition.getPlayer() == null) return true; + var name = condition.getPlayer().getGameMode().name().toLowerCase(Locale.ENGLISH); + if (modes.contains(name)) { + return true; + } + if (advanced) triggerActions(actions, condition); + return false; + }; + }); + } + private void registerTemperatureRequirement() { registerRequirement("temperature", (args, actions, advanced) -> { List> tempPairs = ConfigUtils.stringListArgs(args).stream().map(it -> ConfigUtils.splitStringIntegerArgs(it, "~")).toList(); @@ -317,6 +333,7 @@ public class RequirementManagerImpl implements RequirementManager { registerRequirement("level", (args, actions, advanced) -> { int level = (int) args; return state -> { + if (state.getPlayer() == null) return true; int current = state.getPlayer().getLevel(); if (current >= level) return true; @@ -330,6 +347,7 @@ public class RequirementManagerImpl implements RequirementManager { registerRequirement("money", (args, actions, advanced) -> { double money = ConfigUtils.getDoubleValue(args); return state -> { + if (state.getPlayer() == null) return true; double current = VaultHook.getEconomy().getBalance(state.getPlayer()); if (current >= money) return true; @@ -420,6 +438,7 @@ public class RequirementManagerImpl implements RequirementManager { String key = section.getString("key"); int time = section.getInt("time"); return state -> { + if (state.getPlayer() == null) return true; if (!plugin.getCoolDownManager().isCoolDown(state.getPlayer().getUniqueId(), key, time)) { return true; } @@ -451,6 +470,7 @@ public class RequirementManagerImpl implements RequirementManager { registerRequirement("sneak", (args, actions, advanced) -> { boolean sneak = (boolean) args; return state -> { + if (state.getPlayer() == null) return true; if (sneak) { if (state.getPlayer().isSneaking()) return true; @@ -468,6 +488,7 @@ public class RequirementManagerImpl implements RequirementManager { registerRequirement("permission", (args, actions, advanced) -> { List perms = ConfigUtils.stringListArgs(args); return state -> { + if (state.getPlayer() == null) return true; for (String perm : perms) if (state.getPlayer().hasPermission(perm)) return true; @@ -478,6 +499,7 @@ public class RequirementManagerImpl implements RequirementManager { registerRequirement("!permission", (args, actions, advanced) -> { List perms = ConfigUtils.stringListArgs(args); return state -> { + if (state.getPlayer() == null) return true; for (String perm : perms) if (state.getPlayer().hasPermission(perm)) { if (advanced) triggerActions(actions, state); @@ -934,6 +956,7 @@ public class RequirementManagerImpl implements RequirementManager { int required = Integer.parseInt(split[1]); String operator = potions.substring(split[0].length(), potions.length() - split[1].length()); return state -> { + if (state.getPlayer() == null) return true; int level = -1; PotionEffect potionEffect = state.getPlayer().getPotionEffect(type); if (potionEffect != null) { diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java index 0766304..011e10f 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CChunk.java @@ -88,9 +88,7 @@ public class CChunk implements CustomCropsChunk { @Override public void notifyOfflineUpdates() { - long delta = this.lastLoadedTime - System.currentTimeMillis(); - int seconds = (int) (delta / 1000); - + this.lastLoadedTime = System.currentTimeMillis(); } public void setWorld(CWorld cWorld) { diff --git a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java index 015e402..c3a726a 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java +++ b/plugin/src/main/java/net/momirealms/customcrops/mechanic/world/CWorld.java @@ -94,8 +94,10 @@ public class CWorld implements CustomCropsWorld { if (setting.isAutoSeasonChange()) { this.updateSeasonAndDate(); } - for (CChunk chunk : loadedChunks.values()) { - chunk.secondTimer(); + if (setting.isSchedulerEnabled()) { + for (CChunk chunk : loadedChunks.values()) { + chunk.secondTimer(); + } } } diff --git a/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java b/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java index 5ee4bd2..ba5af1e 100644 --- a/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java +++ b/plugin/src/main/java/net/momirealms/customcrops/utils/ConfigUtils.java @@ -328,6 +328,7 @@ public class ConfigUtils { innerSection.getInt("item-amount",1), innerSection.getString("return"), innerSection.getInt("return-amount",1), + innerSection.getBoolean("dispenser",true), getIntChancePair(innerSection.getConfigurationSection("chance")), getActions(innerSection.getConfigurationSection("actions")) ); diff --git a/plugin/src/main/resources/contents/crops/default.yml b/plugin/src/main/resources/contents/crops/default.yml index 3f993fa..1bc252b 100644 --- a/plugin/src/main/resources/contents/crops/default.yml +++ b/plugin/src/main/resources/contents/crops/default.yml @@ -259,6 +259,8 @@ tomato: custom-bone-meal: bone_meal_1: item: BONE_MEAL + # Allow to be used with dispenser + dispenser: true chance: 2: 0.2 1: 0.6