diff --git a/src/main/java/com/minecolonies/api/colony/buildings/IBuilding.java b/src/main/java/com/minecolonies/api/colony/buildings/IBuilding.java index 283581306bd..f7c91d34037 100755 --- a/src/main/java/com/minecolonies/api/colony/buildings/IBuilding.java +++ b/src/main/java/com/minecolonies/api/colony/buildings/IBuilding.java @@ -356,10 +356,21 @@ ImmutableList> getOpenRequestsOfTypeFiltered( * Creates a pickup request for the building. It will make sure that only one pickup request exists per building, so it's safe to call multiple times. The call will return * false if a pickup request already exists, or if the priority is not within the proper range, or if the pickup priority is set to NEVER (0). * - * @param pickUpPrio The priority of the pickup request. + * @param priority the priority of the pickup request. * @return true if a pickup request could be created, false if not. */ - boolean createPickupRequest(final int pickUpPrio); + boolean createPickupRequest(final int priority); + + /** + * Creates a pickup request for the building. It will make sure that only one pickup request exists per building, so it's safe to call multiple times. The call will return + * false if a pickup request already exists, or if the priority is not within the proper range, or if the pickup priority is set to NEVER (0). + * This overload features a filter that can be used to only pick up the one given item stack and ignore the rest. + * + * @param priority the priority of the pickup request. + * @param pickupFilter the item stacks to filter for this specific pickup. + * @return true if a pickup request could be created, false if not. + */ + boolean createPickupRequest(final int priority, final @Nullable List pickupFilter); @Override ImmutableCollection> getResolvers(); diff --git a/src/main/java/com/minecolonies/api/colony/requestsystem/requestable/deliveryman/Pickup.java b/src/main/java/com/minecolonies/api/colony/requestsystem/requestable/deliveryman/Pickup.java index 35e8cb34c46..3f7595a703a 100755 --- a/src/main/java/com/minecolonies/api/colony/requestsystem/requestable/deliveryman/Pickup.java +++ b/src/main/java/com/minecolonies/api/colony/requestsystem/requestable/deliveryman/Pickup.java @@ -5,10 +5,14 @@ import com.minecolonies.api.util.ReflectionUtils; import com.minecolonies.api.util.constant.TypeConstants; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.ItemStack; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -16,20 +20,63 @@ */ public class Pickup extends AbstractDeliverymanRequestable { + ////// --------------------------- NBTConstants --------------------------- \\\\\\ + protected static final String NBT_PICKUP_FILTER = "Filter"; + ////// --------------------------- NBTConstants --------------------------- \\\\\\ + /** * Set of type tokens belonging to this class. */ private final static Set> TYPE_TOKENS = ReflectionUtils.getSuperClasses(TypeToken.of(Pickup.class)).stream().filter(type -> !type.equals(TypeConstants.OBJECT)).collect(Collectors.toSet()); + /** + * The itemstack to filter for this specific pickup. + */ + @Nullable + private List pickupFilter; + /** * Constructor for Delivery requests * - * @param priority The priority of the request. + * @param priority the priority of the request. + * @param filter a filter to apply to the pickup request. */ - public Pickup(final int priority) + public Pickup(final int priority, final @Nullable List filter) { super(priority); + if (filter != null) + { + this.pickupFilter = filter.stream().map(ItemStack::copy).collect(Collectors.toList()); + } + } + + /** + * Get the itemstack to filter for this specific pickup. + * + * @return the itemstack or null. + */ + @Nullable + public List getPickupFilter() + { + return pickupFilter; + } + + /** + * Add or update a pickup filter. + * + * @param stacks the input stacks. + */ + public void addToPickupFilter(final List stacks) + { + if (pickupFilter == null) + { + pickupFilter = stacks; + } + else + { + pickupFilter.addAll(stacks); + } } @NotNull @@ -37,6 +84,15 @@ public static CompoundTag serialize(@NotNull final IFactoryController controller { final CompoundTag compound = new CompoundTag(); compound.put(NBT_PRIORITY, controller.serialize(pickup.getPriority())); + if (pickup.getPickupFilter() != null) + { + final ListTag listTag = new ListTag(); + for (final ItemStack itemStack : pickup.getPickupFilter()) + { + listTag.add(itemStack.save(new CompoundTag())); + } + compound.put(NBT_PICKUP_FILTER, listTag); + } return compound; } @@ -44,19 +100,42 @@ public static CompoundTag serialize(@NotNull final IFactoryController controller public static Pickup deserialize(@NotNull final IFactoryController controller, @NotNull final CompoundTag compound) { final int priority = controller.deserialize(compound.getCompound(NBT_PRIORITY)); - return new Pickup(priority); + final List pickupFilter; + if (compound.contains(NBT_PICKUP_FILTER)) + { + pickupFilter = new ArrayList<>(); + final ListTag list = compound.getList(NBT_PICKUP_FILTER, Tag.TAG_COMPOUND); + for (int i = 0; i < list.size(); i++) + { + pickupFilter.add(ItemStack.of(list.getCompound(i))); + } + } + else + { + pickupFilter = null; + } + return new Pickup(priority, pickupFilter); } /** * Serialize the deliverable. * * @param controller the controller. - * @param buffer the the buffer to write to. + * @param buffer the buffer to write to. * @param input the input to serialize. */ public static void serialize(final IFactoryController controller, final FriendlyByteBuf buffer, final Pickup input) { buffer.writeInt(input.getPriority()); + buffer.writeBoolean(input.getPickupFilter() != null); + if (input.getPickupFilter() != null) + { + buffer.writeInt(input.getPickupFilter().size()); + for (final ItemStack itemStack : input.getPickupFilter()) + { + buffer.writeItem(itemStack); + } + } } /** @@ -69,8 +148,21 @@ public static void serialize(final IFactoryController controller, final Friendly public static Pickup deserialize(final IFactoryController controller, final FriendlyByteBuf buffer) { final int priority = buffer.readInt(); - - return new Pickup(priority); + final List pickupFilter; + if (buffer.readBoolean()) + { + pickupFilter = new ArrayList<>(); + final int itemCount = buffer.readInt(); + for (int i = 0; i < itemCount; i++) + { + pickupFilter.add(buffer.readItem()); + } + } + else + { + pickupFilter = null; + } + return new Pickup(priority, pickupFilter); } @Override diff --git a/src/main/java/com/minecolonies/core/colony/buildings/AbstractBuilding.java b/src/main/java/com/minecolonies/core/colony/buildings/AbstractBuilding.java index 433e96bed50..bc49df3c605 100755 --- a/src/main/java/com/minecolonies/core/colony/buildings/AbstractBuilding.java +++ b/src/main/java/com/minecolonies/core/colony/buildings/AbstractBuilding.java @@ -51,6 +51,7 @@ import com.minecolonies.core.colony.requestsystem.management.IStandardRequestManager; import com.minecolonies.core.colony.requestsystem.requesters.BuildingBasedRequester; import com.minecolonies.core.colony.requestsystem.requests.StandardRequests; +import com.minecolonies.core.colony.requestsystem.requests.StandardRequests.PickupRequest; import com.minecolonies.core.colony.requestsystem.resolvers.BuildingRequestResolver; import com.minecolonies.core.colony.workorders.WorkOrderBuilding; import com.minecolonies.core.entity.ai.workers.service.EntityAIWorkDeliveryman; @@ -1518,9 +1519,15 @@ public ImmutableList> getOpenRequestsOfType( } @Override - public boolean createPickupRequest(final int pickUpPrio) + public boolean createPickupRequest(final int priority) { - int daysToPickup = 10 - pickUpPrio; + return createPickupRequest(priority, null); + } + + @Override + public boolean createPickupRequest(final int priority, final @Nullable List pickupFilter) + { + int daysToPickup = 10 - priority; if (pickUpDay == -1 || pickUpDay > colony.getDay() + daysToPickup) { pickUpDay = colony.getDay() + daysToPickup; @@ -1546,12 +1553,17 @@ public boolean createPickupRequest(final int pickUpPrio) { colony.getRequestManager().reassignRequest(req, Collections.emptyList()); } + + if (request instanceof PickupRequest pickup && pickupFilter != null) + { + pickup.getRequest().addToPickupFilter(pickupFilter); + } } } return false; } - createRequest(new Pickup(pickUpPrio), true); + createRequest(new Pickup(priority, pickupFilter), true); return true; } diff --git a/src/main/java/com/minecolonies/core/entity/ai/workers/crafting/AbstractEntityAICrafting.java b/src/main/java/com/minecolonies/core/entity/ai/workers/crafting/AbstractEntityAICrafting.java index 1bfd8233c15..d4bf53012ae 100755 --- a/src/main/java/com/minecolonies/core/entity/ai/workers/crafting/AbstractEntityAICrafting.java +++ b/src/main/java/com/minecolonies/core/entity/ai/workers/crafting/AbstractEntityAICrafting.java @@ -464,6 +464,11 @@ protected IAIState craft() module.improveRecipe(currentRecipeStorage, job.getCraftCounter(), worker.getCitizenData()); } + if (!currentRecipeStorage.getSecondaryOutputs().isEmpty()) + { + building.createPickupRequest(10, currentRecipeStorage.getSecondaryOutputs()); + } + currentRecipeStorage = null; resetValues(); diff --git a/src/main/java/com/minecolonies/core/entity/ai/workers/service/EntityAIWorkDeliveryman.java b/src/main/java/com/minecolonies/core/entity/ai/workers/service/EntityAIWorkDeliveryman.java index 2c5196edb97..0f954f3c144 100755 --- a/src/main/java/com/minecolonies/core/entity/ai/workers/service/EntityAIWorkDeliveryman.java +++ b/src/main/java/com/minecolonies/core/entity/ai/workers/service/EntityAIWorkDeliveryman.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.ListIterator; import java.util.stream.Collectors; import static com.minecolonies.api.entity.ai.statemachine.states.AIWorkerState.*; @@ -144,7 +145,7 @@ private IAIState pickup() setDelay(WALK_DELAY); final IRequest currentTask = job.getCurrentTask(); - if (!(currentTask instanceof PickupRequest)) + if (!(currentTask instanceof PickupRequest pickupRequest)) { // The current task has changed since the Decision-state. Restart. return START_WORKING; @@ -172,7 +173,7 @@ private IAIState pickup() return PICKUP; } - if (pickupFromBuilding(pickupBuilding)) + if (pickupFromBuilding(pickupBuilding, pickupRequest)) { this.alreadyKept = new ArrayList<>(); this.currentSlot = 0; @@ -203,9 +204,10 @@ else if (InventoryUtils.openSlotCount(worker.getInventoryCitizen()) <= 0) * Gather not needed Items from building. * * @param building building to gather it from. + * @param request the pickup request. * @return true when finished. */ - private boolean pickupFromBuilding(@NotNull final IBuilding building) + private boolean pickupFromBuilding(@NotNull final IBuilding building, final PickupRequest request) { if (cannotHoldMoreItems() || InventoryUtils.openSlotCount(worker.getInventoryCitizen()) <= 0) { @@ -241,20 +243,49 @@ private boolean pickupFromBuilding(@NotNull final IBuilding building) return false; } - if (ItemStackUtils.isEmpty(handler.getStackInSlot(currentSlot))) + if (request.getRequest().getPickupFilter() != null) { - return false; + final ListIterator iterator = request.getRequest().getPickupFilter().listIterator(); + while (iterator.hasNext()) + { + final ItemStack filter = iterator.next(); + if (ItemStackUtils.compareItemStacksIgnoreStackSize(stack, filter)) + { + final ItemStack activeStack = handler.extractItem(currentSlot, filter.getCount(), false); + transferItemForPickup(activeStack); + if (filter.getCount() == activeStack.getCount()) + { + iterator.remove(); + } + else + { + iterator.set(filter.copyWithCount(filter.getCount() - activeStack.getCount())); + } + } + } } + else + { + final ItemStack activeStack = handler.extractItem(currentSlot, amount, false); + transferItemForPickup(activeStack); + } + return false; + } - final ItemStack activeStack = handler.extractItem(currentSlot, amount, false); - InventoryUtils.transferItemStackIntoNextBestSlotInItemHandler(activeStack, worker.getInventoryCitizen()); + /** + * Transfer an item to the courier for pickup. + * + * @param stack the stack to transfer. + */ + private void transferItemForPickup(final ItemStack stack) + { + InventoryUtils.transferItemStackIntoNextBestSlotInItemHandler(stack, worker.getInventoryCitizen()); building.markDirty(); worker.decreaseSaturationForContinuousAction(); // The worker gets a little bit of exp for every itemstack he grabs. worker.getCitizenExperienceHandler().addExperience(0.01D); CitizenItemUtils.setHeldItem(worker, InteractionHand.MAIN_HAND, SLOT_HAND); - return false; } /**