aboutsummaryrefslogtreecommitdiffstats
path: root/bukkit
diff options
context:
space:
mode:
authorKrakenied <krakenied1@gmail.com>2025-12-15 23:59:34 +0100
committerKrakenied <46192742+Krakenied@users.noreply.github.com>2026-01-15 07:05:55 +0100
commited2e2039ca836d9b69c147aec2b5792f2b76895b (patch)
tree05234c5a965010d2457ef983ac5048932b89d557 /bukkit
parent03cbd00fe232e4dbe27cde854bba0af376802bb2 (diff)
New blockchanging task type
Closes https://github.com/LMBishop/Quests/issues/831
Diffstat (limited to 'bukkit')
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java2
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BlockchangingTaskType.java136
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java19
3 files changed, 154 insertions, 3 deletions
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
index 586ba55d..434b0752 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
@@ -67,6 +67,7 @@ import com.leonardobishop.quests.bukkit.storage.ModernYAMLStorageProvider;
import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskTypeManager;
import com.leonardobishop.quests.bukkit.tasktype.type.BarteringTaskType;
import com.leonardobishop.quests.bukkit.tasktype.type.BlockItemdroppingTaskType;
+import com.leonardobishop.quests.bukkit.tasktype.type.BlockchangingTaskType;
import com.leonardobishop.quests.bukkit.tasktype.type.BlockfertilizingTaskType;
import com.leonardobishop.quests.bukkit.tasktype.type.BlockshearingTaskType;
import com.leonardobishop.quests.bukkit.tasktype.type.BreedingTaskType;
@@ -487,6 +488,7 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
// Register task types with class/method compatibility requirement
taskTypeManager.registerTaskType(() -> new BarteringTaskType(this), () -> CompatUtils.classExists("org.bukkit.event.entity.PiglinBarterEvent"));
taskTypeManager.registerTaskType(() -> new BlockItemdroppingTaskType(this), () -> CompatUtils.classExists("org.bukkit.event.block.BlockDropItemEvent"));
+ taskTypeManager.registerTaskType(() -> new BlockchangingTaskType(this), () -> CompatUtils.classWithMethodExists("org.bukkit.event.entity.EntityChangeBlockEvent", "getBlockData"));
taskTypeManager.registerTaskType(() -> new BlockfertilizingTaskType(this), () -> CompatUtils.classExists("org.bukkit.event.block.BlockFertilizeEvent"));
taskTypeManager.registerTaskType(() -> new BlockshearingTaskType(this), () -> CompatUtils.classExists("io.papermc.paper.event.block.PlayerShearBlockEvent"));
taskTypeManager.registerTaskType(() -> new BrewingTaskType(this), () -> CompatUtils.classWithMethodExists("org.bukkit.event.inventory.BrewEvent", "getResults"));
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BlockchangingTaskType.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BlockchangingTaskType.java
new file mode 100644
index 00000000..7fc1dd26
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/tasktype/type/BlockchangingTaskType.java
@@ -0,0 +1,136 @@
+package com.leonardobishop.quests.bukkit.tasktype.type;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.leonardobishop.quests.bukkit.hook.coreprotect.AbstractCoreProtectHook;
+import com.leonardobishop.quests.bukkit.hook.playerblocktracker.AbstractPlayerBlockTrackerHook;
+import com.leonardobishop.quests.bukkit.tasktype.BukkitTaskType;
+import com.leonardobishop.quests.bukkit.util.TaskUtils;
+import com.leonardobishop.quests.bukkit.util.constraint.TaskConstraintSet;
+import com.leonardobishop.quests.common.player.QPlayer;
+import com.leonardobishop.quests.common.player.questprogressfile.TaskProgress;
+import com.leonardobishop.quests.common.quest.Quest;
+import com.leonardobishop.quests.common.quest.Task;
+import org.bukkit.block.Block;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.entity.EntityChangeBlockEvent;
+import org.jetbrains.annotations.NotNull;
+
+public final class BlockchangingTaskType extends BukkitTaskType {
+
+ private final BukkitQuestsPlugin plugin;
+
+ public BlockchangingTaskType(final @NotNull BukkitQuestsPlugin plugin) {
+ super("blockchanging", TaskUtils.TASK_ATTRIBUTION_STRING, "Change a set amount of certain blocks.");
+ this.plugin = plugin;
+
+ super.addConfigValidator(TaskUtils.useRequiredConfigValidator(this, "amount"));
+ super.addConfigValidator(TaskUtils.useIntegerConfigValidator(this, "amount"));
+ super.addConfigValidator(TaskUtils.useMaterialListConfigValidator(this, TaskUtils.MaterialListConfigValidatorMode.BLOCK, "from", "froms"));
+ super.addConfigValidator(TaskUtils.useMaterialListConfigValidator(this, TaskUtils.MaterialListConfigValidatorMode.BLOCK, "to", "tos"));
+ super.addConfigValidator(TaskUtils.useBooleanConfigValidator(this, "check-playerblocktracker"));
+ super.addConfigValidator(TaskUtils.useBooleanConfigValidator(this, "check-coreprotect"));
+ super.addConfigValidator(TaskUtils.useIntegerConfigValidator(this, "check-coreprotect-time"));
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
+ public void onEntityChangeBlock(final @NotNull EntityChangeBlockEvent event) {
+ Entity entity = event.getEntity();
+ if (!(entity instanceof Player player) || player.hasMetadata("NPC")) {
+ return;
+ }
+
+ QPlayer qPlayer = plugin.getPlayerManager().getPlayer(player.getUniqueId());
+ if (qPlayer == null) {
+ return;
+ }
+
+ Block from = event.getBlock();
+ BlockData toData = event.getBlockData();
+
+ for (TaskUtils.PendingTask pendingTask : TaskUtils.getApplicableTasks(player, qPlayer, this, TaskConstraintSet.ALL)) {
+ Quest quest = pendingTask.quest();
+ Task task = pendingTask.task();
+ TaskProgress taskProgress = pendingTask.taskProgress();
+
+ super.debug("Player changed a block, from block is " + from.getType() + ", to block is " + event.getTo(), quest.getId(), task.getId(), player.getUniqueId());
+
+ if (!TaskUtils.matchBlock(this, pendingTask, from, player.getUniqueId(), "from", "froms")) {
+ super.debug("Continuing...", quest.getId(), task.getId(), player.getUniqueId());
+ continue;
+ }
+
+ if (!TaskUtils.matchBlock(this, pendingTask, toData, player.getUniqueId(), "to", "tos")) {
+ super.debug("Continuing...", quest.getId(), task.getId(), player.getUniqueId());
+ continue;
+ }
+
+ boolean playerBlockTrackerEnabled = TaskUtils.getConfigBoolean(task, "check-playerblocktracker");
+
+ if (playerBlockTrackerEnabled) {
+ AbstractPlayerBlockTrackerHook playerBlockTrackerHook = plugin.getPlayerBlockTrackerHook();
+ if (playerBlockTrackerHook != null) {
+ super.debug("Running PlayerBlockTracker lookup", quest.getId(), task.getId(), player.getUniqueId());
+
+ boolean result = playerBlockTrackerHook.checkBlock(from);
+ if (result) {
+ super.debug("PlayerBlockTracker lookup indicates this is a player placed block, continuing...", quest.getId(), task.getId(), player.getUniqueId());
+ continue;
+ }
+
+ super.debug("PlayerBlockTracker lookup OK", quest.getId(), task.getId(), player.getUniqueId());
+ } else {
+ super.debug("check-playerblocktracker is enabled, but PlayerBlockTracker is not detected on the server", quest.getId(), task.getId(), player.getUniqueId());
+ continue; // we want to prevent progressing in quest if PBT failed to start and was expected to
+ }
+ }
+
+ Runnable increment = () -> {
+ int progress = TaskUtils.incrementIntegerTaskProgress(taskProgress);
+ super.debug("Incrementing task progress (now " + progress + ")", quest.getId(), task.getId(), player.getUniqueId());
+
+ int amount = (int) task.getConfigValue("amount");
+ if (progress >= amount) {
+ super.debug("Marking task as complete", quest.getId(), task.getId(), player.getUniqueId());
+ taskProgress.setCompleted(true);
+ }
+
+ TaskUtils.sendTrackAdvancement(player, quest, task, pendingTask, amount);
+ };
+
+ boolean coreProtectEnabled = TaskUtils.getConfigBoolean(task, "check-coreprotect");
+ int coreProtectTime = (int) task.getConfigValue("check-coreprotect-time", 3600);
+
+ if (coreProtectEnabled) {
+ AbstractCoreProtectHook coreProtectHook = plugin.getCoreProtectHook();
+ if (coreProtectHook != null) {
+ super.debug("Running CoreProtect lookup (may take a while)", quest.getId(), task.getId(), player.getUniqueId());
+
+ // Run CoreProtect lookup
+ plugin.getCoreProtectHook().checkBlock(from, coreProtectTime).thenAccept(result -> {
+ if (result) {
+ super.debug("CoreProtect lookup indicates this is a player placed block, continuing...", quest.getId(), task.getId(), player.getUniqueId());
+ } else {
+ super.debug("CoreProtect lookup OK", quest.getId(), task.getId(), player.getUniqueId());
+ increment.run();
+ }
+ }).exceptionally(throwable -> {
+ super.debug("CoreProtect lookup failed: " + throwable.getMessage(), quest.getId(), task.getId(), player.getUniqueId());
+ throwable.printStackTrace();
+ return null;
+ });
+
+ continue;
+ }
+
+ super.debug("check-coreprotect is enabled, but CoreProtect is not detected on the server", quest.getId(), task.getId(), player.getUniqueId());
+ continue; // we want to prevent progressing in quest if CoreProtect failed to start and was expected to
+ }
+
+ increment.run();
+ }
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java
index 5594211f..4feb2628 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/TaskUtils.java
@@ -22,6 +22,7 @@ import org.bukkit.Material;
import org.bukkit.block.Biome;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
+import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
@@ -40,6 +41,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
+import java.util.function.Supplier;
@SuppressWarnings({"deprecation", "BooleanMethodIsAlwaysInverted"})
public class TaskUtils {
@@ -329,23 +331,34 @@ public class TaskUtils {
return matchBlock(type, pendingTask, block != null ? block.getState() : null, player, stringKey, listKey);
}
+ public static boolean matchBlock(@NotNull BukkitTaskType type, @NotNull PendingTask pendingTask, @Nullable BlockData data, @NotNull UUID player) {
+ return matchBlock(type, pendingTask, data, player, "block", "blocks");
+ }
+
+ public static boolean matchBlock(@NotNull BukkitTaskType type, @NotNull PendingTask pendingTask, @Nullable BlockData data, @NotNull UUID player, @NotNull String stringKey, @NotNull String listKey) {
+ return matchBlock(type, pendingTask, data != null ? data.getMaterial() : null, () -> (byte) 0, player, stringKey, listKey);
+ }
+
public static boolean matchBlock(@NotNull BukkitTaskType type, @NotNull PendingTask pendingTask, @Nullable BlockState state, @NotNull UUID player) {
return matchBlock(type, pendingTask, state, player, "block", "blocks");
}
public static boolean matchBlock(@NotNull BukkitTaskType type, @NotNull PendingTask pendingTask, @Nullable BlockState state, @NotNull UUID player, @NotNull String stringKey, @NotNull String listKey) {
+ return matchBlock(type, pendingTask, state != null ? state.getType() : null, () -> state.getRawData(), player, stringKey, listKey);
+ }
+
+ public static boolean matchBlock(@NotNull BukkitTaskType type, @NotNull PendingTask pendingTask, @Nullable Material blockMaterial, @NotNull Supplier<Byte> rawDataSupplier, @NotNull UUID player, @NotNull String stringKey, @NotNull String listKey) {
Task task = pendingTask.task;
List<String> checkBlocks = TaskUtils.getConfigStringList(task, task.getConfigValues().containsKey(stringKey) ? stringKey : listKey);
if (checkBlocks == null) {
return true;
} else if (checkBlocks.isEmpty()) {
- return state == null;
+ return blockMaterial == null;
}
Object configData = task.getConfigValue("data");
- Material blockMaterial = state.getType();
// do not set block data here as it will initialize Legacy Material Support
Byte blockData = null;
@@ -374,7 +387,7 @@ public class TaskUtils {
// delay legacy material support initialization
if (blockData == null) {
- blockData = state.getRawData();
+ blockData = rawDataSupplier.get();
}
if (blockData == comparableData) {