#1414: Convert InventoryView to interface

By: Miles Holder <mwholder2005@gmail.com>
This commit is contained in:
CraftBukkit/Spigot 2024-06-16 08:47:38 +10:00
parent 6af115230a
commit d2d0972bc3
4 changed files with 238 additions and 2 deletions

View file

@ -0,0 +1,221 @@
package org.bukkit.craftbukkit.inventory;
import com.google.common.base.Preconditions;
import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public abstract class CraftAbstractInventoryView implements InventoryView {
@Override
public void setItem(final int slot, @Nullable final ItemStack item) {
Inventory inventory = getInventory(slot);
if (inventory != null) {
inventory.setItem(convertSlot(slot), item);
} else if (item != null) {
getPlayer().getWorld().dropItemNaturally(getPlayer().getLocation(), item);
}
}
@Nullable
@Override
public ItemStack getItem(final int slot) {
Inventory inventory = getInventory(slot);
return (inventory == null) ? null : inventory.getItem(convertSlot(slot));
}
@Override
public void setCursor(@Nullable final ItemStack item) {
getPlayer().setItemOnCursor(item);
}
@Nullable
@Override
public ItemStack getCursor() {
return getPlayer().getItemOnCursor();
}
@Nullable
@Override
public Inventory getInventory(final int rawSlot) {
// Slot may be -1 if not properly detected due to client bug
// e.g. dropping an item into part of the enchantment list section of an enchanting table
if (rawSlot == OUTSIDE || rawSlot == -1) {
return null;
}
Preconditions.checkArgument(rawSlot >= 0, "Negative, non outside slot %s", rawSlot);
Preconditions.checkArgument(rawSlot < countSlots(), "Slot %s greater than inventory slot count", rawSlot);
if (rawSlot < getTopInventory().getSize()) {
return getTopInventory();
} else {
return getBottomInventory();
}
}
@Override
public int convertSlot(final int rawSlot) {
int numInTop = getTopInventory().getSize();
// Index from the top inventory as having slots from [0,size]
if (rawSlot < numInTop) {
return rawSlot;
}
// Move down the slot index by the top size
int slot = rawSlot - numInTop;
// Player crafting slots are indexed differently. The matrix is caught by the first return.
// Creative mode is the same, except that you can't see the crafting slots (but the IDs are still used)
if (getType() == InventoryType.CRAFTING || getType() == InventoryType.CREATIVE) {
/*
* Raw Slots:
*
* 5 1 2 0
* 6 3 4
* 7
* 8 45
* 9 10 11 12 13 14 15 16 17
* 18 19 20 21 22 23 24 25 26
* 27 28 29 30 31 32 33 34 35
* 36 37 38 39 40 41 42 43 44
*/
/*
* Converted Slots:
*
* 39 1 2 0
* 38 3 4
* 37
* 36 40
* 9 10 11 12 13 14 15 16 17
* 18 19 20 21 22 23 24 25 26
* 27 28 29 30 31 32 33 34 35
* 0 1 2 3 4 5 6 7 8
*/
if (slot < 4) {
// Send [5,8] to [39,36]
return 39 - slot;
} else if (slot > 39) {
// Slot lives in the extra slot section
return slot;
} else {
// Reset index so 9 -> 0
slot -= 4;
}
}
// 27 = 36 - 9
if (slot >= 27) {
// Put into hotbar section
slot -= 27;
} else {
// Take out of hotbar section
// 9 = 36 - 27
slot += 9;
}
return slot;
}
@NotNull
@Override
public InventoryType.SlotType getSlotType(final int slot) {
InventoryType.SlotType type = InventoryType.SlotType.CONTAINER;
if (slot >= 0 && slot < this.getTopInventory().getSize()) {
switch (this.getType()) {
case BLAST_FURNACE:
case FURNACE:
case SMOKER:
if (slot == 2) {
type = InventoryType.SlotType.RESULT;
} else if (slot == 1) {
type = InventoryType.SlotType.FUEL;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
case BREWING:
if (slot == 3) {
type = InventoryType.SlotType.FUEL;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
case ENCHANTING:
type = InventoryType.SlotType.CRAFTING;
break;
case WORKBENCH:
case CRAFTING:
if (slot == 0) {
type = InventoryType.SlotType.RESULT;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
case BEACON:
type = InventoryType.SlotType.CRAFTING;
break;
case ANVIL:
case SMITHING:
case CARTOGRAPHY:
case GRINDSTONE:
case MERCHANT:
if (slot == 2) {
type = InventoryType.SlotType.RESULT;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
case STONECUTTER:
if (slot == 1) {
type = InventoryType.SlotType.RESULT;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
case LOOM:
case SMITHING_NEW:
if (slot == 3) {
type = InventoryType.SlotType.RESULT;
} else {
type = InventoryType.SlotType.CRAFTING;
}
break;
default:
// Nothing to do, it's a CONTAINER slot
}
} else {
if (slot < 0) {
type = InventoryType.SlotType.OUTSIDE;
} else if (this.getType() == InventoryType.CRAFTING) { // Also includes creative inventory
if (slot < 9) {
type = InventoryType.SlotType.ARMOR;
} else if (slot > 35) {
type = InventoryType.SlotType.QUICKBAR;
}
} else if (slot >= (this.countSlots() - (9 + 4 + 1))) { // Quickbar, Armor, Offhand
type = InventoryType.SlotType.QUICKBAR;
}
}
return type;
}
@Override
public void close() {
getPlayer().closeInventory();
}
@Override
public int countSlots() {
return getTopInventory().getSize() + getBottomInventory().getSize();
}
@Override
public boolean setProperty(@NotNull final Property prop, final int value) {
return getPlayer().setWindowProperty(prop, value);
}
}

View file

@ -48,7 +48,7 @@ public class CraftContainer extends Container {
}
public CraftContainer(final Inventory inventory, final EntityHuman player, int id) {
this(new InventoryView() {
this(new CraftAbstractInventoryView() {
private final String originalTitle = (inventory instanceof CraftInventoryCustom) ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).getTitle() : inventory.getType().getDefaultTitle();
private String title = originalTitle;

View file

@ -15,7 +15,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
import org.bukkit.inventory.ItemStack;
public class CraftInventoryView extends InventoryView {
public class CraftInventoryView extends CraftAbstractInventoryView {
private final Container container;
private final CraftHumanEntity player;
private final CraftInventory viewing;

View file

@ -67,6 +67,10 @@ public class Commodore {
"org/spigotmc/event/entity/EntityDismountEvent", "org/bukkit/event/entity/EntityDismountEvent"
);
private static final Set<String> CLASS_TO_INTERFACE = Set.of(
"org/bukkit/inventory/InventoryView"
);
private static Map<String, RerouteMethodData> createReroutes(Class<?> clazz) {
Map<String, RerouteMethodData> reroutes = RerouteBuilder.buildFromClass(clazz);
REROUTES.add(reroutes);
@ -288,6 +292,17 @@ public class Commodore {
return;
}
if (CLASS_TO_INTERFACE.contains(owner)) {
if (opcode == Opcodes.INVOKEVIRTUAL) {
opcode = Opcodes.INVOKEINTERFACE;
}
if (opcode == Opcodes.H_INVOKEVIRTUAL) {
opcode = Opcodes.H_INVOKEINTERFACE;
}
itf = true;
}
// SPIGOT-4496
if (owner.equals("org/bukkit/map/MapView") && name.equals("getId") && desc.equals("()S")) {
// Should be same size on stack so just call other method