Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 25 additions & 5 deletions src/main/java/org/zeroBzeroT/antiillegals/AntiIllegals.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ public static FileConfiguration config() {
return INSTANCE.getConfig();
}

public static boolean resolveNbtContainersDefault() {
final FileConfiguration cfg = config();
if (cfg.isBoolean("nbtContainers"))
return cfg.getBoolean("nbtContainers");
return true;
}

/**
* log formatting and output
*/
Expand All @@ -53,19 +60,32 @@ public void onEnable() {
log("unbreakables", "" + getConfig().getBoolean("unbreakables"));
log("durability", "" + getConfig().getBoolean("durability"));
log("illegalBlocks", "" + getConfig().getBoolean("illegalBlocks"));
log("nbtContainers", "" + getConfig().getBoolean("nbtContainers"));
log("nbtContainers.enabled", "" + getConfig().getBoolean("nbtContainers.enabled",
resolveNbtContainersDefault()));
log("nbtContainers.armorStandItems", "" + getConfig().getBoolean("nbtContainers.armorStandItems", true));
log("nbtContainers.itemFrameItems", "" + getConfig().getBoolean("nbtContainers.itemFrameItems", true));
log("nbtContainers.bundleItems", "" + getConfig().getBoolean("nbtContainers.bundleItems", true));
log("nbtContainers.stripOtherContainers", ""
+ getConfig().getBoolean("nbtContainers.stripOtherContainers", true));
log("blockStates.enabled", "" + getConfig().getBoolean("blockStates.enabled"));
log("blockStates.keys", String.join(", ", getConfig().getStringList("blockStates.keys")));
log("overstackedItems", "" + getConfig().getBoolean("overstackedItems"));
log("allowCollectibles", "" + getConfig().getBoolean("allowCollectibles"));
log("conflictingEnchantments", "" + getConfig().getBoolean("conflictingEnchantments"));
log("maxEnchantments", "" + getConfig().getBoolean("maxEnchantments"));
log("shulkerBoxes", "" + getConfig().getBoolean("shulkerBoxes"));
log("maxBooksInShulker", "" + getConfig().getInt("maxBooksInShulker"));
log("maxBooksShulkersInInventory", "" + getConfig().getInt("maxBooksShulkersInInventory"));
log("interactItems", "" + getConfig().getBoolean("interactItems", true));
log("books.lecternCheck", "" + getConfig().getBoolean("books.lecternCheck", true));
log("books.shulkerBoxes.enabled", "" + getConfig().getBoolean("books.shulkerBoxes.enabled", true));
log("books.shulkerBoxes.maxBooksInside", "" + getConfig().getInt("books.shulkerBoxes.maxBooksInside", 10));
log("books.shulkerBoxes.maxContainersPerInventory",
"" + getConfig().getInt("books.shulkerBoxes.maxContainersPerInventory", 3));
log("books.bundles.enabled", "" + getConfig().getBoolean("books.bundles.enabled", true));
log("books.bundles.maxBooksInside", "" + getConfig().getInt("books.bundles.maxBooksInside", 10));
log("books.bundles.maxContainersPerInventory",
"" + getConfig().getInt("books.bundles.maxContainersPerInventory", 1));
log("attributeModifiers", "" + getConfig().getBoolean("attributeModifiers"));
log("customPotionEffects", "" + getConfig().getBoolean("customPotionEffects"));
log("crossbowProjectiles", "" + getConfig().getBoolean("crossbowProjectiles"));
log("crossbowProjectiles", "" + getConfig().getBoolean("crossbowProjectiles"));
log("suspiciousStewEffects", "" + getConfig().getBoolean("suspiciousStewEffects"));
log("hideFlags", "" + getConfig().getBoolean("hideFlags"));

Expand Down
53 changes: 53 additions & 0 deletions src/main/java/org/zeroBzeroT/antiillegals/Events.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,44 @@ public void onBlockBreak(@NotNull final BlockBreakEvent event) {
.ifPresent(inventory -> RevertHelper.checkInventory(inventory, location, true));
}

@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerInteractUseItem(@NotNull final PlayerInteractEvent event) {
if (!AntiIllegals.config().getBoolean("interactItems"))
return;

if (event.getAction() == Action.PHYSICAL)
return;

final Player player = event.getPlayer();
final PlayerInventory inventory = player.getInventory();
final Location location = player.getLocation();

final ItemStack mainHandStack = inventory.getItemInMainHand();
final ItemStack offhandHandStack = inventory.getItemInOffHand();

boolean removedIllegal = false;

final ItemState mainState = RevertHelper.checkItemStack(mainHandStack, location, true);
if (mainState == ItemState.ILLEGAL && mainHandStack != null)
mainHandStack.setAmount(0);

final ItemState offState = RevertHelper.checkItemStack(offhandHandStack, location, true);
if (offState == ItemState.ILLEGAL && offhandHandStack != null)
offhandHandStack.setAmount(0);

removedIllegal = mainState == ItemState.ILLEGAL || offState == ItemState.ILLEGAL;

inventory.setItemInMainHand(mainHandStack);
inventory.setItemInOffHand(offhandHandStack);

if (!removedIllegal)
return;

event.setCancelled(true);
AntiIllegals.log(event.getEventName(), "Removed illegal items from " + player.getName()
+ " during interaction.");
}

@EventHandler(ignoreCancelled = true)
public void onPlayerInteractBlock(@NotNull final PlayerInteractEvent event) {
if (event.getAction() != Action.RIGHT_CLICK_BLOCK)
Expand All @@ -86,6 +124,21 @@ public void onPlayerInteractBlock(@NotNull final PlayerInteractEvent event) {
});
}

@EventHandler(ignoreCancelled = true)
public void onPlayerTakeLecternBook(@NotNull final PlayerTakeLecternBookEvent event) {
if (!BookHelper.shouldCheckLecternBooks())
return;

final ItemStack book = event.getBook();
final Location location = event.getLectern().getLocation();

if (!RevertHelper.revert(book, location, true, ItemState::wasReverted))
return;

AntiIllegals.log(event.getEventName(), "Reverted lectern book taken by "
+ event.getPlayer().getName() + ".");
}

@EventHandler(ignoreCancelled = true)
public void onInventoryOpen(@NotNull final InventoryOpenEvent event) {
final Inventory inventory = event.getInventory();
Expand Down
203 changes: 181 additions & 22 deletions src/main/java/org/zeroBzeroT/antiillegals/helpers/BookHelper.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.zeroBzeroT.antiillegals.helpers;

import de.tr7zw.changeme.nbtapi.NBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBT;
import de.tr7zw.changeme.nbtapi.iface.ReadWriteNBTCompoundList;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
Expand All @@ -10,9 +13,9 @@
import org.jetbrains.annotations.Nullable;
import org.zeroBzeroT.antiillegals.AntiIllegals;

import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

public class BookHelper {
Expand All @@ -21,32 +24,84 @@ private BookHelper() {

}

public static int maxBookShulkers() {
return AntiIllegals.config().getInt("maxBooksShulkersInInventory");
private static boolean hasConfigValue(@NotNull final String path) {
return AntiIllegals.config().isSet(path);
}

public static int maxBookItemsInShulker() {
return AntiIllegals.config().getInt("maxBooksInShulker");
private static boolean getBoolean(@NotNull final String newPath, @Nullable final String legacyPath,
final boolean defaultValue) {
if (hasConfigValue(newPath))
return AntiIllegals.config().getBoolean(newPath);
if (legacyPath != null && hasConfigValue(legacyPath))
return AntiIllegals.config().getBoolean(legacyPath);
return defaultValue;
}

private static int getInt(@NotNull final String newPath, @Nullable final String legacyPath,
final int defaultValue) {
if (hasConfigValue(newPath))
return AntiIllegals.config().getInt(newPath);
if (legacyPath != null && hasConfigValue(legacyPath))
return AntiIllegals.config().getInt(legacyPath);
return defaultValue;
}

public static boolean shouldCheckLecternBooks() {
return getBoolean("books.lecternCheck", null, true);
}

public static boolean shouldCleanBookShulkers() {
return AntiIllegals.config().getBoolean("shulkerBoxes");
return getBoolean("books.shulkerBoxes.enabled", "shulkerBoxes", true);
}

public static int maxBookItemsInShulker() {
return getInt("books.shulkerBoxes.maxBooksInside", "maxBooksInShulker", 10);
}

public static int maxBookShulkers() {
return getInt("books.shulkerBoxes.maxContainersPerInventory", "maxBooksShulkersInInventory", 3);
}

public static boolean shouldCleanBundleBooks() {
return getBoolean("books.bundles.enabled", null, true);
}

public static void dropBookShulkerItem(@NotNull final Location location, @NotNull final ItemStack itemStack) {
public static int maxBooksInBundle() {
return getInt("books.bundles.maxBooksInside", null, 10);
}

public static int maxBookBundlesInInventory() {
return getInt("books.bundles.maxContainersPerInventory", null, 1);
}

public static void dropBookContainerItem(@NotNull final Location location, @NotNull final ItemStack itemStack) {
location.getWorld().dropItem(location, itemStack).setPickupDelay(100);
}

public static int cleanBookItems(@NotNull final Inventory inventory, @Nullable final Location location,
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack) {
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack) {
if (!shouldCleanBookShulkers())
return 0;

return cleanOversizedItems(inventory, location, shulkerWithBooksItemStack, maxBookItemsInShulker());
}

public static int cleanBookShulkers(@NotNull final Inventory inventory, @Nullable final Location location,
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack) {
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack) {
if (!shouldCleanBookShulkers())
return 0;

return cleanOversizedItems(inventory, location, shulkerWithBooksItemStack, maxBookShulkers());
}

public static int cleanBookBundles(@NotNull final Inventory inventory, @Nullable final Location location,
@NotNull final Collection<ItemStack> bundleItemStacks) {
if (!shouldCleanBundleBooks())
return 0;

return cleanOversizedItems(inventory, location, bundleItemStacks, maxBookBundlesInInventory());
}

public static boolean isBookItem(@NotNull final ItemStack itemStack) {
return isBookItem(itemStack.getType());
}
Expand Down Expand Up @@ -85,12 +140,14 @@ public static boolean containsBooks(@NotNull final Inventory inventory) {
* @return whether it contains books
*/
public static boolean containsBooks(@Nullable final ItemStack itemStack) {
if (itemStack == null) return false;
if (itemStack == null)
return false;
return InventoryHolderHelper.mapInventory(itemStack, BookHelper::containsBooks).orElse(false);
}

public static int cleanBookShulkers(@NotNull final Inventory inventory, @Nullable final Location location) {
if (!shouldCleanBookShulkers()) return 0;
if (!shouldCleanBookShulkers())
return 0;

final Collection<ItemStack> shulkersWithBooks = Arrays.stream(inventory.getContents())
.filter(BookHelper::containsBooks)
Expand All @@ -99,32 +156,134 @@ public static int cleanBookShulkers(@NotNull final Inventory inventory, @Nullabl
return BookHelper.cleanBookShulkers(inventory, location, shulkersWithBooks);
}

public static boolean bundleContainsBooks(@NotNull final ItemStack itemStack) {
if (!shouldCleanBundleBooks() || itemStack.getType() != Material.BUNDLE)
return false;

final AtomicBoolean containsBooks = new AtomicBoolean(false);

NBT.modify(itemStack, nbtItem -> {
final ReadWriteNBTCompoundList items = nbtItem.getCompoundList("Items");
if (items == null)
return;

for (final ReadWriteNBT entry : items) {
if (entry == null)
continue;

final ItemStack stored = NBT.itemStackFromNBT(entry);
if (stored == null)
continue;

if (!isBookItem(stored))
continue;

containsBooks.set(true);
break;
}
});

return containsBooks.get();
}

public static int trimBundleBooks(@NotNull final Collection<ItemStack> bundleItemStacks,
@Nullable final Location location) {
if (!shouldCleanBundleBooks() || location == null || bundleItemStacks.isEmpty())
return 0;

final int maxBooks = maxBooksInBundle();
if (maxBooks < 0)
return 0;

int removed = 0;
for (final ItemStack bundle : bundleItemStacks) {
removed += trimBooksFromBundle(bundle, location, maxBooks);
}
return removed;
}

private static int trimBooksFromBundle(@NotNull final ItemStack bundle, @NotNull final Location location,
final int maxBooks) {
final AtomicInteger removed = new AtomicInteger(0);

NBT.modify(bundle, nbtItem -> {
final ReadWriteNBTCompoundList items = nbtItem.getCompoundList("Items");
if (items == null || items.isEmpty())
return;

int seenBooks = 0;
final List<Integer> removalIndexes = new ArrayList<>();
final List<ItemStack> droppedBooks = new ArrayList<>();

for (int i = 0; i < items.size(); i++) {
final ReadWriteNBT entry = items.get(i);
if (entry == null)
continue;

final ItemStack stored = NBT.itemStackFromNBT(entry);
if (stored == null || !isBookItem(stored))
continue;

if (seenBooks < maxBooks) {
seenBooks++;
continue;
}

removalIndexes.add(i);
droppedBooks.add(stored);
}

if (removalIndexes.isEmpty())
return;

removalIndexes.sort(Integer::compareTo);
Collections.reverse(removalIndexes);
removalIndexes.forEach(items::remove);

removed.addAndGet(droppedBooks.size());
if (location.getWorld() != null)
droppedBooks.forEach(stack -> dropBookContainerItem(location, stack));
});

return removed.get();
}

public static int cleanOversizedItems(@NotNull final Inventory inventory, @Nullable final Location location,
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack,
final int maxItems) {
if (location == null || maxItems < 0 || shulkerWithBooksItemStack.size() <= maxItems) return 0;
@NotNull final Collection<ItemStack> shulkerWithBooksItemStack,
final int maxItems) {
if (location == null || maxItems < 0 || shulkerWithBooksItemStack.size() <= maxItems)
return 0;

int counter = 0;

for (final ItemStack shulkerItemStack : shulkerWithBooksItemStack) {
inventory.remove(shulkerItemStack);
Bukkit.getScheduler().runTask(AntiIllegals.INSTANCE, () -> dropBookShulkerItem(location, shulkerItemStack));
Bukkit.getScheduler().runTask(AntiIllegals.INSTANCE,
() -> dropBookContainerItem(location, shulkerItemStack));
counter++;
}
return counter;
}

public static void checkEnderChest(@NotNull final InventoryOpenEvent inventoryOpenEvent,
@Nullable final Location location) {
@Nullable final Location location) {
final Inventory inventory = inventoryOpenEvent.getInventory();
final ItemStack[] inventoryContents = inventory.getContents();

for (final ItemStack itemStack : inventoryContents) {
if (itemStack == null) continue;
if (itemStack == null)
continue;

InventoryHolderHelper.iterateInventory(itemStack, inv ->
BookHelper.cleanBookItems(inv, location, BookHelper.filterBooks(inv).toList())
);
InventoryHolderHelper.iterateInventory(itemStack,
inv -> BookHelper.cleanBookItems(inv, location, BookHelper.filterBooks(inv).toList()));
}

final List<ItemStack> bundlesWithBooks = Arrays.stream(inventoryContents)
.filter(Objects::nonNull)
.filter(BookHelper::bundleContainsBooks)
.toList();

BookHelper.cleanBookBundles(inventory, location, bundlesWithBooks);
BookHelper.trimBundleBooks(bundlesWithBooks, location);
}
}
Loading