diff options
| author | Krakenied <krakenied1@gmail.com> | 2025-12-15 23:59:34 +0100 |
|---|---|---|
| committer | Krakenied <46192742+Krakenied@users.noreply.github.com> | 2026-01-15 07:05:55 +0100 |
| commit | ed2e2039ca836d9b69c147aec2b5792f2b76895b (patch) | |
| tree | 05234c5a965010d2457ef983ac5048932b89d557 /bukkit | |
| parent | 03cbd00fe232e4dbe27cde854bba0af376802bb2 (diff) | |
New blockchanging task type
Closes https://github.com/LMBishop/Quests/issues/831
Diffstat (limited to 'bukkit')
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) { |
