Skip to content

Commit

Permalink
Add a client side config for controlling whether JEI moves irrelevant…
Browse files Browse the repository at this point in the history
… items from the crafting inventory to the player's inventory or the frequency first (#8027), defaults to moving to the frequency
  • Loading branch information
pupnewfster committed Mar 14, 2024
1 parent 69e3334 commit 02d7f52
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 15 deletions.
Expand Up @@ -25,6 +25,7 @@
import mekanism.api.math.MathUtils;
import mekanism.common.Mekanism;
import mekanism.common.MekanismLang;
import mekanism.common.config.MekanismConfig;
import mekanism.common.content.qio.QIOCraftingTransferHelper;
import mekanism.common.content.qio.QIOCraftingTransferHelper.BaseSimulatedInventory;
import mekanism.common.content.qio.QIOCraftingTransferHelper.HashedItemSource;
Expand Down Expand Up @@ -336,7 +337,7 @@ record TrackedIngredients(IRecipeSlotView view, Set<HashedItem> representations)
// things may not fully be accurate on the client side with the stacks that JEI lets us know match the recipe, as
// they may require extra NBT that is server side only.
//TODO: If the sources are all from the crafting window and are already in the correct spots, there is no need to send this packet
PacketUtils.sendToServer(new PacketQIOFillCraftingWindow(recipeHolder.id(), maxTransfer, sources));
PacketUtils.sendToServer(new PacketQIOFillCraftingWindow(recipeHolder.id(), maxTransfer, MekanismConfig.client.qioRejectsToInventory.get(), sources));
}
}
return null;
Expand All @@ -350,6 +351,9 @@ private IRecipeTransferError invalidSource(@NotNull HashedItem type) {

/**
* Loosely based on how {@link mekanism.common.content.qio.QIOServerCraftingTransferHandler}'s hasRoomToShuffle method works.
*
* @implNote As it simplifies the logic (and is what we had initially written), this simulates if we can shuffle with the player inventory before checking the
* frequency. (I believe this is also more efficient than doing the simulated checks against the frequency)
*/
private static boolean hasRoomToShuffle(QIOCraftingTransferHelper qioTransferHelper, @Nullable QIOFrequency frequency, QIOCraftingWindow craftingWindow,
List<HotBarSlot> hotBarSlots, List<MainInventorySlot> mainInventorySlots, Map<HashedItemSource, List<List<SingularHashedItemSource>>> shuffleLookup) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/java/mekanism/common/config/ClientConfig.java
Expand Up @@ -54,6 +54,7 @@ public class ClientConfig extends BaseMekanismConfig {
public final CachedEnumValue<SortDirection> qioItemViewerSortDirection;
public final CachedIntValue qioItemViewerSlotsX;
public final CachedIntValue qioItemViewerSlotsY;
public final CachedBooleanValue qioRejectsToInventory;

ClientConfig() {
ModConfigSpec.Builder builder = new ModConfigSpec.Builder();
Expand Down Expand Up @@ -133,6 +134,8 @@ public class ClientConfig extends BaseMekanismConfig {
.defineInRange("itemViewerSlotsX", 8, QIOItemViewerContainer.SLOTS_X_MIN, QIOItemViewerContainer.SLOTS_X_MAX));
qioItemViewerSlotsY = CachedIntValue.wrap(this, builder.comment("Number of slots to view vertically on a QIO Item Viewer.")
.defineInRange("itemViewerSlotsY", 4, QIOItemViewerContainer.SLOTS_Y_MIN, QIOItemViewerContainer.SLOTS_Y_MAX));
qioRejectsToInventory = CachedBooleanValue.wrap(this, builder.comment("Determines if items in a QIO crafting window should be moved to the player's inventory or frequency first when replacing the items with a recipe viewer.")
.define("rejectsToInventory", false));
builder.pop();

builder.pop();
Expand Down
Expand Up @@ -53,23 +53,25 @@ public class QIOServerCraftingTransferHandler {
private final Player player;
@Nullable
private final QIOFrequency frequency;
private final boolean rejectToInventory;
private final List<HotBarSlot> hotBarSlots;
private final List<MainInventorySlot> mainInventorySlots;

private final Byte2ObjectMap<SlotData> availableItems = new Byte2ObjectOpenHashMap<>();
private final Map<UUID, FrequencySlotData> frequencyAvailableItems = new HashMap<>();
private final NonNullList<ItemStack> recipeToTest = NonNullList.withSize(9, ItemStack.EMPTY);

public static void tryTransfer(QIOItemViewerContainer container, byte selectedCraftingGrid, Player player, ResourceLocation recipeID,
public static void tryTransfer(QIOItemViewerContainer container, byte selectedCraftingGrid, boolean rejectToInventory, Player player, ResourceLocation recipeID,
CraftingRecipe recipe, Byte2ObjectMap<List<SingularHashedItemSource>> sources) {
QIOServerCraftingTransferHandler transferHandler = new QIOServerCraftingTransferHandler(container, selectedCraftingGrid, player, recipeID);
QIOServerCraftingTransferHandler transferHandler = new QIOServerCraftingTransferHandler(container, selectedCraftingGrid, rejectToInventory, player, recipeID);
transferHandler.tryTransfer(recipe, sources);
}

private QIOServerCraftingTransferHandler(QIOItemViewerContainer container, byte selectedCraftingGrid, Player player, ResourceLocation recipeID) {
private QIOServerCraftingTransferHandler(QIOItemViewerContainer container, byte selectedCraftingGrid, boolean rejectToInventory, Player player, ResourceLocation recipeID) {
this.player = player;
this.recipeID = recipeID;
this.frequency = container.getFrequency();
this.rejectToInventory = rejectToInventory;
this.craftingWindow = container.getCraftingWindow(selectedCraftingGrid);
this.hotBarSlots = container.getHotBarSlots();
this.mainInventorySlots = container.getMainInventorySlots();
Expand Down Expand Up @@ -281,6 +283,10 @@ private int addStackToRecipe(byte targetSlot, ItemData slotData, int used, byte
return used;
}

/**
* @implNote As it simplifies the logic (and is what we had initially written), this simulates if we can shuffle with the player inventory before checking the
* frequency. (I believe this is also more efficient than doing the simulated checks against the frequency)
*/
private boolean hasRoomToShuffle() {
//Map used to keep track of inputs while also merging identical inputs, so we can cut down
// on how many times we have to check if things can stack
Expand Down Expand Up @@ -524,8 +530,11 @@ private void transferItems(Byte2ObjectMap<List<SingularHashedItemSource>> source
}
//Put the items that were in the crafting window in the player's inventory
for (Byte2ObjectMap.Entry<ItemStack> entry : remainingCraftingGridContents.byte2ObjectEntrySet()) {
//Insert into player's inventory
ItemStack stack = returnItemToInventory(entry.getValue(), windowData);
ItemStack stack = entry.getValue();
if (rejectToInventory) {
//If we prioritize inserting back into the player's inventory, start by doing so
stack = returnItemToInventory(stack, windowData);
}
if (!stack.isEmpty()) {
//If we couldn't insert it all, try recombining with the slots they were in the crafting window
// (only if the type matches though)
Expand All @@ -538,14 +547,19 @@ private void transferItems(Byte2ObjectMap<List<SingularHashedItemSource>> source
if (frequency != null) {
stack = frequency.addItem(stack);
}
if (!rejectToInventory) {
//If we didn't already try to insert it into the player's inventory, then try to do so
stack = returnItemToInventory(stack, windowData);
}
if (!stack.isEmpty()) {
//If we couldn't insert it all, either because there was no frequency or it didn't have room for it all
// drop it as the player, and print a warning as ideally we should never have been able to get to this
// point as our simulation should have marked it as invalid
// Note: In theory we should never get to this point due to having accurate simulations ahead of time
player.drop(stack, false);
Mekanism.logger.warn("Received transfer request from: {}, for: {}, and was unable to fit all contents that were in the crafting window "
+ "into the player's inventory/QIO system; dropping items by player.", player, recipeID);
Mekanism.logger.warn("Received transfer request from: {}, for: {}, initially targeting the player's inventory: {}, and was unable to fit "
+ "all contents that were in the crafting window into the player's inventory/QIO system; dropping items by player.",
player, recipeID, rejectToInventory);
}
}
}
Expand Down
Expand Up @@ -26,18 +26,16 @@ public class PacketQIOFillCraftingWindow implements IMekanismPacket<PlayPayloadC

private final Byte2ObjectMap<List<SingularHashedItemSource>> sources;
private final ResourceLocation recipeID;
private final boolean rejectToInventory;
private final boolean maxTransfer;

//Note: While our logic is not dependent on knowing about maxTransfer, we make use of it for encoding and decoding
// as when it is false we can reduce how many bytes the packet is by a good amount by making assumptions about the sizes of things
public PacketQIOFillCraftingWindow(ResourceLocation recipeID, boolean maxTransfer, Byte2ObjectMap<List<SingularHashedItemSource>> sources) {
//TODO - 1.20.4: SP: Test this after JEI updates, I believe this is fine even in single player as the map we create on the client
// for purposes of the packet so we can just directly pass it over (especially as we don't seem to mutate it on the server)
// and while the logic for serialization and deserialization is complex, it is just so that we can reduce the packet size
// and we still manage to transfer all the data we would have regardless
public PacketQIOFillCraftingWindow(ResourceLocation recipeID, boolean maxTransfer, boolean rejectToInventory, Byte2ObjectMap<List<SingularHashedItemSource>> sources) {
this.recipeID = recipeID;
this.sources = sources;
this.maxTransfer = maxTransfer;
this.rejectToInventory = rejectToInventory;
}

@NotNull
Expand All @@ -58,7 +56,7 @@ public void handle(PlayPayloadContext context) {
if (optionalRecipe.isPresent()) {
Recipe<?> recipe = optionalRecipe.get().value();
if (recipe instanceof CraftingRecipe craftingRecipe) {
QIOServerCraftingTransferHandler.tryTransfer(container, selectedCraftingGrid, player, recipeID, craftingRecipe, sources);
QIOServerCraftingTransferHandler.tryTransfer(container, selectedCraftingGrid, rejectToInventory, player, recipeID, craftingRecipe, sources);
} else {
Mekanism.logger.warn("Received transfer request from: {}, but the type ({}) of the specified recipe was not a crafting recipe.",
player, recipe.getClass());
Expand All @@ -75,6 +73,7 @@ public void handle(PlayPayloadContext context) {
public void write(@NotNull FriendlyByteBuf buffer) {
buffer.writeResourceLocation(recipeID);
buffer.writeBoolean(maxTransfer);
buffer.writeBoolean(rejectToInventory);
//Cast to byte as this should always be at most 9
buffer.writeByte((byte) sources.size());
for (Byte2ObjectMap.Entry<List<SingularHashedItemSource>> entry : sources.byte2ObjectEntrySet()) {
Expand Down Expand Up @@ -114,6 +113,7 @@ public void write(@NotNull FriendlyByteBuf buffer) {
public static PacketQIOFillCraftingWindow decode(FriendlyByteBuf buffer) {
ResourceLocation recipeID = buffer.readResourceLocation();
boolean maxTransfer = buffer.readBoolean();
boolean rejectToInventory = buffer.readBoolean();
byte slotCount = buffer.readByte();
Byte2ObjectMap<List<SingularHashedItemSource>> sources = new Byte2ObjectArrayMap<>(slotCount);
for (byte slot = 0; slot < slotCount; slot++) {
Expand All @@ -131,6 +131,6 @@ public static PacketQIOFillCraftingWindow decode(FriendlyByteBuf buffer) {
}
}
}
return new PacketQIOFillCraftingWindow(recipeID, maxTransfer, sources);
return new PacketQIOFillCraftingWindow(recipeID, maxTransfer, rejectToInventory, sources);
}
}

0 comments on commit 02d7f52

Please sign in to comment.