9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-19 14:59:32 +00:00

Fix jade protocol inv

This commit is contained in:
violetc
2024-11-15 23:37:30 +08:00
parent fd9bd9bf9a
commit 21c276fcdc

View File

@@ -124,7 +124,7 @@ index 30d0133a42ce990352f5c492fcf9beb105364848..1ab2eab686b3a89d406f127a6036c0e2
protected CompositeLootItemCondition(List<LootItemCondition> terms, Predicate<LootContext> predicate) {
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java
new file mode 100644
index 0000000000000000000000000000000000000000..eb26708fafa054ba32c5deed43c8496d5496f6a9
index 0000000000000000000000000000000000000000..438dfee78f7114e7c8d3d57c5dcc90e1fcc75a4c
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/JadeProtocol.java
@@ -0,0 +1,311 @@
@@ -196,7 +196,7 @@ index 0000000000000000000000000000000000000000..eb26708fafa054ba32c5deed43c8496d
+import org.leavesmc.leaves.protocol.jade.provider.block.CommandBlockProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.FurnaceProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.HopperLockProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.ItemStorageProvider;
+import org.leavesmc.leaves.protocol.jade.provider.ItemStorageProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.JukeboxProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.LecternProvider;
+import org.leavesmc.leaves.protocol.jade.provider.block.MobSpawnerCooldownProvider;
@@ -442,20 +442,18 @@ index 0000000000000000000000000000000000000000..eb26708fafa054ba32c5deed43c8496d
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java
new file mode 100644
index 0000000000000000000000000000000000000000..9c9b469f805196dd97e02d93a11232d043f5e854
index 0000000000000000000000000000000000000000..1a637045d9375ae357ca1e592ec0dc7b45fa47fa
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/Accessor.java
@@ -0,0 +1,37 @@
@@ -0,0 +1,32 @@
+package org.leavesmc.leaves.protocol.jade.accessor;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.StreamEncoder;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.phys.HitResult;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public interface Accessor<T extends HitResult> {
@@ -464,9 +462,6 @@ index 0000000000000000000000000000000000000000..9c9b469f805196dd97e02d93a11232d0
+
+ Player getPlayer();
+
+ @NotNull
+ CompoundTag getServerData();
+
+ <D> Tag encodeAsNbt(StreamEncoder<RegistryFriendlyByteBuf, D> codec, D value);
+
+ T getHitResult();
@@ -485,20 +480,18 @@ index 0000000000000000000000000000000000000000..9c9b469f805196dd97e02d93a11232d0
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..38d6b146d9135fb7c985f1f4e8a804bb490ff0df
index 0000000000000000000000000000000000000000..a04fbb45b466d8999b40717d8d48f650b81fe82a
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/AccessorImpl.java
@@ -0,0 +1,92 @@
@@ -0,0 +1,83 @@
+package org.leavesmc.leaves.protocol.jade.accessor;
+
+import java.util.function.Supplier;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.jetbrains.annotations.NotNull;
+
+import io.netty.buffer.Unpooled;
+import net.minecraft.nbt.ByteArrayTag;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.Tag;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.StreamEncoder;
@@ -510,20 +503,18 @@ index 0000000000000000000000000000000000000000..38d6b146d9135fb7c985f1f4e8a804bb
+
+ private final Level level;
+ private final Player player;
+ private final CompoundTag serverData;
+ private final Supplier<T> hit;
+ private final boolean serverConnected;
+ private final boolean showDetails;
+ protected boolean verify;
+ private RegistryFriendlyByteBuf buffer;
+
+ public AccessorImpl(Level level, Player player, CompoundTag serverData, Supplier<T> hit, boolean serverConnected, boolean showDetails) {
+ public AccessorImpl(Level level, Player player, Supplier<T> hit, boolean serverConnected, boolean showDetails) {
+ this.level = level;
+ this.player = player;
+ this.hit = hit;
+ this.serverConnected = serverConnected;
+ this.showDetails = showDetails;
+ this.serverData = serverData == null ? new CompoundTag() : serverData.copy();
+ }
+
+ @Override
@@ -536,11 +527,6 @@ index 0000000000000000000000000000000000000000..38d6b146d9135fb7c985f1f4e8a804bb
+ return player;
+ }
+
+ @Override
+ public final @NotNull CompoundTag getServerData() {
+ return serverData;
+ }
+
+ private RegistryFriendlyByteBuf buffer() {
+ if (buffer == null) {
+ buffer = new RegistryFriendlyByteBuf(Unpooled.buffer(), level.registryAccess());
@@ -639,10 +625,10 @@ index 0000000000000000000000000000000000000000..12d689ca80887dcd5dbf68ea2c38a8ad
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a2cd64c7911b756f737ed34f245f7366668f417
index 0000000000000000000000000000000000000000..9e4a321b91a8afc480ef506487608255db2b9c89
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/BlockAccessorImpl.java
@@ -0,0 +1,166 @@
@@ -0,0 +1,163 @@
+package org.leavesmc.leaves.protocol.jade.accessor;
+
+import java.util.function.Supplier;
@@ -653,7 +639,6 @@ index 0000000000000000000000000000000000000000..4a2cd64c7911b756f737ed34f245f736
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Direction;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.FriendlyByteBuf;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.ByteBufCodecs;
@@ -678,7 +663,7 @@ index 0000000000000000000000000000000000000000..4a2cd64c7911b756f737ed34f245f736
+ private final Supplier<BlockEntity> blockEntity;
+
+ private BlockAccessorImpl(Builder builder) {
+ super(builder.level, builder.player, builder.serverData, Suppliers.ofInstance(builder.hit), builder.connected, builder.showDetails);
+ super(builder.level, builder.player, Suppliers.ofInstance(builder.hit), builder.connected, builder.showDetails);
+ blockState = builder.blockState;
+ blockEntity = builder.blockEntity;
+ }
@@ -718,7 +703,6 @@ index 0000000000000000000000000000000000000000..4a2cd64c7911b756f737ed34f245f736
+
+ private Level level;
+ private Player player;
+ private CompoundTag serverData;
+ private boolean connected;
+ private boolean showDetails;
+ private BlockHitResult hit;
@@ -765,7 +749,6 @@ index 0000000000000000000000000000000000000000..4a2cd64c7911b756f737ed34f245f736
+ public Builder from(BlockAccessor accessor) {
+ level = accessor.getLevel();
+ player = accessor.getPlayer();
+ serverData = accessor.getServerData();
+ connected = accessor.isServerConnected();
+ showDetails = accessor.showDetails();
+ hit = accessor.getHitResult();
@@ -862,14 +845,13 @@ index 0000000000000000000000000000000000000000..454360d5e5c01cad3c197b078d536a9f
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..f670ac9b7ee72bbf3fa4f509cc2cdaeee238ccff
index 0000000000000000000000000000000000000000..65d16c0024372ede4cec230b7aad54de28de15f2
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/accessor/EntityAccessorImpl.java
@@ -0,0 +1,126 @@
@@ -0,0 +1,123 @@
+package org.leavesmc.leaves.protocol.jade.accessor;
+
+import com.google.common.base.Suppliers;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.ByteBufCodecs;
+import net.minecraft.network.codec.StreamCodec;
@@ -889,7 +871,7 @@ index 0000000000000000000000000000000000000000..f670ac9b7ee72bbf3fa4f509cc2cdaee
+ private final Supplier<Entity> entity;
+
+ public EntityAccessorImpl(Builder builder) {
+ super(builder.level, builder.player, builder.serverData, builder.hit, builder.connected, builder.showDetails);
+ super(builder.level, builder.player, builder.hit, builder.connected, builder.showDetails);
+ entity = builder.entity;
+ }
+
@@ -914,7 +896,6 @@ index 0000000000000000000000000000000000000000..f670ac9b7ee72bbf3fa4f509cc2cdaee
+ public boolean showDetails;
+ private Level level;
+ private Player player;
+ private CompoundTag serverData;
+ private boolean connected;
+ private Supplier<EntityHitResult> hit;
+ private Supplier<Entity> entity;
@@ -953,7 +934,6 @@ index 0000000000000000000000000000000000000000..f670ac9b7ee72bbf3fa4f509cc2cdaee
+ public Builder from(EntityAccessor accessor) {
+ level = accessor.getLevel();
+ player = accessor.getPlayer();
+ serverData = accessor.getServerData();
+ connected = accessor.isServerConnected();
+ showDetails = accessor.showDetails();
+ hit = accessor::getHitResult;
@@ -1251,10 +1231,10 @@ index 0000000000000000000000000000000000000000..6e32eed15f028020223e2500849b4db3
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe348c895b14
index 0000000000000000000000000000000000000000..797558f3804a1a8143eafafd5dc46cc72ea19a42
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageExtensionProvider.java
@@ -0,0 +1,142 @@
@@ -0,0 +1,138 @@
+package org.leavesmc.leaves.protocol.jade.provider;
+
+import com.google.common.cache.Cache;
@@ -1263,7 +1243,6 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+import net.minecraft.world.Container;
+import net.minecraft.world.LockCode;
+import net.minecraft.world.RandomizableContainer;
+import net.minecraft.world.WorldlyContainer;
+import net.minecraft.world.WorldlyContainerHolder;
+import net.minecraft.world.entity.animal.horse.AbstractHorse;
+import net.minecraft.world.entity.player.Player;
@@ -1274,6 +1253,8 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
+import net.minecraft.world.level.block.entity.ChestBlockEntity;
+import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.leavesmc.leaves.LeavesLogger;
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
@@ -1290,21 +1271,16 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+ INSTANCE;
+
+ public static final Cache<Object, ItemCollector<?>> targetCache = CacheBuilder.newBuilder().weakKeys().expireAfterAccess(60, TimeUnit.SECONDS).build();
+ public static final Cache<Object, ItemCollector<?>> containerCache = CacheBuilder.newBuilder().weakKeys().expireAfterAccess(120, TimeUnit.SECONDS).build();
+
+ private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage.default");
+
+ @Override
+ public List<ViewGroup<ItemStack>> getGroups(Accessor<?> request) {
+ Object target = request.getTarget();
+ if (target == null && request instanceof BlockAccessor blockAccessor && blockAccessor.getBlock() instanceof WorldlyContainerHolder holder) {
+ WorldlyContainer container = holder.getContainer(blockAccessor.getBlockState(), request.getLevel(), blockAccessor.getPosition());
+ return containerGroup(container, request);
+ }
+
+ switch (target) {
+ case null -> {
+ return List.of();
+ return createItemCollector(request).update(request);
+ }
+ case RandomizableContainer te when te.getLootTable() != null -> {
+ return List.of();
@@ -1325,22 +1301,18 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+
+ if (target instanceof EnderChestBlockEntity) {
+ PlayerEnderChestContainer inventory = player.getEnderChestInventory();
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(0)).update(inventory, request.getLevel().getGameTime());
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(x -> inventory, 0)).update(request);
+ }
+
+ ItemCollector<?> itemCollector;
+ try {
+ itemCollector = targetCache.get(target, () -> createItemCollector(target));
+ itemCollector = targetCache.get(target, () -> createItemCollector(request));
+ } catch (ExecutionException e) {
+ LeavesLogger.LOGGER.severe("Failed to get item collector for " + target);
+ return null;
+ }
+
+ if (itemCollector == ItemCollector.EMPTY) {
+ return null;
+ }
+
+ return itemCollector.update(target, request.getLevel().getGameTime());
+ return itemCollector.update(request);
+ }
+
+ @Override
@@ -1348,16 +1320,8 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+ return UNIVERSAL_ITEM_STORAGE;
+ }
+
+ public static List<ViewGroup<ItemStack>> containerGroup(Container container, Accessor<?> accessor) {
+ try {
+ return containerCache.get(container, () -> new ItemCollector<>(new ItemIterator.ContainerItemIterator(0))).update(container, accessor.getLevel().getGameTime());
+ } catch (ExecutionException e) {
+ return null;
+ }
+ }
+
+ public static ItemCollector<?> createItemCollector(Object target) {
+ if (target instanceof AbstractHorse) {
+ public static ItemCollector<?> createItemCollector(Accessor<?> request) {
+ if (request.getTarget() instanceof AbstractHorse) {
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> {
+ if (o instanceof AbstractHorse horse) {
+ return horse.inventory;
@@ -1368,8 +1332,9 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+
+ // TODO BlockEntity like fabric's ItemStorage
+
+ if (target instanceof Container) {
+ if (target instanceof ChestBlockEntity) {
+ final Container container = findContainer(request);
+ if (container != null) {
+ if (container instanceof ChestBlockEntity) {
+ return new ItemCollector<>(new ItemIterator.ContainerItemIterator(o -> {
+ if (o instanceof ChestBlockEntity blockEntity) {
+ if (blockEntity.getBlockState().getBlock() instanceof ChestBlock chestBlock) {
@@ -1392,11 +1357,117 @@ index 0000000000000000000000000000000000000000..7680ff97d99e15a9b3475ef83f7cfe34
+ return ItemCollector.EMPTY;
+ }
+
+ public static @Nullable Container findContainer(@NotNull Accessor<?> accessor) {
+ Object target = accessor.getTarget();
+ if (target == null && accessor instanceof BlockAccessor blockAccessor &&
+ blockAccessor.getBlock() instanceof WorldlyContainerHolder holder) {
+ return holder.getContainer(blockAccessor.getBlockState(), accessor.getLevel(), blockAccessor.getPosition());
+ } else if (target instanceof Container container) {
+ return container;
+ }
+ return null;
+ }
+
+ @Override
+ public int getDefaultPriority() {
+ return IServerExtensionProvider.super.getDefaultPriority() + 1000;
+ }
+}
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..8289b5c48213348a7346dfdbb30ee1b8787d2a2d
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/ItemStorageProvider.java
@@ -0,0 +1,88 @@
+package org.leavesmc.leaves.protocol.jade.provider;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.LockCode;
+import net.minecraft.world.RandomizableContainer;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
+import org.jetbrains.annotations.NotNull;
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
+import org.leavesmc.leaves.protocol.jade.util.CommonUtil;
+import org.leavesmc.leaves.protocol.jade.util.ItemCollector;
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class ItemStorageProvider<T extends Accessor<?>> implements IServerDataProvider<T> {
+
+ private static final StreamCodec<RegistryFriendlyByteBuf, Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>>> STREAM_CODEC = ViewGroup.listCodec(
+ ItemStack.OPTIONAL_STREAM_CODEC);
+
+ private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage");
+
+ public static ForBlock getBlock() {
+ return ForBlock.INSTANCE;
+ }
+
+ public static ForEntity getEntity() {
+ return ForEntity.INSTANCE;
+ }
+
+ public static class ForBlock extends ItemStorageProvider<BlockAccessor> {
+ private static final ForBlock INSTANCE = new ForBlock();
+ }
+
+ public static class ForEntity extends ItemStorageProvider<EntityAccessor> {
+ private static final ForEntity INSTANCE = new ForEntity();
+ }
+
+ public static void putData(CompoundTag tag, @NotNull Accessor<?> accessor) {
+ Object target = accessor.getTarget();
+ Player player = accessor.getPlayer();
+ Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>> entry = CommonUtil.getServerExtensionData(accessor, JadeProtocol.itemStorageProviders);
+ if (entry != null) {
+ List<ViewGroup<ItemStack>> groups = entry.getValue();
+ for (ViewGroup<ItemStack> group : groups) {
+ if (group.views.size() > ItemCollector.MAX_SIZE) {
+ group.views = group.views.subList(0, ItemCollector.MAX_SIZE);
+ }
+ }
+ tag.put(UNIVERSAL_ITEM_STORAGE.toString(), accessor.encodeAsNbt(STREAM_CODEC, entry));
+ return;
+ }
+ if (target instanceof RandomizableContainer containerEntity && containerEntity.getLootTable() != null) {
+ tag.putBoolean("Loot", true);
+ } else if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) {
+ if (te.lockKey != LockCode.NO_LOCK) {
+ tag.putBoolean("Locked", true);
+ }
+ }
+ }
+
+ @Override
+ public ResourceLocation getUid() {
+ return UNIVERSAL_ITEM_STORAGE;
+ }
+
+ @Override
+ public void appendServerData(CompoundTag tag, @NotNull T accessor) {
+ if (accessor.getTarget() instanceof AbstractFurnaceBlockEntity) {
+ return;
+ }
+ putData(tag, accessor);
+ }
+
+ @Override
+ public int getDefaultPriority() {
+ return 9999;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/StreamServerDataProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..52887edb3359c5eb1900cd1eec912e52afef2c9f
@@ -1776,105 +1847,6 @@ index 0000000000000000000000000000000000000000..a3937081bd923d3b6f2ee966dc95aa23
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ItemStorageProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ItemStorageProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4eb38d4b5d98a286964cdb68581bb9a2d836def
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/ItemStorageProvider.java
@@ -0,0 +1,92 @@
+package org.leavesmc.leaves.protocol.jade.provider.block;
+
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.network.RegistryFriendlyByteBuf;
+import net.minecraft.network.codec.StreamCodec;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.LockCode;
+import net.minecraft.world.RandomizableContainer;
+import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
+import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
+import org.jetbrains.annotations.NotNull;
+import org.leavesmc.leaves.protocol.jade.JadeProtocol;
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
+import org.leavesmc.leaves.protocol.jade.accessor.BlockAccessor;
+import org.leavesmc.leaves.protocol.jade.accessor.EntityAccessor;
+import org.leavesmc.leaves.protocol.jade.provider.IServerDataProvider;
+import org.leavesmc.leaves.protocol.jade.util.CommonUtil;
+import org.leavesmc.leaves.protocol.jade.util.ItemCollector;
+import org.leavesmc.leaves.protocol.jade.util.ViewGroup;
+
+import java.util.List;
+import java.util.Map;
+
+public abstract class ItemStorageProvider<T extends Accessor<?>> implements IServerDataProvider<T> {
+
+ private static final StreamCodec<RegistryFriendlyByteBuf, Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>>> STREAM_CODEC = ViewGroup.listCodec(
+ ItemStack.OPTIONAL_STREAM_CODEC);
+
+ private static final ResourceLocation UNIVERSAL_ITEM_STORAGE = JadeProtocol.mc_id("item_storage.default");
+
+ public static ForBlock getBlock() {
+ return ForBlock.INSTANCE;
+ }
+
+ public static ForEntity getEntity() {
+ return ForEntity.INSTANCE;
+ }
+
+ public static class ForBlock extends ItemStorageProvider<BlockAccessor> {
+ private static final ForBlock INSTANCE = new ForBlock();
+ }
+
+ public static class ForEntity extends ItemStorageProvider<EntityAccessor> {
+ private static final ForEntity INSTANCE = new ForEntity();
+ }
+
+ public static void putData(Accessor<?> accessor) {
+ CompoundTag tag = accessor.getServerData();
+ Object target = accessor.getTarget();
+ Player player = accessor.getPlayer();
+ Map.Entry<ResourceLocation, List<ViewGroup<ItemStack>>> entry = CommonUtil.getServerExtensionData(
+ accessor,
+ JadeProtocol.itemStorageProviders);
+ if (entry != null) {
+ List<ViewGroup<ItemStack>> groups = entry.getValue();
+ for (ViewGroup<ItemStack> group : groups) {
+ if (group.views.size() > ItemCollector.MAX_SIZE) {
+ group.views = group.views.subList(0, ItemCollector.MAX_SIZE);
+ }
+ }
+ tag.put(UNIVERSAL_ITEM_STORAGE.toString(), accessor.encodeAsNbt(STREAM_CODEC, entry));
+ return;
+ }
+ if (target instanceof RandomizableContainer containerEntity && containerEntity.getLootTable() != null) {
+ tag.putBoolean("Loot", true);
+ } else if (!player.isCreative() && !player.isSpectator() && target instanceof BaseContainerBlockEntity te) {
+ if (te.lockKey != LockCode.NO_LOCK) {
+ tag.putBoolean("Locked", true);
+ }
+ }
+ }
+
+ @Override
+ public ResourceLocation getUid() {
+ return UNIVERSAL_ITEM_STORAGE;
+ }
+
+ @Override
+ public void appendServerData(CompoundTag tag, @NotNull T accessor) {
+ if (accessor.getTarget() instanceof AbstractFurnaceBlockEntity) {
+ return;
+ }
+ putData(accessor);
+ }
+
+ @Override
+ public int getDefaultPriority() {
+ return 9999;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java b/src/main/java/org/leavesmc/leaves/protocol/jade/provider/block/JukeboxProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..0b6e224ebc8d6acdc29abf51f7d98b667baf0984
@@ -2830,10 +2802,10 @@ index 0000000000000000000000000000000000000000..137cdf619879390477b4fc8c4b7ecee5
+
diff --git a/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java
new file mode 100644
index 0000000000000000000000000000000000000000..769c331035e59408064b63a29d8bf2194b386aa0
index 0000000000000000000000000000000000000000..8f57cb0714dc684bd90325a6d2e84d5b1b303d6e
--- /dev/null
+++ b/src/main/java/org/leavesmc/leaves/protocol/jade/util/ItemCollector.java
@@ -0,0 +1,114 @@
@@ -0,0 +1,116 @@
+package org.leavesmc.leaves.protocol.jade.util;
+
+import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap;
@@ -2843,6 +2815,7 @@ index 0000000000000000000000000000000000000000..769c331035e59408064b63a29d8bf219
+import net.minecraft.world.item.Item;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.component.CustomData;
+import org.leavesmc.leaves.protocol.jade.accessor.Accessor;
+
+import java.util.List;
+import java.util.Locale;
@@ -2877,15 +2850,16 @@ index 0000000000000000000000000000000000000000..769c331035e59408064b63a29d8bf219
+ this.iterator = iterator;
+ }
+
+ public List<ViewGroup<ItemStack>> update(Object target, long gameTime) {
+ public List<ViewGroup<ItemStack>> update(Accessor<?> request) {
+ if (iterator == null) {
+ return null;
+ }
+ T container = iterator.find(target);
+ T container = iterator.find(request.getTarget());
+ if (container == null) {
+ return null;
+ }
+ long currentVersion = iterator.getVersion(container);
+ long gameTime = request.getLevel().getGameTime();
+ if (mergedResult != null && iterator.isFinished()) {
+ if (version == currentVersion) {
+ return mergedResult; // content not changed