package com.hypixel.hytale.server.core.inventory.container;
import com.hypixel.hytale.math.util.MathUtil;
import com.hypixel.hytale.protocol.ItemResourceType;
import com.hypixel.hytale.server.core.asset.type.item.config.Item;
import com.hypixel.hytale.server.core.inventory.ItemStack;
import com.hypixel.hytale.server.core.inventory.ResourceQuantity;
import com.hypixel.hytale.server.core.inventory.transaction.ActionType;
import com.hypixel.hytale.server.core.inventory.transaction.ListTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ResourceSlotTransaction;
import com.hypixel.hytale.server.core.inventory.transaction.ResourceTransaction;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class InternalContainerUtilResource {
public InternalContainerUtilResource() {
}
protected static ResourceSlotTransaction internal_removeResourceFromSlot(@Nonnull ItemContainer itemContainer, short slot, @Nonnull ResourceQuantity resource, boolean allOrNothing, boolean filter) {
ItemContainer.validateSlotIndex(slot, itemContainer.getCapacity());
ItemContainer.validateQuantity(resource.getQuantity());
return (ResourceSlotTransaction)itemContainer.writeAction(() -> {
if (filter && itemContainer.cantRemoveFromSlot(slot)) {
ItemStack itemStack = itemContainer.internal_getSlot(slot);
return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, itemStack, itemStack, (ItemStack)null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
} else {
ItemStack slotItemStack = itemContainer.internal_getSlot(slot);
if (slotItemStack == null) {
return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, (ItemStack)null, (ItemStack)null, (ItemStack)null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
} else {
Item slotItem = slotItemStack.getItem();
int quantityInItems = slotItemStack.getQuantity();
ItemResourceType resourceType = resource.getResourceType(slotItem);
if (resourceType == null) {
return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, (ItemStack)null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
} else {
int resourceTypeQuantity = resourceType.quantity;
int quantityRemaining = resource.getQuantity();
int quantityInItemsRemaining = MathUtil.ceil((double)quantityRemaining / (double)resourceTypeQuantity);
int quantityInItemsAdjustment = Math.min(quantityInItems, quantityInItemsRemaining);
int newItemStackQuantity = Math.max(quantityInItems - quantityInItemsAdjustment, 0);
int quantityAdjustment = quantityInItemsAdjustment * resourceTypeQuantity;
quantityRemaining -= quantityAdjustment;
if (allOrNothing && quantityRemaining > 0) {
return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, (ItemStack)null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
} else if (quantityAdjustment <= 0) {
return new ResourceSlotTransaction(false, ActionType.REMOVE, slot, slotItemStack, slotItemStack, (ItemStack)null, allOrNothing, false, filter, resource, resource.getQuantity(), 0);
} else {
ItemStack slotNewItemStack = slotItemStack.withQuantity(newItemStackQuantity);
itemContainer.internal_setSlot(slot, slotNewItemStack);
ItemStack newStack = slotItemStack.withQuantity(quantityInItemsAdjustment);
return new ResourceSlotTransaction(true, ActionType.REMOVE, slot, slotItemStack, slotNewItemStack, newStack, allOrNothing, false, filter, resource, quantityRemaining, quantityAdjustment);
}
}
}
}
});
}
protected static ResourceTransaction internal_removeResource(@Nonnull ItemContainer itemContainer, @Nonnull ResourceQuantity resource, boolean allOrNothing, boolean exactAmount, boolean filter) {
return (ResourceTransaction)itemContainer.writeAction(() -> {
if (allOrNothing || exactAmount) {
int testQuantityRemaining = testRemoveResourceFromItems(itemContainer, resource, resource.getQuantity(), filter);
if (testQuantityRemaining > 0) {
return new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList());
}
if (exactAmount && testQuantityRemaining < 0) {
return new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList());
}
}
List<ResourceSlotTransaction> list = new ObjectArrayList<ResourceSlotTransaction>();
int consumed = 0;
int quantityRemaining = resource.getQuantity();
for(short i = 0; i < itemContainer.getCapacity() && quantityRemaining > 0; ++i) {
ResourceQuantity clone = resource.clone(quantityRemaining);
ResourceSlotTransaction transaction = internal_removeResourceFromSlot(itemContainer, i, clone, false, filter);
if (transaction.succeeded()) {
list.add(transaction);
quantityRemaining = transaction.getRemainder();
consumed += transaction.getConsumed();
}
}
return new ResourceTransaction(quantityRemaining != resource.getQuantity(), ActionType.REMOVE, resource, quantityRemaining, consumed, allOrNothing, exactAmount, filter, list);
});
}
protected static ListTransaction<ResourceTransaction> internal_removeResources(@Nonnull ItemContainer itemContainer, @Nullable List<ResourceQuantity> resources, boolean allOrNothing, boolean exactAmount, boolean filter) {
return resources != null && !resources.isEmpty() ? (ListTransaction)itemContainer.writeAction(() -> {
if (allOrNothing || exactAmount) {
for(ResourceQuantity resource : resources) {
int testQuantityRemaining = testRemoveResourceFromItems(itemContainer, resource, resource.getQuantity(), filter);
if (testQuantityRemaining > 0) {
return new ListTransaction(false, (List)resources.stream().map((remainder) -> new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
}
if (exactAmount && testQuantityRemaining < 0) {
return new ListTransaction(false, (List)resources.stream().map((remainder) -> new ResourceTransaction(false, ActionType.REMOVE, resource, resource.getQuantity(), 0, allOrNothing, exactAmount, filter, Collections.emptyList())).collect(Collectors.toList()));
}
}
}
List<ResourceTransaction> transactions = new ObjectArrayList<ResourceTransaction>();
for(ResourceQuantity resource : resources) {
transactions.add(internal_removeResource(itemContainer, resource, allOrNothing, exactAmount, filter));
}
return new ListTransaction(true, transactions);
}) : ListTransaction.getEmptyTransaction(true);
}
public static int testRemoveResourceFromItems(@Nonnull ItemContainer container, @Nonnull ResourceQuantity resource, int testQuantityRemaining, boolean filter) {
for(short i = 0; i < container.getCapacity() && testQuantityRemaining > 0; ++i) {
testQuantityRemaining = testRemoveResourceFromSlot(container, i, resource, testQuantityRemaining, filter);
}
return testQuantityRemaining;
}
public static TestRemoveItemSlotResult testRemoveResourceSlotFromItems(@Nonnull ItemContainer container, @Nonnull ResourceQuantity resource, int testQuantityRemaining, boolean filter) {
TestRemoveItemSlotResult result = new TestRemoveItemSlotResult(testQuantityRemaining);
for(short i = 0; i < container.getCapacity() && result.quantityRemaining > 0; ++i) {
int newValue = testRemoveResourceFromSlot(container, i, resource, result.quantityRemaining, filter);
if (newValue != result.quantityRemaining) {
int diff = result.quantityRemaining - newValue;
result.quantityRemaining = newValue;
result.picked.put(i, diff);
}
}
return result;
}
public static int testRemoveResourceFromSlot(@Nonnull ItemContainer container, short slot, @Nonnull ResourceQuantity resource, int testQuantityRemaining, boolean filter) {
if (filter && container.cantRemoveFromSlot(slot)) {
return testQuantityRemaining;
} else {
ItemStack slotItemStack = container.internal_getSlot(slot);
if (ItemStack.isEmpty(slotItemStack)) {
return testQuantityRemaining;
} else {
Item slotItem = slotItemStack.getItem();
ItemResourceType resourceType = resource.getResourceType(slotItem);
if (resourceType == null) {
return testQuantityRemaining;
} else {
int resourceTypeQuantity = resourceType.quantity;
int quantityInItemsRemaining = MathUtil.ceil((double)testQuantityRemaining / (double)resourceTypeQuantity);
int quantityInItems = slotItemStack.getQuantity();
int quantityInItemsAdjustment = Math.min(quantityInItems, quantityInItemsRemaining);
int quantityAdjustment = quantityInItemsAdjustment * resourceTypeQuantity;
testQuantityRemaining -= quantityAdjustment;
return testQuantityRemaining;
}
}
}
}
}