Skip to content

Commit

Permalink
finish
Browse files Browse the repository at this point in the history
  • Loading branch information
Nightenom committed Oct 20, 2024
1 parent cdf463b commit 3d9d0ff
Show file tree
Hide file tree
Showing 14 changed files with 343 additions and 65 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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,)
Expand Down
198 changes: 141 additions & 57 deletions src/main/java/com/ldtteam/structurize/api/ItemStackUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,17 @@
import net.minecraft.world.entity.decoration.ItemFrame;
import net.minecraft.world.entity.vehicle.ContainerEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
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 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.
Expand All @@ -44,48 +43,70 @@ 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<ItemStack> getItemStacksOfTileEntity(final CompoundTag compound, final BlockState state, final Level level)
{
if (compound == null)
{
return List.of();
}

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();
}

return itemHandlerFakeLevel.get(level).useFakeLevelContext(state, tileEntity, level, fakeLevel -> {
final List<ItemStack> items = new ArrayList<>();
for (final IItemHandler handler : getItemHandlersFromProvider(tileEntity))
{
for (int slot = 0; slot < handler.getSlots(); slot++)
{
final ItemStack stack = handler.getStackInSlot(slot).copy();
if (!ItemStackUtils.isEmpty(stack))
{
items.add(stack);
}
}
}
getItemHandlersFromProvider(tileEntity).forEach(itemHandler -> deepExtractItemHandler(itemHandler, items::add));
return items;
});
}

/**
* @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<ItemStack> sink)
{
if (handler == null)
{
return;
}

for (int slot = 0; slot < handler.getSlots(); slot++)
{
final ItemStack stack = handler.getStackInSlot(slot).copy();
if (!ItemStackUtils.isEmpty(stack))
{
sink.accept(stack);
deepExtractItemHandler(stack.getCapability(ItemHandler.ITEM), sink);
}
}
}

/**
* 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<IItemHandler> getItemHandlersFromProvider(final BlockEntity provider)
public static Set<IItemHandler> getItemHandlersFromProvider(@Nullable final BlockEntity provider)
{
if (provider == null)
{
return Set.of();
}
if (provider instanceof final IItemHandler itemHandler)
{
// be is itemHandler itself = easy
Expand All @@ -97,7 +118,7 @@ public static Set<IItemHandler> getItemHandlersFromProvider(final BlockEntity pr
return Set.of(new InvWrapper(container));
}

final IItemHandler unsidedItemHandler = Capabilities.ItemHandler.BLOCK.getCapability(provider.getLevel(), provider.getBlockPos(), provider.getBlockState(), provider, null);
final IItemHandler unsidedItemHandler = ItemHandler.BLOCK.getCapability(provider.getLevel(), provider.getBlockPos(), provider.getBlockState(), provider, null);
if (unsidedItemHandler != null)
{
// weak assumption of unsided being partial view only
Expand All @@ -107,7 +128,7 @@ public static Set<IItemHandler> getItemHandlersFromProvider(final BlockEntity pr
final Set<IItemHandler> 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 = ItemHandler.BLOCK.getCapability(provider.getLevel(), provider.getBlockPos(), provider.getBlockState(), provider, side);
if (cap != null)
{
handlerSet.add(cap);
Expand Down Expand Up @@ -147,54 +168,117 @@ 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<ItemStack> 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<ItemStack> getListOfStackForEntity(final Entity entity, final BlockPos pos)
public static List<ItemStack> getListOfStackForEntity(final Entity entity)
{
if (entity != null)
if (entity == null)
{
final List<ItemStack> request = new ArrayList<>();
if (entity instanceof final ItemFrame itemFrame)
{
final ItemStack stack = itemFrame.getItem();
if (!ItemStackUtils.isEmpty(stack))
{
stack.setCount(1);
request.add(stack);
}
request.add(new ItemStack(Items.ITEM_FRAME, 1));
}
else if (entity instanceof final ArmorStand armorStand)
return List.of();
}

final List<ItemStack> request = new ArrayList<>();

// process entity itself
final ItemStack spawnItem = getEntitySpawningItem(entity);
if (spawnItem != null && !(spawnItem.getItem() instanceof SpawnEggItem))
{
request.add(spawnItem);
}

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<ItemStack> getItemStacksOfEntity(final Entity entity)
{
final List<ItemStack> entityContent = new ArrayList<>();

// if entity has unsided itemHandler then done
IItemHandler itemHandler = null;
if (entity instanceof final IItemHandler iitemHandler)
{
itemHandler = iitemHandler;
}
if (itemHandler == null)
{
itemHandler = entity.getCapability(ItemHandler.ENTITY);
}
if (itemHandler == null)
{
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();
if (!ItemStackUtils.isEmpty(stack))
{
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);
stack.setCount(1);
entityContent.add(stack);
}
else if (entity instanceof ContainerEntity containerEntity)
}
else if (entity instanceof final ArmorStand armorStand)
{
armorStand.getArmorSlots().forEach(entityContent::add);
armorStand.getHandSlots().forEach(entityContent::add);
}
else if (entity instanceof final ContainerEntity containerEntity)
{
entityContent.addAll(containerEntity.getItemStacks());
}
else // sided item handler
{
for (final Direction side : Direction.values())
{
request.add(entity.getPickedResult(new HitResult(Vec3.atLowerCornerOf(pos)) {
@Override
public Type getType()
{
return Type.ENTITY;
}
}));
request.addAll(containerEntity.getItemStacks());
final IItemHandler cap = entity.getCapability(ItemHandler.ENTITY_AUTOMATION, side);
if (cap != null)
{
deepExtractItemHandler(cap, entityContent::add);
}
}
}

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));
}

/**
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/ldtteam/structurize/api/ItemStorage.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/ldtteam/structurize/client/BlueprintHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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<Entity> getOptionalEntitiesForBlueprint(final BlueprintPreviewData previewData)
{
final BlueprintRenderer renderer = rendererCache.getIfPresent(previewData.getRenderKey());
return renderer == null ? List.of() : renderer.entities;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public class BlueprintRenderer implements AutoCloseable
private static boolean hasWarnedExceptions = false;

private final BlueprintBlockAccess blockAccess;
private List<Entity> entities;
List<Entity> entities = List.of();
private List<BlockEntity> tileEntities;
private Map<RenderType, VertexBuffer> vertexBuffers;
private long lastGameTime;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -259,6 +261,7 @@ public void onUpdate()
{
findPaneOfTypeByID("tip", Text.class).setVisible(false);
}
findPaneByID(BUTTON_CONTENTS).setVisible(RenderingCache.getOrCreateBlueprintPreviewData(bluePrintId).getBlueprint() != null);
}

@Override
Expand Down Expand Up @@ -542,6 +545,12 @@ private void rotateLeftClicked()
updateRotationState();
}

private void openContents()
{
final BlueprintPreviewData previewData = RenderingCache.getOrCreateBlueprintPreviewData(bluePrintId);
new WindowBlockGetterContents(previewData.getBlueprint(), BlueprintHandler.getInstance().getOptionalEntitiesForBlueprint(previewData)).openAsLayer();
}

/*
* ---------------- Miscellaneous ----------------
*/
Expand Down
Loading

0 comments on commit 3d9d0ff

Please sign in to comment.