Skip to content

Commit

Permalink
Fix pocket computers not being active in the off-hand
Browse files Browse the repository at this point in the history
While Item.inventoryTick is passed a slot number, apparently that slot
corresponds to the offset within a particular inventory compartment
(such as the main inventory or armour)[^1], rather than the inventory as
a whole.

In the case of the off-hand, this means the pocket computer is set to be
in slot 0. When we next tick the computer (to send terminal updates), we
then assume the item has gone missing, and so skip sending updates.

Fixes #1945.

[^1]: A fun side effect of this is that the "selected" flag is true for
  the off-hand iff the player has slot 0 active. This whole thing feels
  like a vanilla bug, but who knows!
  • Loading branch information
SquidDev committed Aug 19, 2024
1 parent d7cea55 commit 8080dcd
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,12 +128,16 @@ private boolean updateItem(ItemStack stack, PocketBrain brain) {
}

@Override
public void inventoryTick(ItemStack stack, Level world, Entity entity, int slotNum, boolean selected) {
public void inventoryTick(ItemStack stack, Level world, Entity entity, int compartmentSlot, boolean selected) {
// This (in vanilla at least) is only called for players. Don't bother to handle other entities.
if (world.isClientSide || !(entity instanceof ServerPlayer player)) return;

// Find the actual slot the item exists in, aborting if it can't be found.
var slot = InventoryUtil.getInventorySlotFromCompartment(player, compartmentSlot, stack);
if (slot < 0) return;

// If we're in the inventory, create a computer and keep it alive.
var holder = new PocketHolder.PlayerHolder(player, slotNum);
var holder = new PocketHolder.PlayerHolder(player, slot);
var brain = getOrCreateBrain((ServerLevel) world, holder, stack);
brain.computer().keepAlive();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;

Expand All @@ -35,6 +38,28 @@ public static int getHandSlot(Player player, InteractionHand hand) {
};
}

/**
* Map a slot inside a player's compartment to a slot in the full player's inventory.
* <p>
* {@link Inventory#tick()} passes in a slot to {@link Item#inventoryTick(ItemStack, Level, Entity, int, boolean)}.
* However, this slot corresponds to the index within the current compartment (items, armour, offhand) and not
* the actual slot.
* <p>
* This method searches the relevant compartments (inventory and offhand, skipping armour) for the stack, returning
* its slot if found.
*
* @param player The player holding the item.
* @param slot The slot inside the compartment.
* @param stack The stack being ticked.
* @return The inventory slot, or {@code -1} if the item could not be found in the inventory.
*/
public static int getInventorySlotFromCompartment(Player player, int slot, ItemStack stack) {
if (stack.isEmpty()) throw new IllegalArgumentException("Cannot search for empty stack");
if (player.getInventory().getItem(slot) == stack) return slot;
if (player.getInventory().getItem(Inventory.SLOT_OFFHAND) == stack) return Inventory.SLOT_OFFHAND;
return -1;
}

public static @Nullable Container getEntityContainer(ServerLevel level, BlockPos pos, Direction side) {
var vecStart = new Vec3(
pos.getX() + 0.5 + 0.6 * side.getStepX(),
Expand Down

0 comments on commit 8080dcd

Please sign in to comment.