Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Drop correct amount of items when burned shulker box #108

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -291,4 +291,6 @@ default void setPaperFromMobSpawner(Entity entity) {

EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what, @NotNull List<ItemStack> drops, int droppedExp);

List<ItemStack> getBoxContents(Item item);

}
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,11 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
return new ArrayList<>();
}

private SpawnReason toBukkitSpawnReason(EnumMobSpawn mobSpawnType) {
return switch (mobSpawnType) {
case SPAWN_EGG -> SpawnReason.SPAWNER_EGG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,14 +50,14 @@
import net.minecraft.world.entity.ai.goal.WrappedGoal;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.animal.Rabbit;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.Spider;
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
Expand Down Expand Up @@ -418,6 +418,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
net.minecraft.world.item.ItemStack itemStack = ((ItemEntity) item).getItem();
CompoundTag contents = itemStack.getTag();

if (contents != null) {
return contents.getCompound("BlockEntityTag").getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

private SpawnReason toBukkitSpawnReason(MobSpawnType mobSpawnType) {
return switch (mobSpawnType) {
case SPAWN_EGG -> SpawnReason.SPAWNER_EGG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -422,6 +423,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

private SpawnReason toBukkitSpawnReason(MobSpawnType mobSpawnType) {
return switch (mobSpawnType) {
case SPAWN_EGG -> SpawnReason.SPAWNER_EGG;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -499,6 +500,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -499,6 +500,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -496,6 +497,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -496,6 +497,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -498,6 +499,22 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
ItemStack itemStack = item.getItemStack();
CompoundTag contents = BlockItem.getBlockEntityData(CraftItemStack.asNMSCopy(itemStack));

if (contents != null && contents.contains("Items", 9)) {
return contents.getList("Items", 10).stream()
.map(CompoundTag.class::cast)
.map(net.minecraft.world.item.ItemStack::of)
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,13 @@
import net.minecraft.world.entity.ai.goal.WrappedGoal;
import net.minecraft.world.entity.ai.memory.MemoryModuleType;
import net.minecraft.world.entity.animal.Rabbit;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.monster.Spider;
import net.minecraft.world.entity.monster.Strider;
import net.minecraft.world.entity.monster.Zombie;
import net.minecraft.world.entity.raid.Raider;
import net.minecraft.world.item.component.CustomData;
import net.minecraft.world.item.component.ItemContainerContents;
import net.minecraft.world.item.trading.MerchantOffers;
import net.minecraft.world.level.BaseSpawner;
import net.minecraft.world.level.ClipContext;
Expand Down Expand Up @@ -499,6 +501,21 @@ public EntityDeathEvent createAsyncEntityDeathEvent(@NotNull LivingEntity what,
return new AsyncEntityDeathEventImpl(what, drops, droppedExp);
}

@Override
public List<ItemStack> getBoxContents(Item item) {
net.minecraft.world.item.ItemStack itemStack = CraftItemStack.asNMSCopy(item.getItemStack());
ItemContainerContents contents = itemStack.set(DataComponents.CONTAINER, ItemContainerContents.EMPTY);

if (contents != null) {
return contents.stream()
.filter(x -> !x.isEmpty())
.map(CraftItemStack::asBukkitCopy)
.toList();
}

return new ArrayList<>();
}

public void addEntityToWorld(ServerLevel world, Entity entity) throws ReflectiveOperationException {
if (field_ServerLevel_entityManager != null) {
PersistentEntitySectionManager<Entity> entityManager = (PersistentEntitySectionManager<Entity>) field_ServerLevel_entityManager.get(world);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import dev.rosewood.guiframework.framework.util.GuiUtil;
import dev.rosewood.rosegarden.RosePlugin;
import dev.rosewood.rosegarden.utils.NMSUtil;
import dev.rosewood.rosestacker.RoseStacker;
import dev.rosewood.rosestacker.event.AsyncEntityDeathEvent;
import dev.rosewood.rosestacker.manager.ConfigurationManager.Setting;
import dev.rosewood.rosestacker.manager.EntityCacheManager;
import dev.rosewood.rosestacker.manager.StackManager;
import dev.rosewood.rosestacker.manager.StackSettingManager;
import dev.rosewood.rosestacker.nms.NMSAdapter;
import dev.rosewood.rosestacker.nms.NMSHandler;
import dev.rosewood.rosestacker.nms.storage.EntityDataEntry;
import dev.rosewood.rosestacker.nms.storage.StackedEntityDataStorageType;
import dev.rosewood.rosestacker.stack.StackedEntity;
Expand All @@ -31,6 +34,7 @@
import org.bukkit.Statistic;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.block.ShulkerBox;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Chicken;
import org.bukkit.entity.Creeper;
Expand Down Expand Up @@ -72,6 +76,7 @@
import org.bukkit.event.entity.SpawnerSpawnEvent;
import org.bukkit.event.player.PlayerShearEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.util.Vector;

public class EntityListener implements Listener {
Expand Down Expand Up @@ -240,6 +245,11 @@ public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityDamage(EntityDamageEvent event) {
if (NMSUtil.getVersionNumber() >= 17 && event.getEntity() instanceof Item item && item.getItemStack().getType().toString().contains("SHULKER_BOX") && unpackShulkerBox(item, event.getFinalDamage())) {
event.setCancelled(true);
return;
}

if (!(event.getEntity() instanceof LivingEntity entity) || event.getEntity().getType() == EntityType.ARMOR_STAND || event.getEntity().getType() == EntityType.PLAYER)
return;

Expand Down Expand Up @@ -277,6 +287,65 @@ public void onEntityDamage(EntityDamageEvent event) {
}
}

private boolean unpackShulkerBox(Item item, double damage) {
StackedItem stackedItem = this.stackManager.getStackedItem(item);
if (stackedItem == null)
return false;

final int amount = stackedItem.getStackSize();

if (amount > 1 && damage >= item.getHealth()) {
final List<ItemStack> contents = getContents(item);
final List<ItemStack> totalContents = new ArrayList<>();
final Location location = item.getLocation();

item.remove();

for (int i = amount; i > 0; i--) {
totalContents.addAll(contents);
}

final int maxStackSize = Setting.ITEM_MAX_STACK_SIZE.getInt();

for (;;) {
if (totalContents.size() > maxStackSize) {
List<ItemStack> stack = new ArrayList<>(totalContents.subList(0, maxStackSize));
totalContents.subList(0, maxStackSize).clear();
this.stackManager.preStackItems(stack, location);
} else {
this.stackManager.preStackItems(totalContents, location);
break;
}
}

return true;
}

return false;
}

private List<ItemStack> getContents(Item item) {
List<ItemStack> contents = new ArrayList<>();

if (Setting.ITEM_UNPACK_BOX_LIKE_VANILLA.getBoolean()) {
NMSHandler nmsHandler = NMSAdapter.getHandler();
contents = nmsHandler.getBoxContents(item);
} else {
ItemStack itemStack = item.getItemStack();
if (!(itemStack.getItemMeta() instanceof BlockStateMeta meta)) return contents;

if (!(meta.getBlockState() instanceof ShulkerBox box)) return contents;

for (ItemStack content : box.getInventory().getContents()) {
if (content == null || content.getType().isAir()) continue;

contents.add(content);
}
}

return contents;
}

@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onEntityCombust(EntityCombustEvent event) {
Entity entity = event.getEntity();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ public enum Setting implements RoseSetting {
ITEM_DISPLAY_DESPAWN_TIMER_PLACEHOLDER("global-item-settings.display-despawn-timer-placeholder", false, "Should the %timer% placeholder be available in item display tags?", "You will need to add the %timer% placeholder to the item display tag in your locale file manually", "Placeholder updates will occur at the same frequency as item-stack-frequency"),
ITEM_RESET_DESPAWN_TIMER_ON_MERGE("global-item-settings.reset-despawn-timer-on-merge", true, "Should the item despawn timer be reset when an item is merged into it?"),
ITEM_MERGE_INTO_NEWEST("global-item-settings.merge-into-newest", false, "Should items be merged into the newest stack?"),
ITEM_UNPACK_BOX_LIKE_VANILLA("global-item-settings.unpack-stacked-shulker-box-like-vanilla", false, "Use vanilla method to get items stored in box, which may allow unpacking an illegal amount of items from the box."),

GLOBAL_BLOCK_SETTINGS("global-block-settings", null, "Global block settings", "Changed values in block_settings.yml will override these values"),
BLOCK_STACKING_ENABLED("global-block-settings.stacking-enabled", true, "Should block stacking be enabled at all?"),
Expand Down