From ae55e3544c11ffe4d283c01a7df1575f2d2477bb Mon Sep 17 00:00:00 2001 From: Nightenom <17338378+Nightenom@users.noreply.github.com> Date: Mon, 28 Oct 2024 08:12:06 +0100 Subject: [PATCH] Rework itemHandler extraction and add "show resources" to buildTool (#699) --- gradle.properties | 2 +- .../structurize/api/ItemStackUtils.java | 264 ++++++++++++------ .../ldtteam/structurize/api/ItemStorage.java | 10 + .../api/constants/WindowConstants.java | 2 + .../structurize/blueprints/v1/Blueprint.java | 3 + .../structurize/client/BlueprintHandler.java | 11 + .../structurize/client/BlueprintRenderer.java | 2 +- .../AbstractBlueprintManipulationWindow.java | 9 + .../client/gui/WindowBlockGetterContents.java | 131 +++++++++ .../structurize/client/gui/WindowScan.java | 2 +- .../structurize/commands/AbstractCommand.java | 8 +- .../placement/StructurePlacer.java | 6 +- .../handlers/placement/PlacementHandlers.java | 15 +- .../ldtteam/structurize/util/BlockUtils.java | 5 + .../resources/META-INF/accesstransformer.cfg | 4 + .../structurize/gui/layoutmanipulation.xml | 1 + .../assets/structurize/gui/windowcontents.xml | 37 +++ .../assets/structurize/lang/en_us.json | 7 +- 18 files changed, 405 insertions(+), 114 deletions(-) create mode 100644 src/main/java/com/ldtteam/structurize/client/gui/WindowBlockGetterContents.java create mode 100644 src/main/resources/assets/structurize/gui/windowcontents.xml diff --git a/gradle.properties b/gradle.properties index ddbd51fa4..d1eb2f49e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -12,7 +12,7 @@ javaVersion=21 useJavaToolChains=true #The currently running forge. -forgeVersion=21.1.4 +forgeVersion=21.1.72 fmlRange=[4,) forgeRange=[21.0.143,) diff --git a/src/main/java/com/ldtteam/structurize/api/ItemStackUtils.java b/src/main/java/com/ldtteam/structurize/api/ItemStackUtils.java index 2a4783e01..d095c9fb9 100644 --- a/src/main/java/com/ldtteam/structurize/api/ItemStackUtils.java +++ b/src/main/java/com/ldtteam/structurize/api/ItemStackUtils.java @@ -1,38 +1,36 @@ package com.ldtteam.structurize.api; +import com.ldtteam.common.fakelevel.SingleBlockFakeLevel.SidedSingleBlockFakeLevel; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.HolderLookup; import net.minecraft.core.component.DataComponentMap; import net.minecraft.core.component.DataComponentType; import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; -import net.minecraft.nbt.ListTag; -import net.minecraft.nbt.Tag; +import net.minecraft.world.Container; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.ArmorStand; import net.minecraft.world.entity.decoration.ItemFrame; -import net.minecraft.world.entity.vehicle.ContainerEntity; +import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Items; -import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.item.SpawnEggItem; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.HitResult; -import net.minecraft.world.phys.Vec3; -import net.neoforged.neoforge.capabilities.Capabilities; +import net.minecraft.world.phys.EntityHitResult; +import net.neoforged.neoforge.capabilities.Capabilities.ItemHandler; import net.neoforged.neoforge.items.IItemHandler; -import org.jetbrains.annotations.NotNull; +import net.neoforged.neoforge.items.wrapper.InvWrapper; import org.jetbrains.annotations.Nullable; - import java.util.*; -import java.util.stream.Collectors; +import java.util.function.Consumer; /** * Utility methods for the inventories. */ public final class ItemStackUtils { + public static final SidedSingleBlockFakeLevel ITEM_HANDLER_FAKE_LEVEL = new SidedSingleBlockFakeLevel(); + /** * Private constructor to hide the implicit one. */ @@ -44,87 +42,98 @@ private ItemStackUtils() } /** - * Get itemStack of tileEntityData. Retrieve the data from the tileEntity. + * Get itemStack of tileEntityData. Retrieve the data from the tileEntity. Including recursive content, eg. shulkers * * @param compound the tileEntity stored in a compound. * @param state the block. + * @param level real vanilla instance for fakeLevel * @return the list of itemstacks. + * @see #getListOfStackForEntity(Entity, BlockPos) */ - public static List getItemStacksOfTileEntity(final CompoundTag compound, final BlockState state, final HolderLookup.Provider provider) + public static List getItemStacksOfTileEntity(final CompoundTag compound, final BlockState state, final Level level) { - if (state.getBlock() instanceof BaseEntityBlock && compound.contains("Items")) + if (compound == null) { - // because we're constructing the BlockEntity out-of-world below, chests (and perhaps a few others) - // can't generate an IItemHandler for us, so we need to read the contents manually. - // this could be removed if we always get a "real" BE from a world, but we're called both from a - // real world and from a schematic non-world, and the latter still breaks. - return getItemStacksFromNbt(compound, provider); + return List.of(); } - BlockPos blockpos = new BlockPos(compound.getInt("x"), compound.getInt("y"), compound.getInt("z")); - final BlockEntity tileEntity = BlockEntity.loadStatic(blockpos, state, compound, provider); + final BlockPos blockpos = new BlockPos(compound.getInt("x"), compound.getInt("y"), compound.getInt("z")); + final BlockEntity tileEntity = BlockEntity.loadStatic(blockpos, state, compound, level.registryAccess()); if (tileEntity == null) { - return Collections.emptyList(); + return List.of(); } - final List items = new ArrayList<>(); - for (final IItemHandler handler : getItemHandlersFromProvider(tileEntity)) - { - for (int slot = 0; slot < handler.getSlots(); slot++) - { - final ItemStack stack = handler.getStackInSlot(slot); - if (!ItemStackUtils.isEmpty(stack)) - { - items.add(stack); - } - } - } - - return items; + return ITEM_HANDLER_FAKE_LEVEL.get(level).useFakeLevelContext(state, tileEntity, level, fakeLevel -> { + final List items = new ArrayList<>(); + getItemHandlersFromProvider(tileEntity, blockpos, state).forEach(itemHandler -> deepExtractItemHandler(itemHandler, items::add)); + return items; + }); } - @NotNull - private static List getItemStacksFromNbt(@NotNull final CompoundTag compound, final HolderLookup.Provider provider) + /** + * @param handler root itemHandler to extract + * @param sink where to put content of all found itemStacks, incl. recursive contents + */ + public static void deepExtractItemHandler(@Nullable final IItemHandler handler, final Consumer sink) { - final List items = new ArrayList<>(); - final ListTag listtag = compound.getList("Items", Tag.TAG_COMPOUND); + if (handler == null) + { + return; + } - for (int i = 0; i < listtag.size(); ++i) + for (int slot = 0; slot < handler.getSlots(); slot++) { - final CompoundTag compoundtag = listtag.getCompound(i); - final ItemStack stack = ItemStack.parseOptional(provider, compoundtag); - if (!stack.isEmpty()) + final ItemStack stack = handler.getStackInSlot(slot).copy(); + if (!ItemStackUtils.isEmpty(stack)) { - items.add(stack); + sink.accept(stack); + deepExtractItemHandler(stack.getCapability(ItemHandler.ITEM), sink); } } - - return items; } /** - * Method to get all the IItemHandlers from a given Provider. + * Method to get sensible item handlers from blockEntity. Tries to provide whole deduplicated content. However this assumption is + * weak. There still might be content (in returned set) that is not present at all or duplicated. * * @param provider The provider to get the IItemHandlers from. * @return A list with all the unique IItemHandlers a provider has. */ - public static Set getItemHandlersFromProvider(final BlockEntity provider) + public static Set getItemHandlersFromProvider(@Nullable final BlockEntity provider, final BlockPos pos, final BlockState state) { + if (provider == null) + { + return Set.of(); + } + if (provider instanceof final IItemHandler itemHandler) + { + // be is itemHandler itself = easy + return Set.of(itemHandler); + } + if (provider instanceof final Container container) + { + // be is vanilla container = itemHandler cap might return SidedInvWrapper with partial inv view + return Set.of(new InvWrapper(container)); + } + + final IItemHandler unsidedItemHandler = provider.getLevel().getCapability(ItemHandler.BLOCK, pos, state, provider, null); + if (unsidedItemHandler != null) + { + // weak assumption of unsided being partial view only + return Set.of(unsidedItemHandler); + } + final Set handlerSet = new HashSet<>(); for (final Direction side : Direction.values()) { - final IItemHandler cap = Capabilities.ItemHandler.BLOCK.getCapability(provider.getLevel(), provider.getBlockPos(), provider.getBlockState(), provider, side); + final IItemHandler cap = provider.getLevel().getCapability(ItemHandler.BLOCK, pos, state, provider, side); if (cap != null) { handlerSet.add(cap); } } - final IItemHandler cap = Capabilities.ItemHandler.BLOCK.getCapability(provider.getLevel(), provider.getBlockPos(), provider.getBlockState(), provider, null); - if (cap != null) - { - handlerSet.add(cap); - } + // weakest assumption of sided itemHandler having disjoint sides return handlerSet; } @@ -158,54 +167,123 @@ public static int getSize(final ItemStack stack) } /** - * Get the list of required resources for entities. + * @deprecated {@link #getListOfStackForEntity(Entity)} + */ + @Deprecated(forRemoval = true, since = "1.21.1") + public static List getListOfStackForEntity(final Entity entity, final BlockPos pos) + { + return getListOfStackForEntity(entity); + } + + /** + * Get the list of required resources for entities + entity spawning item. Same implementation as blockEntity logic. Including recursive content, eg. shulkers * * @param entity the entity object. - * @param pos the placer pos.. * @return a list of stacks. + * @see #getItemStacksOfTileEntity(BlockEntity) */ - public static List getListOfStackForEntity(final Entity entity, final BlockPos pos) + public static List getListOfStackForEntity(final Entity entity) { - if (entity != null) + if (entity == null) + { + return List.of(); + } + + final List request = new ArrayList<>(); + + // process entity itself + final ItemStack spawnItem = getEntitySpawningItem(entity); + if (spawnItem != null && !(spawnItem.getItem() instanceof SpawnEggItem)) { - final List request = new ArrayList<>(); - if (entity instanceof final ItemFrame itemFrame) + request.add(spawnItem); + } + + // process entity contents + request.addAll(getItemStacksOfEntity(entity)); + + return request.stream().filter(stack -> !stack.isEmpty()).toList(); + } + + /** + * Get the list of required resources for entities. Same implementation as blockEntity logic. Including recursive content, eg. shulkers + * + * @param entity the entity object. + * @return a list of stacks. + * @see #getItemStacksOfTileEntity(BlockEntity) + */ + public static List getItemStacksOfEntity(final Entity entity) + { + if (entity == null) + { + return List.of(); + } + + final List entityContent = new ArrayList<>(); + + IItemHandler itemHandler = null; + if (entity instanceof final IItemHandler iitemHandler) + { + // entity is itemHandler itself = easy + itemHandler = iitemHandler; + } + else if (entity instanceof final Container container) + { + // entity is vanilla container = itemHandler cap might return SidedInvWrapper with partial inv view + itemHandler = new InvWrapper(container); + } + if (itemHandler == null) + { + itemHandler = entity.getCapability(ItemHandler.ENTITY); + } + if (itemHandler == null) + { + // weak assumption of unsided being partial view only + itemHandler = entity.getCapability(ItemHandler.ENTITY_AUTOMATION, null); + } + + if (itemHandler != null) + { + deepExtractItemHandler(itemHandler, entityContent::add); + } + // some vanilla entities "have inventory" but not forge cap yet + else if (entity instanceof final ItemFrame itemFrame) + { + final ItemStack stack = itemFrame.getItem(); + entityContent.add(stack); + deepExtractItemHandler(stack.getCapability(ItemHandler.ITEM), entityContent::add); + } + else if (entity instanceof final ItemEntity itemEntity) + { + final ItemStack stack = itemEntity.getItem(); + entityContent.add(stack); + deepExtractItemHandler(stack.getCapability(ItemHandler.ITEM), entityContent::add); + } + else // sided item handler + { + for (final Direction side : Direction.values()) { - final ItemStack stack = itemFrame.getItem(); - if (!ItemStackUtils.isEmpty(stack)) + final IItemHandler cap = entity.getCapability(ItemHandler.ENTITY_AUTOMATION, side); + if (cap != null) { - stack.setCount(1); - request.add(stack); + deepExtractItemHandler(cap, entityContent::add); } - request.add(new ItemStack(Items.ITEM_FRAME, 1)); - } - else if (entity instanceof final ArmorStand armorStand) - { - request.add(entity.getPickedResult(new HitResult(Vec3.atLowerCornerOf(pos)) { - @Override - public Type getType() - { - return Type.ENTITY; - } - })); - armorStand.getArmorSlots().forEach(request::add); - armorStand.getHandSlots().forEach(request::add); - } - else if (entity instanceof ContainerEntity containerEntity) - { - request.add(entity.getPickedResult(new HitResult(Vec3.atLowerCornerOf(pos)) { - @Override - public Type getType() - { - return Type.ENTITY; - } - })); - request.addAll(containerEntity.getItemStacks()); } + } + + return entityContent; + } - return request.stream().filter(stack -> !stack.isEmpty()).collect(Collectors.toList()); + /** + * @return item that should spawn given entity + */ + @Nullable + public static ItemStack getEntitySpawningItem(final Entity entity) + { + if (entity instanceof final ItemFrame itemFrame) + { + return itemFrame.getFrameItemStack(); } - return Collections.emptyList(); + return entity.getPickedResult(new EntityHitResult(entity)); } /** diff --git a/src/main/java/com/ldtteam/structurize/api/ItemStorage.java b/src/main/java/com/ldtteam/structurize/api/ItemStorage.java index 23bb44c33..6c36acf19 100644 --- a/src/main/java/com/ldtteam/structurize/api/ItemStorage.java +++ b/src/main/java/com/ldtteam/structurize/api/ItemStorage.java @@ -190,4 +190,14 @@ public int getDamageValue() { return stack.getDamageValue(); } + + /** + * Adder for the quantity. + * + * @param amount the amount to be added. + */ + public void addAmount(final int amount) + { + setAmount(getAmount() + amount); + } } \ No newline at end of file diff --git a/src/main/java/com/ldtteam/structurize/api/constants/WindowConstants.java b/src/main/java/com/ldtteam/structurize/api/constants/WindowConstants.java index 618497ed2..81d7d5747 100644 --- a/src/main/java/com/ldtteam/structurize/api/constants/WindowConstants.java +++ b/src/main/java/com/ldtteam/structurize/api/constants/WindowConstants.java @@ -327,6 +327,8 @@ public final class WindowConstants */ public static final String REMOVE_FILTERED = "removefiltered"; + public static final String BUTTON_CONTENTS = "contents"; + /** * public constructor to hide implicit public one. */ diff --git a/src/main/java/com/ldtteam/structurize/blueprints/v1/Blueprint.java b/src/main/java/com/ldtteam/structurize/blueprints/v1/Blueprint.java index a771e084e..5cd3feaee 100644 --- a/src/main/java/com/ldtteam/structurize/blueprints/v1/Blueprint.java +++ b/src/main/java/com/ldtteam/structurize/blueprints/v1/Blueprint.java @@ -2,6 +2,7 @@ import com.ldtteam.structurize.api.Log; import com.ldtteam.common.fakelevel.IFakeLevelBlockGetter; +import com.ldtteam.common.util.BlockToItemHelper; import com.ldtteam.structurize.api.BlockPosUtil; import com.ldtteam.structurize.api.ItemStackUtils; import com.ldtteam.structurize.blockentities.BlockEntityTagSubstitution; @@ -517,8 +518,10 @@ public CompoundTag getTileEntityData(final BlockPos worldPos, final BlockPos str * * @param pos the pos its at. * @return an item or null if not initialized. + * @deprecated use {@link BlockToItemHelper} */ @Nullable + @Deprecated(forRemoval = true, since = "1.21.1") public Item getItem(final BlockPos pos) { @Nullable diff --git a/src/main/java/com/ldtteam/structurize/client/BlueprintHandler.java b/src/main/java/com/ldtteam/structurize/client/BlueprintHandler.java index a544af122..be7597bc0 100644 --- a/src/main/java/com/ldtteam/structurize/client/BlueprintHandler.java +++ b/src/main/java/com/ldtteam/structurize/client/BlueprintHandler.java @@ -7,8 +7,10 @@ import com.ldtteam.structurize.storage.rendering.types.BlueprintPreviewData; import net.minecraft.client.Minecraft; import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.Entity; import net.neoforged.neoforge.client.event.RenderLevelStageEvent; import java.util.Collection; +import java.util.List; import java.util.concurrent.TimeUnit; /** @@ -125,4 +127,13 @@ public void drawAtListOfPositions(final BlueprintPreviewData previewData, Minecraft.getInstance().getProfiler().pop(); } + + /** + * @return list of entities for instantiated renderer (potentially immediately invalid), else empty list + */ + public List getOptionalEntitiesForBlueprint(final BlueprintPreviewData previewData) + { + final BlueprintRenderer renderer = rendererCache.getIfPresent(previewData.getRenderKey()); + return renderer == null ? List.of() : renderer.entities; + } } diff --git a/src/main/java/com/ldtteam/structurize/client/BlueprintRenderer.java b/src/main/java/com/ldtteam/structurize/client/BlueprintRenderer.java index 876fcb170..8f7570ab0 100644 --- a/src/main/java/com/ldtteam/structurize/client/BlueprintRenderer.java +++ b/src/main/java/com/ldtteam/structurize/client/BlueprintRenderer.java @@ -94,7 +94,7 @@ public class BlueprintRenderer implements AutoCloseable private static boolean hasWarnedExceptions = false; private final BlueprintBlockAccess blockAccess; - private List entities; + List entities = List.of(); private List tileEntities; private Map vertexBuffers; private long lastGameTime; diff --git a/src/main/java/com/ldtteam/structurize/client/gui/AbstractBlueprintManipulationWindow.java b/src/main/java/com/ldtteam/structurize/client/gui/AbstractBlueprintManipulationWindow.java index 9033aa206..5cc03667c 100644 --- a/src/main/java/com/ldtteam/structurize/client/gui/AbstractBlueprintManipulationWindow.java +++ b/src/main/java/com/ldtteam/structurize/client/gui/AbstractBlueprintManipulationWindow.java @@ -15,6 +15,7 @@ import com.ldtteam.structurize.api.constants.Constants; import com.ldtteam.structurize.blueprints.v1.Blueprint; import com.ldtteam.structurize.blueprints.v1.BlueprintTagUtils; +import com.ldtteam.structurize.client.BlueprintHandler; import com.ldtteam.structurize.client.ModKeyMappings; import com.ldtteam.structurize.network.messages.BuildToolPlacementMessage; import com.ldtteam.structurize.storage.ISurvivalBlueprintHandler; @@ -113,6 +114,7 @@ public AbstractBlueprintManipulationWindow(@NotNull final String resourceId, @Nu registerButton(BUTTON_ROTATE_RIGHT, this::rotateRightClicked); registerButton(BUTTON_ROTATE_LEFT, this::rotateLeftClicked); registerButton(BUTTON_SETTINGS, this::settingsClicked); + registerButton(BUTTON_CONTENTS, this::openContents); settingsList = findPaneOfTypeByID("settinglist", ScrollingList.class); placementOptionsList = findPaneOfTypeByID("placement", ScrollingList.class); @@ -259,6 +261,7 @@ public void onUpdate() { findPaneOfTypeByID("tip", Text.class).setVisible(false); } + findPaneByID(BUTTON_CONTENTS).setVisible(RenderingCache.getOrCreateBlueprintPreviewData(bluePrintId).getBlueprint() != null); } @Override @@ -542,6 +545,12 @@ private void rotateLeftClicked() updateRotationState(); } + private void openContents() + { + final BlueprintPreviewData previewData = RenderingCache.getOrCreateBlueprintPreviewData(bluePrintId); + new WindowBlockGetterContents(previewData.getBlueprint(), Minecraft.getInstance().level, BlueprintHandler.getInstance().getOptionalEntitiesForBlueprint(previewData)).openAsLayer(); + } + /* * ---------------- Miscellaneous ---------------- */ diff --git a/src/main/java/com/ldtteam/structurize/client/gui/WindowBlockGetterContents.java b/src/main/java/com/ldtteam/structurize/client/gui/WindowBlockGetterContents.java new file mode 100644 index 000000000..cf55283e3 --- /dev/null +++ b/src/main/java/com/ldtteam/structurize/client/gui/WindowBlockGetterContents.java @@ -0,0 +1,131 @@ +package com.ldtteam.structurize.client.gui; + +import com.ldtteam.blockui.Pane; +import com.ldtteam.blockui.controls.ItemIcon; +import com.ldtteam.blockui.controls.Text; +import com.ldtteam.blockui.views.BOWindow; +import com.ldtteam.blockui.views.ScrollingList; +import com.ldtteam.common.util.BlockToItemHelper; +import com.ldtteam.structurize.api.ItemStackUtils; +import com.ldtteam.structurize.api.ItemStorage; +import com.ldtteam.structurize.api.constants.Constants; +import com.ldtteam.structurize.blueprints.v1.Blueprint; +import net.minecraft.client.Minecraft; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Computes as exact as possible contents of given AABB. This should be used as base for item related analysis + */ +public class WindowBlockGetterContents extends BOWindow +{ + public WindowBlockGetterContents(final Blueprint blueprint, final Level realLevel, final Collection boundedEntities) + { + this(blueprint, + realLevel, + new BlockPos(blueprint.getMinX(), blueprint.getMinBuildHeight(), blueprint.getMinZ()), + new BlockPos(blueprint.getMaxX() - 1, blueprint.getMaxBuildHeight() - 1, blueprint.getMaxZ() - 1), + boundedEntities); + } + + /** + * @param blockGetter level + * @param realLevel vanilla level instance in case of blockGetter not being one + * @param start inclusive from + * @param end inclusive to + * @param boundedEntities entities bounded by [start, end] parameters + */ + public WindowBlockGetterContents(final BlockGetter blockGetter, + @Nullable final Level realLevel, + final BlockPos start, + final BlockPos end, + final Collection boundedEntities) + { + super(Constants.resLocStruct("gui/windowcontents.xml")); + + final Map blocks = new HashMap<>(); + final Map blockItemHandlers = new HashMap<>(); + final Map entities = new HashMap<>(); + final Map entityItemHandlers = new HashMap<>(); + + for (final BlockPos pos : BlockPos.betweenClosed(start, end)) + { + final BlockState blockState = blockGetter.getBlockState(pos); + final BlockEntity blockEntity = blockGetter.getBlockEntity(pos); + + // blockstate + addAmountToMap(blocks, BlockToItemHelper.getItemStack(blockState, blockEntity, Minecraft.getInstance().player)); + + // blockentity content + if (blockEntity != null && blockEntity.getLevel() == null) + { + ItemStackUtils.ITEM_HANDLER_FAKE_LEVEL.get(realLevel).withFakeLevelContext(blockState, blockEntity, realLevel, level -> { + ItemStackUtils.getItemHandlersFromProvider(blockEntity, pos, blockState) + .forEach(i -> ItemStackUtils.deepExtractItemHandler(i, stack -> addAmountToMap(blockItemHandlers, stack))); + }); + } + else + { + ItemStackUtils.getItemHandlersFromProvider(blockEntity, pos, blockState) + .forEach(i -> ItemStackUtils.deepExtractItemHandler(i, stack -> addAmountToMap(blockItemHandlers, stack))); + } + } + + for (final Entity entity : boundedEntities) + { + addAmountToMap(entities, ItemStackUtils.getEntitySpawningItem(entity)); + ItemStackUtils.getItemStacksOfEntity(entity).forEach(stack -> addAmountToMap(entityItemHandlers, stack)); + } + + final List blockList = new ArrayList<>(blocks.values()); + final List blockItemHandlerList = new ArrayList<>(blockItemHandlers.values()); + final List entityList = new ArrayList<>(entities.values()); + final List entityItemHandlerList = new ArrayList<>(entityItemHandlers.values()); + + final Comparator alphabeticalOrder = + (i1, i2) -> i1.getItemStack().getHoverName().getString().compareTo(i2.getItemStack().getHoverName().getString()); + blockList.sort(alphabeticalOrder); + blockItemHandlerList.sort(alphabeticalOrder); + entityList.sort(alphabeticalOrder); + entityItemHandlerList.sort(alphabeticalOrder); + + findPaneOfTypeByID("blocks", ScrollingList.class).setDataProvider(blockList::size, + (idx, pane) -> updateItem(blockList.get(idx), pane)); + findPaneOfTypeByID("block_item_handlers", ScrollingList.class).setDataProvider(blockItemHandlerList::size, + (idx, pane) -> updateItem(blockItemHandlerList.get(idx), pane)); + findPaneOfTypeByID("entities", ScrollingList.class).setDataProvider(entityList::size, + (idx, pane) -> updateItem(entityList.get(idx), pane)); + findPaneOfTypeByID("entity_item_handlers", ScrollingList.class).setDataProvider(entityItemHandlerList::size, + (idx, pane) -> updateItem(entityItemHandlerList.get(idx), pane)); + } + + private void addAmountToMap(final Map itemSet, @Nullable final ItemStack blockAsItem) + { + if (blockAsItem != null) + { + itemSet.computeIfAbsent(blockAsItem.getItem(), i -> new ItemStorage(blockAsItem.copyWithCount(1), 0, true)) + .addAmount(Math.max(1, blockAsItem.getCount())); + } + } + + private void updateItem(final ItemStorage itemStorage, final Pane pane) + { + pane.findPaneOfTypeByID("icon", ItemIcon.class).setItem(itemStorage.getItemStack()); + pane.findPaneOfTypeByID("registry_key", Text.class).setText(itemStorage.getItemStack().getHoverName()); + pane.findPaneOfTypeByID("amount", Text.class).setText(Component.literal(Integer.toString(itemStorage.getAmount()))); + } +} diff --git a/src/main/java/com/ldtteam/structurize/client/gui/WindowScan.java b/src/main/java/com/ldtteam/structurize/client/gui/WindowScan.java index 3b4d3ba3c..06f6c0704 100644 --- a/src/main/java/com/ldtteam/structurize/client/gui/WindowScan.java +++ b/src/main/java/com/ldtteam/structurize/client/gui/WindowScan.java @@ -478,7 +478,7 @@ private void updateResources() boolean handled = false; for (final IPlacementHandler handler : PlacementHandlers.handlers) { - if (handler.canHandle(world, BlockPos.ZERO, blockState)) + if (handler.canHandle(world, here, blockState)) { final List itemList = handler.getRequiredItems(world, here, blockState, tileEntity == null ? null : tileEntity.saveWithFullMetadata(world.registryAccess()), true); for (final ItemStack stack : itemList) diff --git a/src/main/java/com/ldtteam/structurize/commands/AbstractCommand.java b/src/main/java/com/ldtteam/structurize/commands/AbstractCommand.java index efaee7e7f..dd5afefab 100644 --- a/src/main/java/com/ldtteam/structurize/commands/AbstractCommand.java +++ b/src/main/java/com/ldtteam/structurize/commands/AbstractCommand.java @@ -5,9 +5,7 @@ import java.util.Optional; import java.util.function.Supplier; import com.ldtteam.structurize.api.constants.Constants; -import com.ldtteam.common.language.LanguageHandler; import com.mojang.brigadier.CommandDispatcher; -import com.mojang.brigadier.LiteralMessage; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.builder.LiteralArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; @@ -15,6 +13,7 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands.CommandSelection; +import net.minecraft.network.chat.Component; import net.minecraft.util.Tuple; /** @@ -73,7 +72,7 @@ protected static RequiredArgumentBuilder newArgument( */ public static void throwSyntaxException(final String key) throws CommandSyntaxException { - throw new CommandSyntaxException(new StructurizeCommandExceptionType(), new LiteralMessage(LanguageHandler.translateKey(key))); + throw new CommandSyntaxException(new StructurizeCommandExceptionType(), Component.translatable(key)); } /** @@ -84,8 +83,7 @@ public static void throwSyntaxException(final String key) throws CommandSyntaxEx */ public static void throwSyntaxException(final String key, final Object... format) throws CommandSyntaxException { - throw new CommandSyntaxException(new StructurizeCommandExceptionType(), - new LiteralMessage(LanguageHandler.translateKeyWithFormat(key, format))); + throw new CommandSyntaxException(new StructurizeCommandExceptionType(), Component.translatable(key, format)); } /** diff --git a/src/main/java/com/ldtteam/structurize/placement/StructurePlacer.java b/src/main/java/com/ldtteam/structurize/placement/StructurePlacer.java index 87c0d5b56..2d58dbac6 100644 --- a/src/main/java/com/ldtteam/structurize/placement/StructurePlacer.java +++ b/src/main/java/com/ldtteam/structurize/placement/StructurePlacer.java @@ -282,7 +282,7 @@ public BlockPlacementResult handleBlockPlacement( continue; } - List requiredItems = ItemStackUtils.getListOfStackForEntity(entity, pos); + List requiredItems = ItemStackUtils.getListOfStackForEntity(entity); if (!handler.isCreative()) { if (requiredItems == null) @@ -465,7 +465,7 @@ public BlockPlacementResult handleEntitySpawn( continue; } - List requiredItems = ItemStackUtils.getListOfStackForEntity(entity, pos); + List requiredItems = ItemStackUtils.getListOfStackForEntity(entity); if (!handler.isCreative()) { if (requiredItems == null) @@ -620,7 +620,7 @@ public BlockPlacementResult getResourceRequirements( continue; } - requiredItems.addAll(ItemStackUtils.getListOfStackForEntity(entity, pos)); + requiredItems.addAll(ItemStackUtils.getListOfStackForEntity(entity)); } } } diff --git a/src/main/java/com/ldtteam/structurize/placement/handlers/placement/PlacementHandlers.java b/src/main/java/com/ldtteam/structurize/placement/handlers/placement/PlacementHandlers.java index bed161e83..deac9279b 100644 --- a/src/main/java/com/ldtteam/structurize/placement/handlers/placement/PlacementHandlers.java +++ b/src/main/java/com/ldtteam/structurize/placement/handlers/placement/PlacementHandlers.java @@ -12,7 +12,6 @@ import com.ldtteam.structurize.api.RotationMirror; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.core.HolderLookup; import net.minecraft.nbt.CompoundTag; import net.minecraft.tags.BlockTags; import net.minecraft.world.entity.Entity; @@ -241,7 +240,7 @@ public List getRequiredItems( @Nullable final CompoundTag tileEntityData, final boolean complete) { - final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world.registryAccess())); + final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world)); itemList.add(BlockUtils.getItemStackFromBlockState(blockState)); itemList.removeIf(ItemStackUtils::isEmpty); @@ -742,7 +741,7 @@ public List getRequiredItems( @Nullable final CompoundTag tileEntityData, final boolean complete) { - final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world.registryAccess())); + final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world)); itemList.add(BlockUtils.getItemStackFromBlockState(blockState)); itemList.removeIf(ItemStackUtils::isEmpty); return itemList; @@ -777,7 +776,7 @@ public ActionProcessingResult handle( try { // Try detecting inventory content. - ItemStackUtils.getItemStacksOfTileEntity(tileEntityData, blockState, world.registryAccess()); + ItemStackUtils.getItemStacksOfTileEntity(tileEntityData, blockState, world); } catch (final Exception ex) { @@ -803,7 +802,7 @@ public List getRequiredItems( { final List itemList = new ArrayList<>(); itemList.add(BlockUtils.getItemStackFromBlockState(blockState)); - itemList.addAll(getItemsFromTileEntity(tileEntityData, blockState, world.registryAccess())); + itemList.addAll(getItemsFromTileEntity(tileEntityData, blockState, world)); itemList.removeIf(ItemStackUtils::isEmpty); @@ -889,7 +888,7 @@ public List getRequiredItems( @Nullable final CompoundTag tileEntityData, final boolean complete) { - final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world.registryAccess())); + final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world)); itemList.add(BlockUtils.getItemStackFromBlockState(blockState)); itemList.removeIf(ItemStackUtils::isEmpty); return itemList; @@ -971,7 +970,7 @@ public List getRequiredItems( @Nullable final CompoundTag tileEntityData, final boolean complete) { - final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world.registryAccess())); + final List itemList = new ArrayList<>(getItemsFromTileEntity(tileEntityData, blockState, world)); itemList.add(BlockUtils.getItemStackFromBlockState(blockState)); itemList.removeIf(ItemStackUtils::isEmpty); return itemList; @@ -1079,7 +1078,7 @@ public static List getRequiredItemsForState(final Level world, final * @param blockState the block. * @return the required list. */ - public static List getItemsFromTileEntity(final CompoundTag tileEntityData, final BlockState blockState, final HolderLookup.Provider provider) + public static List getItemsFromTileEntity(final CompoundTag tileEntityData, final BlockState blockState, final Level provider) { if (tileEntityData == null) { diff --git a/src/main/java/com/ldtteam/structurize/util/BlockUtils.java b/src/main/java/com/ldtteam/structurize/util/BlockUtils.java index f823362e0..a41050eff 100644 --- a/src/main/java/com/ldtteam/structurize/util/BlockUtils.java +++ b/src/main/java/com/ldtteam/structurize/util/BlockUtils.java @@ -1,5 +1,6 @@ package com.ldtteam.structurize.util; +import com.ldtteam.common.util.BlockToItemHelper; import com.ldtteam.domumornamentum.client.model.data.MaterialTextureData; import com.ldtteam.domumornamentum.entity.block.MateriallyTexturedBlockEntity; import com.ldtteam.structurize.api.ItemStackUtils; @@ -264,6 +265,7 @@ public static boolean isWater(final BlockState iBlockState) return iBlockState.getBlock() == Blocks.WATER; } + @Deprecated(forRemoval = true, since = "1.21") private static Item getItem(final BlockState blockState) { final Block block = blockState.getBlock(); @@ -304,6 +306,7 @@ else if (block == Blocks.BAMBOO_SAPLING) } } + @Deprecated(forRemoval = true, since = "1.21") private static Item getItemFromBlock(final Block block) { return GameData.getBlockItemMap().get(block); @@ -434,7 +437,9 @@ else if (stack.getItem() instanceof final BlockItem blockItem) * * @param blockState the block and state we are creating an ItemStack for. * @return ItemStack fromt the BlockState. + * @see BlockToItemHelper */ + @Deprecated(forRemoval = true, since = "1.21") public static ItemStack getItemStackFromBlockState(final BlockState blockState) { if (blockState.getBlock() instanceof final LiquidBlock liquid) diff --git a/src/main/resources/META-INF/accesstransformer.cfg b/src/main/resources/META-INF/accesstransformer.cfg index a2f065ec3..8fa4e81b1 100644 --- a/src/main/resources/META-INF/accesstransformer.cfg +++ b/src/main/resources/META-INF/accesstransformer.cfg @@ -21,3 +21,7 @@ public net.minecraft.world.level.levelgen.SurfaceRules$SurfaceRule # keybinds public net.minecraft.client.KeyMapping clickCount + +# itemHandler +public net.minecraft.world.entity.decoration.GlowItemFrame getFrameItemStack()Lnet/minecraft/world/item/ItemStack; +public net.minecraft.world.entity.decoration.ItemFrame getFrameItemStack()Lnet/minecraft/world/item/ItemStack; diff --git a/src/main/resources/assets/structurize/gui/layoutmanipulation.xml b/src/main/resources/assets/structurize/gui/layoutmanipulation.xml index 8b4c9f081..94f98cc71 100644 --- a/src/main/resources/assets/structurize/gui/layoutmanipulation.xml +++ b/src/main/resources/assets/structurize/gui/layoutmanipulation.xml @@ -32,4 +32,5 @@