Skip to content

Commit

Permalink
More work on fixing various issues with the QIO including some relate…
Browse files Browse the repository at this point in the history
…d to the crafting windows:

- Fix accidentally having broken being able to extract from the output slot when adding support for doLimitedCrafting #7203
- Fix rounding in QIO GUI of items stored which caused things like showing 100000.0K when there are 9,999,935 items stored instead of showing 9999.9K and make 9,999,999 display as 9999.9K as well rather than rounding up to 10M. We also now only display the decimal place if it is in use, and actually make use of it at times rather than it just being ignored and always being zero
- Fix the QIO sometimes showing multiple stacks of the same item in the GUI because of it not properly removing the old stack #7229
- Fix desyncs when splitting stacks via quick crafting and then releasing the remaining stacks over the QIO viewer by not inserting items into the QIO viewer on release from quick crafting, and requiring a second click instead
  • Loading branch information
pupnewfster committed Aug 15, 2021
1 parent 5741625 commit d307ecc
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 12 deletions.
5 changes: 5 additions & 0 deletions src/main/java/mekanism/client/gui/GuiMekanism.java
Expand Up @@ -532,6 +532,11 @@ public ItemRenderer getItemRenderer() {
return itemRenderer;
}

@Override
public boolean currentlyQuickCrafting() {
return isQuickCrafting && !quickCraftSlots.isEmpty();
}

@Override
public void addWindow(GuiWindow window) {
GuiWindow top = windows.isEmpty() ? null : windows.iterator().next();
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/mekanism/client/gui/IGuiWrapper.java
Expand Up @@ -72,6 +72,10 @@ default void removeWindow(GuiWindow window) {
Mekanism.logger.error("Tried to call 'removeWindow' but unsupported in {}", getClass().getName());
}

default boolean currentlyQuickCrafting() {
return false;
}

@Nullable
default GuiWindow getWindowHovering(double mouseX, double mouseY) {
Mekanism.logger.error("Tried to call 'getWindowHovering' but unsupported in {}", getClass().getName());
Expand Down
@@ -1,6 +1,8 @@
package mekanism.client.gui.element.scroll;

import com.mojang.blaze3d.matrix.MatrixStack;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
Expand All @@ -24,6 +26,11 @@ public class GuiSlotScroll extends GuiRelativeElement {

private static final ResourceLocation SLOTS = MekanismUtils.getResource(ResourceType.GUI_SLOT, "slots.png");
private static final ResourceLocation SLOTS_DARK = MekanismUtils.getResource(ResourceType.GUI_SLOT, "slots_dark.png");
private static final DecimalFormat COUNT_FORMAT = new DecimalFormat("#.#");

static {
COUNT_FORMAT.setRoundingMode(RoundingMode.FLOOR);
}

private final GuiScrollBar scrollBar;

Expand Down Expand Up @@ -91,6 +98,10 @@ public boolean mouseScrolled(double mouseX, double mouseY, double delta) {

@Override
public boolean mouseReleased(double mouseX, double mouseY, int button) {
if (gui().currentlyQuickCrafting()) {
//If the player is currently quick crafting don't do any special handling for as if they clicked in the screen
return super.mouseReleased(mouseX, mouseY, button);
}
super.mouseReleased(mouseX, mouseY, button);
IScrollableSlot slot = getSlot(mouseX, mouseY, x, y);
clickHandler.onClick(slot, button, Screen.hasShiftDown(), minecraft.player.inventory.getCarried());
Expand Down Expand Up @@ -167,16 +178,18 @@ private void renderSlotText(MatrixStack matrix, String text, int x, int y) {
}

private String getCountText(long count) {
//Note: For cases like 9,999,999 we intentionally display as 9999.9K instead of 10M so that people
// do not think they have more stored than they actually have just because it is rounding up
if (count <= 1) {
return null;
} else if (count < 10_000) {
return Long.toString(count);
} else if (count < 10_000_000) {
return Double.toString(Math.round(count / 1_000D)) + "K";
return COUNT_FORMAT.format(count / 1_000D) + "K";
} else if (count < 10_000_000_000L) {
return Double.toString(Math.round(count / 1_000_000D)) + "M";
return COUNT_FORMAT.format(count / 1_000_000D) + "M";
} else if (count < 10_000_000_000_000L) {
return Double.toString(Math.round(count / 1_000_000_000D)) + "B";
return COUNT_FORMAT.format(count / 1_000_000_000D) + "B";
}
return ">10T";
}
Expand Down
Expand Up @@ -528,8 +528,9 @@ private boolean updateRemainderHelperInputs(boolean updated, @Nonnull ItemStack

private class QIOCraftingInventory extends CraftingInventory {

//TODO - 10.1: Suppress warning and also add a note that we override all the places where it being
// null would cause issues, and we handle slots individually as well
//Note: We suppress the warning about this passing null as the container as we override all methods that
// that make use of the container to use our handler instead
@SuppressWarnings("ConstantConditions")
public QIOCraftingInventory() {
super(null, 0, 0);
}
Expand Down
32 changes: 28 additions & 4 deletions src/main/java/mekanism/common/content/qio/QIOFrequency.java
Expand Up @@ -54,8 +54,13 @@ public class QIOFrequency extends Frequency {
private final Map<String, Set<HashedItem>> modIDLookupMap = new HashMap<>();
// efficiently keep track of the items for use in fuzzy lookup utilized by the items stored
private final Map<Item, Set<HashedItem>> fuzzyItemLookupMap = new HashMap<>();
//Keep track of a UUID for each hashed item
// keep track of a UUID for each hashed item
private final BiMap<HashedItem, UUID> itemTypeLookup = HashBiMap.create();
// allows for lazily removing the UUIDs assigned to items in the itemTypeLookup BiMap without having any issues
// come up related to updatedItems being a set and UUIDAwareHashedItems server side intentionally not comparing
// the UUIDs, so then if multiple add/remove calls happened at once the items in need of updating potentially
// would sync using a different UUID to the client, causing the client to not know the old stack needed to be removed
private final Set<UUID> uuidsToInvalidate = new HashSet<>();
// a sensitive cache for wildcard tag lookups (wildcard -> [matching tags])
private final SetMultimap<String, String> tagWildcardCache = HashMultimap.create();
private final Set<String> failedWildcardTags = new HashSet<>();
Expand Down Expand Up @@ -141,7 +146,15 @@ private QIOItemTypeData createTypeDataForAbsent(HashedItem type) {
}).add(type);
//Fuzzy item lookup has no wildcard cache related to it
fuzzyItemLookupMap.computeIfAbsent(stack.getItem(), item -> new HashSet<>()).add(type);
itemTypeLookup.put(type, UUID.randomUUID());
UUID oldUUID = getUUIDForType(type);
if (oldUUID != null) {
//If there was a UUID stored and prepped to be invalidated, remove it from the UUIDS we are trying to invalidate
// so that it is able to continue being used/sync'd to the client
uuidsToInvalidate.remove(oldUUID);
} else {
// otherwise, create a new uuid for use with this item type
itemTypeLookup.put(type, UUID.randomUUID());
}
return new QIOItemTypeData(type);
}

Expand All @@ -154,7 +167,7 @@ public ItemStack removeItem(ItemStack stack, int amount) {
}

public ItemStack removeByType(@Nullable HashedItem itemType, int amount) {
if (itemDataMap.isEmpty()) {
if (itemDataMap.isEmpty() || amount <= 0) {
return ItemStack.EMPTY;
}

Expand All @@ -180,7 +193,11 @@ public ItemStack removeByType(@Nullable HashedItem itemType, int amount) {

private void removeItemData(HashedItem type) {
itemDataMap.remove(type);
itemTypeLookup.remove(type);
//If the item has a UUID that corresponds to it, add that UUID to our list of uuids to invalidate
UUID toInvalidate = getUUIDForType(type);
if (toInvalidate != null) {
uuidsToInvalidate.add(toInvalidate);
}
//Note: We need to copy the tags to a new collection as otherwise when we start removing them from the lookup
// they will also get removed from this view
Set<String> tags = new HashSet<>(tagLookupMap.getKeys(type));
Expand Down Expand Up @@ -346,6 +363,13 @@ public QIODriveData getDriveData(QIODriveKey key) {
@Override
public void tick() {
super.tick();
if (!uuidsToInvalidate.isEmpty()) {
//If we have uuids we need to invalidate the Item UUID pairing of them
for (UUID uuidToInvalidate : uuidsToInvalidate) {
itemTypeLookup.inverse().remove(uuidToInvalidate);
}
uuidsToInvalidate.clear();
}
if (!updatedItems.isEmpty() || needsUpdate) {
Object2LongMap<UUIDAwareHashedItem> map = new Object2LongOpenHashMap<>();
updatedItems.forEach(type -> {
Expand Down
Expand Up @@ -90,7 +90,10 @@ public ItemStack onTake(@Nonnull PlayerEntity player, @Nonnull ItemStack stack)

@Override
public boolean mayPickup(@Nonnull PlayerEntity player) {
return canCraft && super.mayPickup(player);
if (player.level.isClientSide || !(player instanceof ServerPlayerEntity)) {
return canCraft && super.mayPickup(player);
}
return craftingWindow.canViewRecipe((ServerPlayerEntity) player) && super.mayPickup(player);
}

@Nonnull
Expand Down
Expand Up @@ -75,7 +75,6 @@ protected void addSlots() {
}
if (tile.supportsUpgrades()) {
//Add the virtual slot for the upgrade (add them before the main inventory to make sure they take priority in targeting)
//TODO - 10.1: Test this and test how it handles
addSlot(upgradeSlot = tile.getComponent().getUpgradeSlot().createContainerSlot());
addSlot(upgradeOutputSlot = tile.getComponent().getUpgradeOutputSlot().createContainerSlot());
}
Expand Down
Expand Up @@ -275,7 +275,7 @@ private void transferItems(@Nullable QIOFrequency frequency, QIOCraftingWindow c
targetContents.put(entry.getByteKey(), stack);
}
}
//Extract what items are still
//Extract what items are still in the window
Byte2ObjectMap<ItemStack> remainingCraftingGridContents = new Byte2ObjectArrayMap<>(9);
for (byte i = 0; i < 9; i++) {
CraftingWindowInventorySlot inputSlot = craftingWindow.getInputSlot(i);
Expand Down

0 comments on commit d307ecc

Please sign in to comment.