132 lines
4.3 KiB
Java
132 lines
4.3 KiB
Java
package com.alttd.playerutils.util;
|
|
|
|
import lombok.Getter;
|
|
import net.kyori.adventure.text.Component;
|
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
import org.bukkit.Material;
|
|
import org.bukkit.block.ShulkerBox;
|
|
import org.bukkit.entity.HumanEntity;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.inventory.meta.BookMeta;
|
|
import org.bukkit.inventory.meta.BlockStateMeta;
|
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
|
/**
|
|
* Utility to compute the UTF-8 byte size of a written book's contents.
|
|
*/
|
|
public final class BookByteUtils {
|
|
|
|
private BookByteUtils() {
|
|
}
|
|
|
|
// 65,000 bytes per book (below CoreProtect hard limit ~65,535)
|
|
@Getter
|
|
private static final int MAX_BOOK_BYTES = 30_000;
|
|
@Getter
|
|
private static final int BIG_BOOK_BYTES = 10_000;
|
|
|
|
public static int getBigBookBytes(HumanEntity humanEntity) {
|
|
return calcBookBytes(humanEntity, BIG_BOOK_BYTES);
|
|
}
|
|
|
|
public static int getMaxBookBytes(HumanEntity humanEntity) {
|
|
return calcBookBytes(humanEntity, MAX_BOOK_BYTES);
|
|
}
|
|
|
|
private static int calcBookBytes(HumanEntity humanEntity, int bookBytes) {
|
|
if (humanEntity.hasPermission("playerutils.bigbook.bypass")) {
|
|
return Integer.MAX_VALUE;
|
|
} else if (humanEntity.hasPermission("playerutils.bigbook.double")) {
|
|
return bookBytes * 2;
|
|
} else if (humanEntity.hasPermission("playerutils.bigbook.quadruple")) {
|
|
return bookBytes * 4;
|
|
} else {
|
|
return bookBytes;
|
|
}
|
|
}
|
|
|
|
public static boolean shouldCountForBookByteLimit(ItemStack stack) {
|
|
if (stack == null) {
|
|
return false;
|
|
}
|
|
Material type = stack.getType();
|
|
if (type == Material.WRITTEN_BOOK || type == Material.WRITABLE_BOOK) {
|
|
return true;
|
|
}
|
|
if (stack.getItemMeta() instanceof BookMeta) {
|
|
return true;
|
|
}
|
|
if (!(stack.getItemMeta() instanceof BlockStateMeta bsm) || !(bsm.getBlockState() instanceof ShulkerBox shulker)) {
|
|
return false;
|
|
}
|
|
for (ItemStack content : shulker.getInventory().getContents()) {
|
|
if (content == null) {
|
|
continue;
|
|
}
|
|
Material contentType = content.getType();
|
|
if (contentType == Material.WRITTEN_BOOK || contentType == Material.WRITABLE_BOOK) {
|
|
return true;
|
|
}
|
|
if (content.getItemMeta() instanceof BookMeta) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Compute the number of bytes used by the provided BookMeta.
|
|
*/
|
|
public static int computeBytes(BookMeta meta) {
|
|
if (meta == null) {
|
|
return 0;
|
|
}
|
|
int totalBytes = 0;
|
|
String title = meta.getTitle();
|
|
if (title != null) {
|
|
totalBytes += title.getBytes(StandardCharsets.UTF_8).length;
|
|
}
|
|
for (Component page : meta.pages()) {
|
|
if (page == null) {
|
|
continue;
|
|
}
|
|
String pageString = MiniMessage.miniMessage().serialize(page);
|
|
if (pageString.isEmpty()) {
|
|
continue;
|
|
}
|
|
totalBytes += pageString.getBytes(StandardCharsets.UTF_8).length;
|
|
}
|
|
return totalBytes;
|
|
}
|
|
|
|
/**
|
|
* Compute the number of bytes used by a book item stack. If the item is not a written book, returns 0.
|
|
*/
|
|
public static int computeBytes(ItemStack stack) {
|
|
if (stack == null) {
|
|
return 0;
|
|
}
|
|
// Direct written book
|
|
if (stack.getItemMeta() instanceof BookMeta meta) {
|
|
int perBook = computeBytes(meta);
|
|
return perBook * Math.max(1, stack.getAmount());
|
|
}
|
|
// Shulker box: sum bytes of contained written books
|
|
if (stack.getItemMeta() instanceof BlockStateMeta bsm && bsm.getBlockState() instanceof ShulkerBox shulker) {
|
|
int total = 0;
|
|
for (ItemStack content : shulker.getInventory().getContents()) {
|
|
if (content == null) {
|
|
continue;
|
|
}
|
|
if (content.getItemMeta() instanceof BookMeta bookMeta) {
|
|
total += computeBytes(bookMeta) * Math.max(1, content.getAmount());
|
|
}
|
|
}
|
|
return total;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|