Skip to content

Commit

Permalink
some tweaks to the anti book ban module
Browse files Browse the repository at this point in the history
  • Loading branch information
xGinko committed Nov 17, 2023
1 parent ce74da3 commit 2e8f6b3
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 94 deletions.
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
package me.moomoo.anarchyexploitfixes.modules.patches;

import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes;
import me.moomoo.anarchyexploitfixes.config.Config;
import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.BookMeta;
import org.jetbrains.annotations.Nullable;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static me.moomoo.anarchyexploitfixes.utils.ItemUtils.isBook;
import static me.moomoo.anarchyexploitfixes.utils.ItemUtils.isShulkerBox;
import java.util.Iterator;

public class BookBan implements AnarchyExploitFixesModule, Listener {

private final int maxByteSizePerPage;
private final MiniMessage miniMessage;
private final int maxBookSize, maxItemSize, maxInventorySize;

public BookBan() {
shouldEnable();
this.maxByteSizePerPage = AnarchyExploitFixes.getConfiguration().getInt("patches.prevent-book-ban.max-byte-size-per-page", 255);
this.miniMessage = MiniMessage.miniMessage();
Config config = AnarchyExploitFixes.getConfiguration();
this.maxBookSize = config.getInt("patches.anti-book-ban.max-book-size", 8000);
this.maxItemSize = config.getInt("patches.anti-book-ban.max-item-size", 8260);
this.maxInventorySize = config.getInt("patches.anti-book-ban.max-inventory-size", 50674);
}

@Override
Expand All @@ -51,62 +50,92 @@ public void enable() {

@Override
public boolean shouldEnable() {
return AnarchyExploitFixes.getConfiguration().getBoolean("patches.prevent-book-ban.enable", true);
return AnarchyExploitFixes.getConfiguration().getBoolean("patches.anti-book-ban.enable", true);
}

@Override
public void disable() {
HandlerList.unregisterAll(this);
}

private void clearBooks(Player player) {
for (ItemStack itemInInventory : player.getInventory()) {
if (isBook(itemInInventory)) {
stripPages(itemInInventory);
}
else if (isShulkerBox(itemInInventory)) {
BlockStateMeta meta = (BlockStateMeta) itemInInventory.getItemMeta();
ShulkerBox shulkerBox = (ShulkerBox) meta.getBlockState();

for (ItemStack itemInsideShulker : shulkerBox.getInventory()) {
if (isBook(itemInsideShulker)) {
stripPages(itemInsideShulker);
}
}

shulkerBox.update();
meta.setBlockState(shulkerBox);
itemInInventory.setItemMeta(meta);
}
private long getItemSize(@Nullable ItemStack stack) {
long byteSize = 0L;
if (stack == null) return byteSize;

if (
stack.hasItemMeta()
&& stack.getItemMeta() instanceof BlockStateMeta blockStateMeta
&& blockStateMeta.getBlockState() instanceof ShulkerBox shulkerBox
) {
byteSize += getInventorySize(shulkerBox.getInventory().getContents());
}

// The serialize as bytes function takes significantly longer to run because
// it tries to compress the file. Instead, we will just use the string length,
// even though that is not a great proxy.
byteSize += stack.serialize().toString().getBytes(StandardCharsets.UTF_8).length;

return byteSize;
}

private void stripPages(ItemStack book) {
BookMeta bookMeta = (BookMeta) book.getItemMeta();
private long getInventorySize(ItemStack[] contents) {
long size = 0L;
for (ItemStack stack : contents) {
size += getItemSize(stack);
}
return size;
}

List<Component> newPages = new ArrayList<>(bookMeta.getPageCount());
// Prevent players from creating big books
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBookEdit(PlayerEditBookEvent event) {
// Map using MiniMessage#serialize so there are no possible bypasses using large components.
final String serializedPages = String.join("", event.getNewBookMeta().pages().stream().map(miniMessage::serialize).toList());
if (
serializedPages.getBytes(StandardCharsets.UTF_8).length > maxBookSize
|| serializedPages.getBytes(StandardCharsets.UTF_16).length > maxBookSize
) {
event.setCancelled(true);
}
}

for (Component page : bookMeta.pages()) {
if (PlainTextComponentSerializer.plainText().serialize(page).getBytes(StandardCharsets.UTF_8).length <= maxByteSizePerPage)
newPages.add(page);
// Attempt to stop players from picking up large items
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) {
final long itemSize = getItemSize(event.getItem().getItemStack());
if (itemSize > maxItemSize) {
event.setCancelled(true);
return;
}

bookMeta.pages(newPages);
book.setItemMeta(bookMeta);
// Check if the total inventory size would be larger than the maximum inventory size
if (itemSize + getInventorySize(event.getPlayer().getInventory().getContents()) > maxInventorySize) {
event.setCancelled(true);
}
}

private void sanitizeInventory(PlayerInventory inventory) {
Iterator<ItemStack> invIterator = inventory.iterator();
while (invIterator.hasNext()) {
if (getItemSize(invIterator.next()) > maxItemSize) {
invIterator.remove();
}
}
}

@EventHandler(priority = EventPriority.NORMAL)
// Attempt to clear off big items from affected players
@EventHandler(priority = EventPriority.LOW)
private void onJoin(PlayerJoinEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}

@EventHandler(priority = EventPriority.NORMAL)
@EventHandler(priority = EventPriority.LOW)
private void onLeave(PlayerQuitEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}

@EventHandler(priority = EventPriority.NORMAL)
@EventHandler(priority = EventPriority.LOW)
private void onKick(PlayerKickEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}
}
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,36 @@
package me.moomoo.anarchyexploitfixes.modules.patches;

import me.moomoo.anarchyexploitfixes.AnarchyExploitFixes;
import me.moomoo.anarchyexploitfixes.config.Config;
import me.moomoo.anarchyexploitfixes.modules.AnarchyExploitFixesModule;
import org.bukkit.block.ShulkerBox;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerKickEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.*;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.BookMeta;
import org.bukkit.inventory.meta.ItemMeta;

import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

import static me.moomoo.anarchyexploitfixes.utils.ItemUtils.isBook;
import static me.moomoo.anarchyexploitfixes.utils.ItemUtils.isShulkerBox;
import java.util.Iterator;

public class BookBan implements AnarchyExploitFixesModule, Listener {

private final int maxByteSizePerPage;
private final int maxBookSize, maxItemSize, maxInventorySize;

public BookBan() {
shouldEnable();
this.maxByteSizePerPage = AnarchyExploitFixes.getConfiguration().getInt("patches.prevent-book-ban.max-byte-size-per-page", 255);
Config config = AnarchyExploitFixes.getConfiguration();
this.maxBookSize = config.getInt("patches.anti-book-ban.max-book-size", 8000);
this.maxItemSize = config.getInt("patches.anti-book-ban.max-item-size", 8260);
this.maxInventorySize = config.getInt("patches.anti-book-ban.max-inventory-size", 50674);
}

@Override
public String name() {
return "prevent-book-ban";
return "anti-book-ban";
}

@Override
Expand All @@ -48,56 +46,88 @@ public void enable() {

@Override
public boolean shouldEnable() {
return AnarchyExploitFixes.getConfiguration().getBoolean("patches.prevent-book-ban.enable", true);
return AnarchyExploitFixes.getConfiguration().getBoolean("patches.anti-book-ban.enable", true);
}

private void clearBooks(Player player) {
for (ItemStack itemInInventory : player.getInventory()) {
if (isBook(itemInInventory)) {
stripPages(itemInInventory);
} else if (isShulkerBox(itemInInventory)) {
BlockStateMeta meta = (BlockStateMeta) itemInInventory.getItemMeta();
ShulkerBox shulkerBox = (ShulkerBox) meta.getBlockState();

for (ItemStack itemInsideShulker : shulkerBox.getInventory()) {
if (isBook(itemInsideShulker)) {
stripPages(itemInsideShulker);
}
}
private long getItemSize(ItemStack stack) {
long byteSize = 0L;
if (stack == null) return byteSize;

shulkerBox.update();
meta.setBlockState(shulkerBox);
itemInInventory.setItemMeta(meta);
if (stack.hasItemMeta()) {
final ItemMeta itemMeta = stack.getItemMeta();
if (itemMeta instanceof BlockStateMeta) {
final BlockStateMeta blockStateMeta = (BlockStateMeta) itemMeta;
if (blockStateMeta instanceof ShulkerBox) {
byteSize += getInventorySize(((ShulkerBox) blockStateMeta).getInventory().getContents());
}
}
}

// The serialize as bytes function takes significantly longer to run because
// it tries to compress the file. Instead, we will just use the string length,
// even though that is not a great proxy.
byteSize += stack.serialize().toString().getBytes(StandardCharsets.UTF_8).length;

return byteSize;
}

private long getInventorySize(ItemStack[] contents) {
long size = 0L;
for (ItemStack stack : contents) {
size += getItemSize(stack);
}
return size;
}

private void stripPages(ItemStack book) {
BookMeta bookMeta = (BookMeta) book.getItemMeta();
// Prevent players from creating big books
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onBookEdit(PlayerEditBookEvent event) {
final String serializedPages = String.join("", event.getNewBookMeta().getPages());
if (
serializedPages.getBytes(StandardCharsets.UTF_8).length > maxBookSize
|| serializedPages.getBytes(StandardCharsets.UTF_16).length > maxBookSize
) {
event.setCancelled(true);
}
}

List<String> pages = new ArrayList<>(bookMeta.getPageCount());
// Attempt to stop players from picking up large items
@EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true)
private void onPlayerAttemptPickupItem(PlayerAttemptPickupItemEvent event) {
final long itemSize = getItemSize(event.getItem().getItemStack());
if (itemSize > maxItemSize) {
event.setCancelled(true);
return;
}

for (String page : bookMeta.getPages()) {
if (page.getBytes(StandardCharsets.UTF_8).length <= maxByteSizePerPage)
pages.add(page);
// Check if the total inventory size would be larger than the maximum inventory size
if (itemSize + getInventorySize(event.getPlayer().getInventory().getContents()) > maxInventorySize) {
event.setCancelled(true);
}
}

bookMeta.setPages(pages);
book.setItemMeta(bookMeta);
private void sanitizeInventory(PlayerInventory inventory) {
Iterator<ItemStack> invIterator = inventory.iterator();
while (invIterator.hasNext()) {
if (getItemSize(invIterator.next()) > maxItemSize) {
invIterator.remove();
}
}
}

@EventHandler(priority = EventPriority.NORMAL)
// Attempt to clear off big items from affected players
@EventHandler(priority = EventPriority.LOW)
private void onJoin(PlayerJoinEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}

@EventHandler(priority = EventPriority.NORMAL)
@EventHandler(priority = EventPriority.LOW)
private void onLeave(PlayerQuitEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}

@EventHandler(priority = EventPriority.NORMAL)
@EventHandler(priority = EventPriority.LOW)
private void onKick(PlayerKickEvent event) {
clearBooks(event.getPlayer());
sanitizeInventory(event.getPlayer().getInventory());
}
}
}

0 comments on commit 2e8f6b3

Please sign in to comment.