Improved block tracking by @IllusionTheDev (#2270)

* Initial support for modern block tracking

* Use BlockItemStack for other block events

* Change internals to use BlockItemStack

* Update types and compare

* legacy block data support

* Fix item name translation

* Remove unused imports and cleanup

* Blocks do not have display names

* help I accidentally ran the auto formatter

* Cast the correct value

* Tiny format

* Use correct goal object

---------

Co-authored-by: Illusion <imdatillusion@gmail.com>
This commit is contained in:
PikaMug 2024-07-30 22:24:34 -04:00 committed by GitHub
parent 70119ad4ab
commit c9d77d5708
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 663 additions and 284 deletions

View File

@ -15,6 +15,7 @@ import me.pikamug.quests.quests.components.Stage;
import me.pikamug.quests.quests.components.Objective; import me.pikamug.quests.quests.components.Objective;
import me.pikamug.quests.enums.ObjectiveType; import me.pikamug.quests.enums.ObjectiveType;
import me.pikamug.quests.module.CustomObjective; import me.pikamug.quests.module.CustomObjective;
import me.pikamug.quests.util.stack.BlockItemStack;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
@ -145,16 +146,31 @@ public interface Quester extends Comparable<Quester> {
void showCurrentConditions(final Quest quest, final Quester quester); void showCurrentConditions(final Quest quest, final Quester quester);
@Deprecated
void breakBlock(final Quest quest, final ItemStack itemStack); void breakBlock(final Quest quest, final ItemStack itemStack);
void breakBlock(final Quest quest, final BlockItemStack blockItemStack);
@Deprecated
void damageBlock(final Quest quest, final ItemStack itemStack); void damageBlock(final Quest quest, final ItemStack itemStack);
void damageBlock(final Quest quest, final BlockItemStack blockItemStack);
@Deprecated
void placeBlock(final Quest quest, final ItemStack itemStack); void placeBlock(final Quest quest, final ItemStack itemStack);
void placeBlock(final Quest quest, final BlockItemStack blockItemStack);
@Deprecated
void useBlock(final Quest quest, final ItemStack itemStack); void useBlock(final Quest quest, final ItemStack itemStack);
void useBlock(final Quest quest, final BlockItemStack blockItemStack);
@Deprecated
void cutBlock(final Quest quest, final ItemStack itemStack); void cutBlock(final Quest quest, final ItemStack itemStack);
void cutBlock(final Quest quest, final BlockItemStack blockItemStack);
void craftItem(final Quest quest, final ItemStack itemStack); void craftItem(final Quest quest, final ItemStack itemStack);
void smeltItem(final Quest quest, final ItemStack itemStack); void smeltItem(final Quest quest, final ItemStack itemStack);

View File

@ -0,0 +1,39 @@
package me.pikamug.quests.util.stack;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.inventory.ItemStack;
public interface BlockItemStack {
static BlockItemStack of(final ItemStack original) {
if (original == null) {
return null;
}
return of(original.getType(), original.getAmount(), original.getDurability());
}
static BlockItemStack of(final Block block) {
return BlockItemStacks.getFactory().of(block);
}
static BlockItemStack of(final Material type, final int amount, final short durability) {
return BlockItemStacks.getFactory().of(type, amount, durability);
}
static BlockItemStack clone(final BlockItemStack original, final int amount) {
return BlockItemStacks.getFactory().clone(original, amount);
}
static BlockItemStack clone(final BlockItemStack original, final int amount, final short durability) {
return BlockItemStacks.getFactory().clone(original, amount, durability);
}
Material getType();
int getAmount();
short getDurability();
boolean matches(BlockItemStack other);
}

View File

@ -0,0 +1,12 @@
package me.pikamug.quests.util.stack;
import org.bukkit.Material;
import org.bukkit.block.Block;
public interface BlockItemStackFactory {
BlockItemStack of(final Block block);
BlockItemStack of(final Material type, final int amount, final short durability);
BlockItemStack clone(final BlockItemStack original, final int amount);
BlockItemStack clone(final BlockItemStack original, final int amount, final short durability);
}

View File

@ -0,0 +1,32 @@
package me.pikamug.quests.util.stack;
import me.pikamug.quests.util.stack.impl.LegacyBlockItemStack;
import me.pikamug.quests.util.stack.impl.ModernBlockItemStack;
public final class BlockItemStacks {
private BlockItemStacks() {
}
private static BlockItemStackFactory factory;
public static BlockItemStackFactory getFactory() {
return factory;
}
private static void setFactory(final BlockItemStackFactory factory) {
if (BlockItemStacks.factory != null) {
throw new IllegalStateException("Factory is already set");
}
BlockItemStacks.factory = factory;
}
public static void init(final boolean modern) {
if (modern) {
setFactory(ModernBlockItemStack.FACTORY);
} else {
setFactory(LegacyBlockItemStack.FACTORY);
}
}
}

View File

@ -0,0 +1,90 @@
package me.pikamug.quests.util.stack.impl;
import me.pikamug.quests.util.stack.BlockItemStack;
import me.pikamug.quests.util.stack.BlockItemStackFactory;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.material.MaterialData;
@SuppressWarnings("deprecation")
public class LegacyBlockItemStack implements BlockItemStack {
public static final BlockItemStackFactory FACTORY = new Factory();
private final MaterialData materialData;
private int amount;
private LegacyBlockItemStack(final MaterialData materialData, final int amount) {
this.materialData = materialData;
this.amount = amount;
}
public MaterialData getMaterialData() {
return materialData;
}
@Override
public int getAmount() {
return amount;
}
@Override
public short getDurability() {
return materialData.getData();
}
@Override
public Material getType() {
return materialData.getItemType();
}
@Override
public boolean matches(BlockItemStack other) {
if (other == null) {
return false;
}
final MaterialData blockData = Factory.getBlockData(other);
return this.materialData.equals(blockData) && (getDurability() == 0 || getDurability() == other.getDurability());
}
public void setAmount(int amount) {
this.amount = amount;
}
public static class Factory implements BlockItemStackFactory {
@Override
public BlockItemStack of(final Block block) {
final MaterialData data = block.getState().getData();
return new LegacyBlockItemStack(data, 1);
}
@Override
public BlockItemStack of(final Material type, final int amount, final short durability) {
final MaterialData data = type.getNewData((byte) durability);
return new LegacyBlockItemStack(data, amount);
}
@Override
public BlockItemStack clone(final BlockItemStack original, final int amount) {
final MaterialData data = getBlockData(original);
return new LegacyBlockItemStack(data, amount);
}
@Override
public BlockItemStack clone(final BlockItemStack original, final int amount, final short durability) {
final MaterialData data = getBlockData(original);
data.setData((byte) durability);
return new LegacyBlockItemStack(data, amount);
}
private static MaterialData getBlockData(final BlockItemStack stack) {
if (stack instanceof LegacyBlockItemStack) {
return ((LegacyBlockItemStack)stack).materialData;
}
return stack.getType().getNewData((byte) stack.getDurability());
}
}
}

View File

@ -0,0 +1,103 @@
package me.pikamug.quests.util.stack.impl;
import me.pikamug.quests.util.stack.BlockItemStack;
import me.pikamug.quests.util.stack.BlockItemStackFactory;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Powerable;
public class ModernBlockItemStack implements BlockItemStack {
public static final BlockItemStackFactory FACTORY = new Factory();
private final BlockData blockData;
private int amount;
private final short durability;
private ModernBlockItemStack(final BlockData blockData, final int amount, final short durability) {
this.blockData = blockData;
this.amount = amount;
this.durability = durability;
}
private static short getDurability(BlockData data) {
if (data instanceof Ageable) {
return (short) ((Ageable)data).getAge();
}
if (data instanceof Powerable) {
return (short) (((Powerable)data).isPowered() ? 1 : 0);
}
return 0;
}
public BlockData getBlockData() {
return blockData;
}
@Override
public int getAmount() {
return amount;
}
@Override
public short getDurability() {
return durability;
}
@Override
public Material getType() {
return blockData.getMaterial();
}
@Override
public boolean matches(BlockItemStack other) {
if (other == null) {
return false;
}
final BlockData blockData = Factory.getBlockData(other);
return this.blockData.matches(blockData) && (durability == 0 || durability == other.getDurability());
}
public void setAmount(int amount) {
this.amount = amount;
}
public static class Factory implements BlockItemStackFactory {
@Override
public BlockItemStack of(final Block block) {
return new ModernBlockItemStack(block.getBlockData(), 1, getDurability(block.getBlockData()));
}
@Override
public BlockItemStack of(final Material type, final int amount, final short durability) {
return new ModernBlockItemStack(type.createBlockData(), amount, durability);
}
@Override
public BlockItemStack clone(final BlockItemStack original, final int amount) {
final BlockData data = getBlockData(original);
return new ModernBlockItemStack(data, amount, original.getDurability());
}
@Override
public BlockItemStack clone(final BlockItemStack original, final int amount, final short durability) {
final BlockData data = getBlockData(original);
return new ModernBlockItemStack(data, amount, durability);
}
private static BlockData getBlockData(final BlockItemStack stack) {
if (stack instanceof ModernBlockItemStack) {
return ((ModernBlockItemStack)stack).getBlockData();
}
return stack.getType().createBlockData();
}
}
}

View File

@ -53,6 +53,7 @@ import me.pikamug.quests.tasks.BukkitNpcEffectThread;
import me.pikamug.quests.tasks.BukkitPlayerMoveThread; import me.pikamug.quests.tasks.BukkitPlayerMoveThread;
import me.pikamug.quests.util.BukkitLang; import me.pikamug.quests.util.BukkitLang;
import me.pikamug.quests.util.BukkitUpdateChecker; import me.pikamug.quests.util.BukkitUpdateChecker;
import me.pikamug.quests.util.stack.BlockItemStacks;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
@ -143,9 +144,11 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
try { try {
Class.forName("me.pikamug.quests.libs.localelib.LocaleManager"); Class.forName("me.pikamug.quests.libs.localelib.LocaleManager");
localeManager = new LocaleManager(); localeManager = new LocaleManager();
BlockItemStacks.init(!localeManager.isBelow113());
} catch (final Exception ignored) { } catch (final Exception ignored) {
getLogger().warning("LocaleLib not present! Is this a debug environment?"); getLogger().warning("LocaleLib not present! Is this a debug environment?");
} }
convoListener = new BukkitConvoListener(); convoListener = new BukkitConvoListener();
blockListener = new BukkitBlockListener(this); blockListener = new BukkitBlockListener(this);
itemListener = new BukkitItemListener(this); itemListener = new BukkitItemListener(this);

View File

@ -22,7 +22,7 @@ import me.pikamug.quests.player.Quester;
import me.pikamug.quests.quests.Quest; import me.pikamug.quests.quests.Quest;
import me.pikamug.quests.quests.components.BukkitObjective; import me.pikamug.quests.quests.components.BukkitObjective;
import me.pikamug.quests.quests.components.BukkitStage; import me.pikamug.quests.quests.components.BukkitStage;
import me.pikamug.quests.util.BukkitItemUtil; import me.pikamug.quests.util.stack.BlockItemStack;
import me.pikamug.quests.util.BukkitLang; import me.pikamug.quests.util.BukkitLang;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Material; import org.bukkit.Material;
@ -61,10 +61,8 @@ public class BukkitBlockListener implements Listener {
} }
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (plugin.canUseQuests(player.getUniqueId())) { if (plugin.canUseQuests(player.getUniqueId())) {
final ItemStack blockItemStack = getItemEquivalent(event.getBlock()); final BlockItemStack blockItem = BlockItemStack.of(event.getBlock());
if (blockItemStack == null) {
return;
}
final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); final BukkitQuester quester = plugin.getQuester(player.getUniqueId());
final ObjectiveType breakType = ObjectiveType.BREAK_BLOCK; final ObjectiveType breakType = ObjectiveType.BREAK_BLOCK;
final ObjectiveType placeType = ObjectiveType.PLACE_BLOCK; final ObjectiveType placeType = ObjectiveType.PLACE_BLOCK;
@ -89,12 +87,12 @@ public class BukkitBlockListener implements Listener {
BukkitActionBarProvider.sendActionBar(player, ChatColor.RED + BukkitLang BukkitActionBarProvider.sendActionBar(player, ChatColor.RED + BukkitLang
.get(player, "optionSilkTouchFail").replace("<quest>", quest.getName())); .get(player, "optionSilkTouchFail").replace("<quest>", quest.getName()));
} else { } else {
quester.breakBlock(quest, blockItemStack); quester.breakBlock(quest, blockItem);
dispatchedBreakQuestIDs.addAll(quester.dispatchMultiplayerEverything(quest, breakType, dispatchedBreakQuestIDs.addAll(quester.dispatchMultiplayerEverything(quest, breakType,
(final Quester q, final Quest cq) -> { (final Quester q, final Quest cq) -> {
if (!dispatchedBreakQuestIDs.contains(cq.getId())) { if (!dispatchedBreakQuestIDs.contains(cq.getId())) {
q.breakBlock(cq, blockItemStack); q.breakBlock(cq, blockItem);
} }
return null; return null;
})); }));
@ -109,11 +107,11 @@ public class BukkitBlockListener implements Listener {
if (progress < 0) { if (progress < 0) {
break; break;
} }
final ItemStack is = currentStage.getBlocksToPlace().get(i); final BlockItemStack is = currentStage.getBlocksToPlace().get(i);
if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) { if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) {
ItemStack goal = new ItemStack(is.getType(), 64); BlockItemStack goal = BlockItemStack.clone(is, 64);
for (final ItemStack stack : currentStage.getBlocksToPlace()) { for (final BlockItemStack stack : currentStage.getBlocksToPlace()) {
if (BukkitItemUtil.compareItems(is, stack, true) == 0) { if (stack.matches(goal)) {
goal = stack; goal = stack;
} }
} }
@ -142,11 +140,11 @@ public class BukkitBlockListener implements Listener {
if (progress < 0) { if (progress < 0) {
break; break;
} }
final ItemStack is = currentStage.getBlocksToPlace().get(i); final BlockItemStack is = currentStage.getBlocksToPlace().get(i);
if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) { if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) {
ItemStack goal = new ItemStack(is.getType(), 64); BlockItemStack goal = BlockItemStack.clone(is, 64);
for (final ItemStack stack : ((BukkitStage) quester.getCurrentStage(cq)).getBlocksToPlace()) { for (final BlockItemStack stack : ((BukkitStage) quester.getCurrentStage(cq)).getBlocksToPlace()) {
if (BukkitItemUtil.compareItems(is, stack, true) == 0) { if (stack.matches(goal)) {
goal = stack; goal = stack;
} }
} }
@ -170,14 +168,14 @@ public class BukkitBlockListener implements Listener {
} }
if (currentStage.containsObjective(cutType)) { if (currentStage.containsObjective(cutType)) {
if (player.getItemInHand().getType().equals(Material.SHEARS)) { if (player.getItemInHand().getType().equals(Material.SHEARS)) {
quester.cutBlock(quest, blockItemStack); quester.cutBlock(quest, blockItem);
} }
} }
dispatchedCutQuestIDs.addAll(quester.dispatchMultiplayerEverything(quest, cutType, dispatchedCutQuestIDs.addAll(quester.dispatchMultiplayerEverything(quest, cutType,
(final Quester q, final Quest cq) -> { (final Quester q, final Quest cq) -> {
if (!dispatchedCutQuestIDs.contains(cq.getId())) { if (!dispatchedCutQuestIDs.contains(cq.getId())) {
if (player.getItemInHand().getType().equals(Material.SHEARS)) { if (player.getItemInHand().getType().equals(Material.SHEARS)) {
q.cutBlock(cq, blockItemStack); q.cutBlock(cq, blockItem);
} }
} }
return null; return null;
@ -195,10 +193,8 @@ public class BukkitBlockListener implements Listener {
} }
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (plugin.canUseQuests(player.getUniqueId())) { if (plugin.canUseQuests(player.getUniqueId())) {
final ItemStack blockItemStack = getItemEquivalent(event.getBlock()); final BlockItemStack blockItemStack = BlockItemStack.of(event.getBlock());
if (blockItemStack == null) {
return;
}
final Quester quester = plugin.getQuester(player.getUniqueId()); final Quester quester = plugin.getQuester(player.getUniqueId());
final ObjectiveType type = ObjectiveType.DAMAGE_BLOCK; final ObjectiveType type = ObjectiveType.DAMAGE_BLOCK;
final Set<String> dispatchedQuestIDs = new HashSet<>(); final Set<String> dispatchedQuestIDs = new HashSet<>();
@ -231,10 +227,8 @@ public class BukkitBlockListener implements Listener {
} }
final Player player = event.getPlayer(); final Player player = event.getPlayer();
if (plugin.canUseQuests(player.getUniqueId())) { if (plugin.canUseQuests(player.getUniqueId())) {
final ItemStack blockItemStack = getItemEquivalent(event.getBlock()); final BlockItemStack blockItemStack = BlockItemStack.of(event.getBlock());
if (blockItemStack == null) {
return;
}
final BukkitQuester quester = plugin.getQuester(player.getUniqueId()); final BukkitQuester quester = plugin.getQuester(player.getUniqueId());
final ObjectiveType placeType = ObjectiveType.PLACE_BLOCK; final ObjectiveType placeType = ObjectiveType.PLACE_BLOCK;
final ObjectiveType breakType = ObjectiveType.BREAK_BLOCK; final ObjectiveType breakType = ObjectiveType.BREAK_BLOCK;
@ -261,11 +255,11 @@ public class BukkitBlockListener implements Listener {
if (progress < 0) { if (progress < 0) {
break; break;
} }
final ItemStack is = currentStage.getBlocksToBreak().get(i); final BlockItemStack is = currentStage.getBlocksToBreak().get(i);
if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) { if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) {
ItemStack goal = new ItemStack(is.getType(), 64); BlockItemStack goal = BlockItemStack.clone(is, 64);
for (final ItemStack stack : currentStage.getBlocksToBreak()) { for (final BlockItemStack stack : currentStage.getBlocksToBreak()) {
if (BukkitItemUtil.compareItems(is, stack, true) == 0) { if (stack.matches(goal)) {
goal = stack; goal = stack;
} }
} }
@ -294,11 +288,11 @@ public class BukkitBlockListener implements Listener {
if (progress < 0) { if (progress < 0) {
break; break;
} }
final ItemStack is = currentStage.getBlocksToBreak().get(i); final BlockItemStack is = currentStage.getBlocksToBreak().get(i);
if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) { if (event.getBlock().getType().equals(is.getType()) && is.getAmount() > 0) {
ItemStack goal = new ItemStack(is.getType(), 64); BlockItemStack goal = BlockItemStack.clone(is, 64);
for (final ItemStack stack : ((BukkitStage) quester.getCurrentStage(cq)).getBlocksToBreak()) { for (final BlockItemStack stack : ((BukkitStage) quester.getCurrentStage(cq)).getBlocksToBreak()) {
if (BukkitItemUtil.compareItems(is, stack, true) == 0) { if (stack.matches(goal)) {
goal = stack; goal = stack;
} }
} }
@ -354,10 +348,8 @@ public class BukkitBlockListener implements Listener {
} }
if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { if (event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
if (!event.isCancelled() && event.getClickedBlock() != null) { if (!event.isCancelled() && event.getClickedBlock() != null) {
final ItemStack blockItemStack = getItemEquivalent(event.getClickedBlock()); final BlockItemStack blockItemStack = BlockItemStack.of(event.getClickedBlock());
if (blockItemStack == null) {
return;
}
final ObjectiveType type = ObjectiveType.USE_BLOCK; final ObjectiveType type = ObjectiveType.USE_BLOCK;
final Set<String> dispatchedQuestIDs = new HashSet<>(); final Set<String> dispatchedQuestIDs = new HashSet<>();
for (final Quest quest : plugin.getLoadedQuests()) { for (final Quest quest : plugin.getLoadedQuests()) {

View File

@ -22,6 +22,7 @@ import me.pikamug.quests.quests.components.Planner;
import me.pikamug.quests.quests.components.Requirements; import me.pikamug.quests.quests.components.Requirements;
import me.pikamug.quests.quests.components.Rewards; import me.pikamug.quests.quests.components.Rewards;
import me.pikamug.quests.quests.components.Stage; import me.pikamug.quests.quests.components.Stage;
import me.pikamug.quests.util.stack.BlockItemStack;
import me.pikamug.quests.util.BukkitConfigUtil; import me.pikamug.quests.util.BukkitConfigUtil;
import me.pikamug.quests.util.BukkitFakeConversable; import me.pikamug.quests.util.BukkitFakeConversable;
import me.pikamug.quests.util.BukkitLang; import me.pikamug.quests.util.BukkitLang;
@ -303,7 +304,7 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
final LinkedList<String> names = new LinkedList<>(); final LinkedList<String> names = new LinkedList<>();
final LinkedList<Integer> amounts = new LinkedList<>(); final LinkedList<Integer> amounts = new LinkedList<>();
final LinkedList<Short> durability = new LinkedList<>(); final LinkedList<Short> durability = new LinkedList<>();
for (final ItemStack e : bukkitStage.getBlocksToBreak()) { for (final BlockItemStack e : bukkitStage.getBlocksToBreak()) {
names.add(e.getType().name()); names.add(e.getType().name());
amounts.add(e.getAmount()); amounts.add(e.getAmount());
durability.add(e.getDurability()); durability.add(e.getDurability());
@ -316,7 +317,7 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
final LinkedList<String> names = new LinkedList<>(); final LinkedList<String> names = new LinkedList<>();
final LinkedList<Integer> amounts = new LinkedList<>(); final LinkedList<Integer> amounts = new LinkedList<>();
final LinkedList<Short> durability = new LinkedList<>(); final LinkedList<Short> durability = new LinkedList<>();
for (final ItemStack e : bukkitStage.getBlocksToDamage()) { for (final BlockItemStack e : bukkitStage.getBlocksToDamage()) {
names.add(e.getType().name()); names.add(e.getType().name());
amounts.add(e.getAmount()); amounts.add(e.getAmount());
durability.add(e.getDurability()); durability.add(e.getDurability());
@ -329,7 +330,7 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
final LinkedList<String> names = new LinkedList<>(); final LinkedList<String> names = new LinkedList<>();
final LinkedList<Integer> amounts = new LinkedList<>(); final LinkedList<Integer> amounts = new LinkedList<>();
final LinkedList<Short> durability = new LinkedList<>(); final LinkedList<Short> durability = new LinkedList<>();
for (final ItemStack e : bukkitStage.getBlocksToPlace()) { for (final BlockItemStack e : bukkitStage.getBlocksToPlace()) {
names.add(e.getType().name()); names.add(e.getType().name());
amounts.add(e.getAmount()); amounts.add(e.getAmount());
durability.add(e.getDurability()); durability.add(e.getDurability());
@ -342,7 +343,7 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
final LinkedList<String> names = new LinkedList<>(); final LinkedList<String> names = new LinkedList<>();
final LinkedList<Integer> amounts = new LinkedList<>(); final LinkedList<Integer> amounts = new LinkedList<>();
final LinkedList<Short> durability = new LinkedList<>(); final LinkedList<Short> durability = new LinkedList<>();
for (final ItemStack e : bukkitStage.getBlocksToUse()) { for (final BlockItemStack e : bukkitStage.getBlocksToUse()) {
names.add(e.getType().name()); names.add(e.getType().name());
amounts.add(e.getAmount()); amounts.add(e.getAmount());
durability.add(e.getDurability()); durability.add(e.getDurability());
@ -355,7 +356,7 @@ public class BukkitQuestFactory implements QuestFactory, ConversationAbandonedLi
final LinkedList<String> names = new LinkedList<>(); final LinkedList<String> names = new LinkedList<>();
final LinkedList<Integer> amounts = new LinkedList<>(); final LinkedList<Integer> amounts = new LinkedList<>();
final LinkedList<Short> durability = new LinkedList<>(); final LinkedList<Short> durability = new LinkedList<>();
for (final ItemStack e : bukkitStage.getBlocksToCut()) { for (final BlockItemStack e : bukkitStage.getBlocksToCut()) {
names.add(e.getType().name()); names.add(e.getType().name());
amounts.add(e.getAmount()); amounts.add(e.getAmount());
durability.add(e.getDurability()); durability.add(e.getDurability());

View File

@ -12,6 +12,7 @@ package me.pikamug.quests.quests.components;
import me.pikamug.quests.entity.BukkitCountableMob; import me.pikamug.quests.entity.BukkitCountableMob;
import me.pikamug.quests.enums.ObjectiveType; import me.pikamug.quests.enums.ObjectiveType;
import me.pikamug.quests.util.stack.BlockItemStack;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
@ -46,6 +47,8 @@ public class BukkitObjective implements Objective {
this.progress = ((BukkitCountableMob) progressObj).getCount(); this.progress = ((BukkitCountableMob) progressObj).getCount();
} else if (progressObj instanceof Integer) { } else if (progressObj instanceof Integer) {
this.progress = (int) progress; this.progress = (int) progress;
} else if (progressObj instanceof BlockItemStack) {
this.progress = ((BlockItemStack) progressObj).getAmount();
} else { } else {
this.progress = 0; this.progress = 0;
} }
@ -55,6 +58,8 @@ public class BukkitObjective implements Objective {
this.goal = ((BukkitCountableMob) goalObj).getCount(); this.goal = ((BukkitCountableMob) goalObj).getCount();
} else if (goalObj instanceof Integer) { } else if (goalObj instanceof Integer) {
this.goal = (int) goalObj; this.goal = (int) goalObj;
} else if (progressObj instanceof BlockItemStack) {
this.goal = ((BlockItemStack) progressObj).getAmount();
} else { } else {
this.goal = 0; this.goal = 0;
} }
@ -90,6 +95,10 @@ public class BukkitObjective implements Objective {
return goalObj; return goalObj;
} }
public @Nullable BlockItemStack getGoalAsBlockItem() {
return goalObj instanceof BlockItemStack ? (BlockItemStack) goalObj : null;
}
/** /**
* @deprecated Paper 1.21 builds do not allow ItemStack with 0 amount * @deprecated Paper 1.21 builds do not allow ItemStack with 0 amount
*/ */

View File

@ -14,7 +14,7 @@ import me.pikamug.quests.actions.Action;
import me.pikamug.quests.conditions.Condition; import me.pikamug.quests.conditions.Condition;
import me.pikamug.quests.enums.ObjectiveType; import me.pikamug.quests.enums.ObjectiveType;
import me.pikamug.quests.module.CustomObjective; import me.pikamug.quests.module.CustomObjective;
import me.pikamug.quests.quests.components.Stage; import me.pikamug.quests.util.stack.BlockItemStack;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
@ -30,11 +30,11 @@ import java.util.UUID;
public class BukkitStage implements Stage { public class BukkitStage implements Stage {
private LinkedList<ItemStack> blocksToBreak = new LinkedList<>(); private LinkedList<BlockItemStack> blocksToBreak = new LinkedList<>();
private LinkedList<ItemStack> blocksToDamage = new LinkedList<>(); private LinkedList<BlockItemStack> blocksToDamage = new LinkedList<>();
private LinkedList<ItemStack> blocksToPlace = new LinkedList<>(); private LinkedList<BlockItemStack> blocksToPlace = new LinkedList<>();
private LinkedList<ItemStack> blocksToUse = new LinkedList<>(); private LinkedList<BlockItemStack> blocksToUse = new LinkedList<>();
private LinkedList<ItemStack> blocksToCut = new LinkedList<>(); private LinkedList<BlockItemStack> blocksToCut = new LinkedList<>();
private LinkedList<ItemStack> itemsToCraft = new LinkedList<>(); private LinkedList<ItemStack> itemsToCraft = new LinkedList<>();
private LinkedList<ItemStack> itemsToSmelt = new LinkedList<>(); private LinkedList<ItemStack> itemsToSmelt = new LinkedList<>();
private LinkedList<ItemStack> itemsToEnchant = new LinkedList<>(); private LinkedList<ItemStack> itemsToEnchant = new LinkedList<>();
@ -137,63 +137,63 @@ public class BukkitStage implements Stage {
private final LinkedList<String> customObjectiveDisplays = new LinkedList<>(); private final LinkedList<String> customObjectiveDisplays = new LinkedList<>();
private final LinkedList<Entry<String, Object>> customObjectiveData = new LinkedList<>(); private final LinkedList<Entry<String, Object>> customObjectiveData = new LinkedList<>();
public LinkedList<ItemStack> getBlocksToBreak() { public LinkedList<BlockItemStack> getBlocksToBreak() {
return blocksToBreak; return blocksToBreak;
} }
public boolean addBlockToBreak(@NotNull ItemStack blockToBreak) { public boolean addBlockToBreak(@NotNull BlockItemStack blockToBreak) {
return blocksToBreak.add(blockToBreak); return blocksToBreak.add(blockToBreak);
} }
public void setBlocksToBreak(final LinkedList<ItemStack> blocksToBreak) { public void setBlocksToBreak(final LinkedList<BlockItemStack> blocksToBreak) {
this.blocksToBreak = blocksToBreak; this.blocksToBreak = blocksToBreak;
} }
public LinkedList<ItemStack> getBlocksToDamage() { public LinkedList<BlockItemStack> getBlocksToDamage() {
return blocksToDamage; return blocksToDamage;
} }
public boolean addBlockToDamage(@NotNull ItemStack blockToDamage) { public boolean addBlockToDamage(@NotNull BlockItemStack blockToDamage) {
return blocksToDamage.add(blockToDamage); return blocksToDamage.add(blockToDamage);
} }
public void setBlocksToDamage(final LinkedList<ItemStack> blocksToDamage) { public void setBlocksToDamage(final LinkedList<BlockItemStack> blocksToDamage) {
this.blocksToDamage = blocksToDamage; this.blocksToDamage = blocksToDamage;
} }
public LinkedList<ItemStack> getBlocksToPlace() { public LinkedList<BlockItemStack> getBlocksToPlace() {
return blocksToPlace; return blocksToPlace;
} }
public boolean addBlockToPlace(@NotNull ItemStack blockToPlace) { public boolean addBlockToPlace(@NotNull BlockItemStack blockToPlace) {
return blocksToPlace.add(blockToPlace); return blocksToPlace.add(blockToPlace);
} }
public void setBlocksToPlace(final LinkedList<ItemStack> blocksToPlace) { public void setBlocksToPlace(final LinkedList<BlockItemStack> blocksToPlace) {
this.blocksToPlace = blocksToPlace; this.blocksToPlace = blocksToPlace;
} }
public LinkedList<ItemStack> getBlocksToUse() { public LinkedList<BlockItemStack> getBlocksToUse() {
return blocksToUse; return blocksToUse;
} }
public boolean addBlockToUse(@NotNull ItemStack blockToUse) { public boolean addBlockToUse(@NotNull BlockItemStack blockToUse) {
return blocksToUse.add(blockToUse); return blocksToUse.add(blockToUse);
} }
public void setBlocksToUse(final LinkedList<ItemStack> blocksToUse) { public void setBlocksToUse(final LinkedList<BlockItemStack> blocksToUse) {
this.blocksToUse = blocksToUse; this.blocksToUse = blocksToUse;
} }
public LinkedList<ItemStack> getBlocksToCut() { public LinkedList<BlockItemStack> getBlocksToCut() {
return blocksToCut; return blocksToCut;
} }
public boolean addBlockToCut(@NotNull ItemStack blockToCut) { public boolean addBlockToCut(@NotNull BlockItemStack blockToCut) {
return blocksToCut.add(blockToCut); return blocksToCut.add(blockToCut);
} }
public void setBlocksToCut(final LinkedList<ItemStack> blocksToCut) { public void setBlocksToCut(final LinkedList<BlockItemStack> blocksToCut) {
this.blocksToCut = blocksToCut; this.blocksToCut = blocksToCut;
} }

View File

@ -16,6 +16,7 @@ import me.pikamug.quests.quests.components.BukkitStage;
import me.pikamug.quests.quests.components.Options; import me.pikamug.quests.quests.components.Options;
import me.pikamug.quests.quests.components.Planner; import me.pikamug.quests.quests.components.Planner;
import me.pikamug.quests.storage.implementation.QuestStorageImpl; import me.pikamug.quests.storage.implementation.QuestStorageImpl;
import me.pikamug.quests.util.stack.BlockItemStack;
import me.pikamug.quests.util.BukkitConfigUtil; import me.pikamug.quests.util.BukkitConfigUtil;
import me.pikamug.quests.util.BukkitItemUtil; import me.pikamug.quests.util.BukkitItemUtil;
import me.pikamug.quests.util.BukkitMiscUtil; import me.pikamug.quests.util.BukkitMiscUtil;
@ -877,12 +878,12 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
} }
for (int i = 0; i < breakNames.size(); i++) { for (int i = 0; i < breakNames.size(); i++) {
final String name = breakNames.get(i); final String name = breakNames.get(i);
final ItemStack is; final BlockItemStack is;
if (i < breakDurability.size() && breakDurability.get(i) != -1) { if (i < breakDurability.size() && breakDurability.get(i) != -1) {
is = BukkitItemUtil.processItemStack(name, breakAmounts.get(i), breakDurability.get(i)); is = BukkitItemUtil.processBlockItemStack(name, breakAmounts.get(i), breakDurability.get(i));
} else { } else {
// Legacy // Legacy
is = BukkitItemUtil.processItemStack(name, breakAmounts.get(i), (short) 0); is = BukkitItemUtil.processBlockItemStack(name, breakAmounts.get(i), (short) 0);
} }
if (is != null && Material.matchMaterial(name) != null) { if (is != null && Material.matchMaterial(name) != null) {
bukkitStage.addBlockToBreak(is); bukkitStage.addBlockToBreak(is);
@ -919,12 +920,12 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
} }
for (int i = 0; i < damageNames.size(); i++) { for (int i = 0; i < damageNames.size(); i++) {
final String name = damageNames.get(i); final String name = damageNames.get(i);
final ItemStack is; final BlockItemStack is;
if (i < damageDurability.size() && damageDurability.get(i) != -1) { if (i < damageDurability.size() && damageDurability.get(i) != -1) {
is = BukkitItemUtil.processItemStack(name, damageAmounts.get(i), damageDurability.get(i)); is = BukkitItemUtil.processBlockItemStack(name, damageAmounts.get(i), damageDurability.get(i));
} else { } else {
// Legacy // Legacy
is = BukkitItemUtil.processItemStack(name, damageAmounts.get(i), (short) 0); is = BukkitItemUtil.processBlockItemStack(name, damageAmounts.get(i), (short) 0);
} }
if (is != null && Material.matchMaterial(name) != null) { if (is != null && Material.matchMaterial(name) != null) {
bukkitStage.addBlockToDamage(is); bukkitStage.addBlockToDamage(is);
@ -960,12 +961,12 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
} }
for (int i = 0; i < placeNames.size(); i++) { for (int i = 0; i < placeNames.size(); i++) {
final String name = placeNames.get(i); final String name = placeNames.get(i);
final ItemStack is; final BlockItemStack is;
if (i < placeDurability.size() && placeDurability.get(i) != -1) { if (i < placeDurability.size() && placeDurability.get(i) != -1) {
is = BukkitItemUtil.processItemStack(name, placeAmounts.get(i), placeDurability.get(i)); is = BukkitItemUtil.processBlockItemStack(name, placeAmounts.get(i), placeDurability.get(i));
} else { } else {
// Legacy // Legacy
is = BukkitItemUtil.processItemStack(name, placeAmounts.get(i), (short) 0); is = BukkitItemUtil.processBlockItemStack(name, placeAmounts.get(i), (short) 0);
} }
if (is != null && Material.matchMaterial(name) != null) { if (is != null && Material.matchMaterial(name) != null) {
bukkitStage.addBlockToPlace(is); bukkitStage.addBlockToPlace(is);
@ -1001,12 +1002,12 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
} }
for (int i = 0; i < useNames.size(); i++) { for (int i = 0; i < useNames.size(); i++) {
final String name = useNames.get(i); final String name = useNames.get(i);
final ItemStack is; final BlockItemStack is;
if (i < useDurability.size() && useDurability.get(i) != -1) { if (i < useDurability.size() && useDurability.get(i) != -1) {
is = BukkitItemUtil.processItemStack(name, useAmounts.get(i), useDurability.get(i)); is = BukkitItemUtil.processBlockItemStack(name, useAmounts.get(i), useDurability.get(i));
} else { } else {
// Legacy // Legacy
is = BukkitItemUtil.processItemStack(name, useAmounts.get(i), (short) 0); is = BukkitItemUtil.processBlockItemStack(name, useAmounts.get(i), (short) 0);
} }
if (is != null && Material.matchMaterial(name) != null) { if (is != null && Material.matchMaterial(name) != null) {
bukkitStage.addBlockToUse(is); bukkitStage.addBlockToUse(is);
@ -1042,12 +1043,12 @@ public class BukkitQuestYamlStorage implements QuestStorageImpl {
} }
for (int i = 0; i < cutNames.size(); i++) { for (int i = 0; i < cutNames.size(); i++) {
final String name = cutNames.get(i); final String name = cutNames.get(i);
final ItemStack is; final BlockItemStack is;
if (i < cutDurability.size() && cutDurability.get(i) != -1) { if (i < cutDurability.size() && cutDurability.get(i) != -1) {
is = BukkitItemUtil.processItemStack(name, cutAmounts.get(i), cutDurability.get(i)); is = BukkitItemUtil.processBlockItemStack(name, cutAmounts.get(i), cutDurability.get(i));
} else { } else {
// Legacy // Legacy
is = BukkitItemUtil.processItemStack(name, cutAmounts.get(i), (short) 0); is = BukkitItemUtil.processBlockItemStack(name, cutAmounts.get(i), (short) 0);
} }
if (is != null && Material.matchMaterial(name) != null) { if (is != null && Material.matchMaterial(name) != null) {
bukkitStage.addBlockToCut(is); bukkitStage.addBlockToCut(is);

View File

@ -11,6 +11,7 @@
package me.pikamug.quests.util; package me.pikamug.quests.util;
import de.tr7zw.changeme.nbtapi.NBT; import de.tr7zw.changeme.nbtapi.NBT;
import me.pikamug.quests.util.stack.BlockItemStack;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Color; import org.bukkit.Color;
@ -257,6 +258,34 @@ public class BukkitItemUtil {
} }
} }
public static BlockItemStack processBlockItemStack(final String material, final int amount, final short durability) {
if (material == null) {
return null;
}
try {
Material mat = Material.getMaterial(material.toUpperCase());
if (mat == null) {
return null;
}
return BlockItemStack.of(mat, amount, durability);
} catch (final Exception e) {
try {
Bukkit.getLogger().warning(material + " x " + amount
+ " is invalid! You may need to update your quests.yml or actions.yml "
+ "in accordance with https://bit.ly/2BkBNNN");
final Material mat = Material.matchMaterial(material, true);
if (mat == null) {
return null;
}
return BlockItemStack.of(mat, amount, durability);
} catch (final Exception e2) {
Bukkit.getLogger().severe("Unable to use LEGACY_" + material + " as item name");
e2.printStackTrace();
return null;
}
}
}
/** /**
* Get ItemStack from formatted string. See #serializeItemStack for reverse function. * Get ItemStack from formatted string. See #serializeItemStack for reverse function.
* *
@ -623,6 +652,19 @@ public class BukkitItemUtil {
return text; return text;
} }
/**
* Returns a formatted display name. If none exists, returns item name.
*
* @param itemStack BlockItemStack to check
* @return true display or item name, if stack is not null
*/
public static String getName(final BlockItemStack itemStack) {
if (itemStack == null) {
return null;
}
return ChatColor.AQUA + getPrettyItemName(itemStack.getType().name());
}
/** /**
* Ensures that an ItemStack is a valid, non-AIR material * Ensures that an ItemStack is a valid, non-AIR material
* *