Port 1.16 container changes (#466)

This commit is contained in:
IzzelAliz 2022-02-05 19:14:41 +08:00
parent d008a1e8a6
commit 8f90a71b29
No known key found for this signature in database
GPG Key ID: EE50E123A11D8338
2 changed files with 16 additions and 129 deletions

View File

@ -71,24 +71,14 @@ public abstract class AbstractContainerMenuMixin implements ContainerBridge {
public boolean checkReachable = true;
private InventoryView bukkitView;
private long bukkitViewHash = 0;
public InventoryView getBukkitView() {
if (bukkitView != null && bukkitViewHash != bukkitViewHash()) {
ArclightContainer.updateView((AbstractContainerMenu) (Object) this, bukkitView);
bukkitViewHash = bukkitViewHash();
}
if (bukkitView == null) {
bukkitView = ArclightContainer.createInvView((AbstractContainerMenu) (Object) this);
bukkitViewHash = bukkitViewHash();
}
return bukkitView;
}
private long bukkitViewHash() {
return (((long) this.slots.size()) << 32) | System.identityHashCode(this.slots);
}
public void transferTo(AbstractContainerMenu other, CraftHumanEntity player) {
InventoryView source = this.getBukkitView();
InventoryView destination = ((ContainerBridge) other).bridge$getBukkitView();
@ -100,7 +90,7 @@ public abstract class AbstractContainerMenuMixin implements ContainerBridge {
private Component title;
public final Component getTitle() {
public Component getTitle() {
if (this.title == null) {
if (this.menuType != null && this.menuType.getRegistryName() != null) {
return new TextComponent(this.menuType.getRegistryName().toString());
@ -111,7 +101,7 @@ public abstract class AbstractContainerMenuMixin implements ContainerBridge {
return this.title;
}
public final void setTitle(Component title) {
public void setTitle(Component title) {
if (this.title == null) {
if (title == null) {
this.title = getTitle();

View File

@ -1,25 +1,15 @@
package io.izzel.arclight.common.mod.server;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.bridge.core.entity.player.PlayerEntityBridge;
import io.izzel.arclight.common.bridge.core.inventory.IInventoryBridge;
import io.izzel.arclight.common.bridge.core.inventory.container.PosContainerBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import io.izzel.tools.product.Product;
import io.izzel.tools.product.Product2;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.SlotItemHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.items.wrapper.InvWrapper;
import net.minecraftforge.items.wrapper.RangedWrapper;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v.inventory.CraftInventory;
@ -30,127 +20,34 @@ import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ArclightContainer {
private static final long HANDLERS_OFFSET;
private static final long COMPOSE_OFFSET;
static {
try {
Unsafe.ensureClassInitialized(CombinedInvWrapper.class);
Field itemHandler = CombinedInvWrapper.class.getDeclaredField("itemHandler");
HANDLERS_OFFSET = Unsafe.objectFieldOffset(itemHandler);
Unsafe.ensureClassInitialized(RangedWrapper.class);
Field compose = RangedWrapper.class.getDeclaredField("compose");
COMPOSE_OFFSET = Unsafe.objectFieldOffset(compose);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
private static Container getActualInventoryForSlot(Slot slot) {
if (slot instanceof SlotItemHandler) {
return getInventoryFromWrapper(((SlotItemHandler) slot).getItemHandler());
} else {
return slot.container;
}
}
private static Container getInventoryFromWrapper(IItemHandler handler) {
if (handler instanceof CombinedInvWrapper) {
IItemHandlerModifiable[] handlers = ((IItemHandlerModifiable[]) Unsafe.getObject(handler, HANDLERS_OFFSET));
Container last = null;
for (IItemHandlerModifiable modifiable : handlers) {
Container inventory = getInventoryFromWrapper(modifiable);
if (inventory instanceof net.minecraft.world.entity.player.Inventory) {
return inventory;
} else {
last = inventory;
}
}
return last;
} else if (handler instanceof InvWrapper) {
return ((InvWrapper) handler).getInv();
} else if (handler instanceof RangedWrapper) {
return getInventoryFromWrapper(((IItemHandler) Unsafe.getObject(handler, COMPOSE_OFFSET)));
} else {
return null;
}
}
/*
* Treat all modded containers not having a "bottom" inventory.
*/
public static InventoryView createInvView(AbstractContainerMenu container) {
Product2<Player, Integer> containerInfo = getContainerInfo(container);
Inventory viewing = new CraftInventory(new ContainerInvWrapper(container, containerInfo._2, containerInfo._1));
return new CraftInventoryView(((PlayerEntityBridge) containerInfo._1).bridge$getBukkitEntity(), viewing, container);
}
public static void updateView(AbstractContainerMenu container, InventoryView inventoryView) {
Inventory topInventory = inventoryView.getTopInventory();
if (topInventory instanceof CraftInventory) {
Container inventory = ((CraftInventory) topInventory).getInventory();
if (inventory instanceof ContainerInvWrapper) {
Product2<Player, Integer> containerInfo = getContainerInfo(container);
((ContainerInvWrapper) inventory).setOwner(((PlayerEntityBridge) containerInfo._1).bridge$getBukkitEntity());
((ContainerInvWrapper) inventory).setSize(containerInfo._2);
}
}
}
// todo check this
private static Product2<Player, Integer> getContainerInfo(AbstractContainerMenu container) {
Player candidate = ArclightCaptures.getContainerOwner();
int bottomBegin = -1, bottomEnd = -1;
for (ListIterator<Slot> iterator = container.slots.listIterator(); iterator.hasNext(); ) {
Slot slot = iterator.next();
Container inventory = getActualInventoryForSlot(slot);
if (inventory instanceof net.minecraft.world.entity.player.Inventory) {
if (candidate != null && ((net.minecraft.world.entity.player.Inventory) inventory).player != candidate) {
ArclightMod.LOGGER.warn("Multiple player found in {}/{}, previous {}, new {}", container, container.getClass(), candidate, ((net.minecraft.world.entity.player.Inventory) inventory).player);
}
candidate = ((net.minecraft.world.entity.player.Inventory) inventory).player;
if (bottomBegin == -1 || bottomBegin < bottomEnd) {
bottomBegin = iterator.previousIndex();
}
} else {
if (bottomEnd < bottomBegin) {
bottomEnd = iterator.previousIndex();
}
}
}
if (candidate == null) {
throw new RuntimeException("candidate cannot be null, " + container + "/" + container.getClass());
}
if (bottomBegin < bottomEnd || bottomBegin == -1) {
bottomBegin = container.slots.size();
}
return Product.of(candidate, bottomBegin);
var containerOwner = ArclightCaptures.getContainerOwner();
Inventory viewing = new CraftInventory(new ContainerInvWrapper(container, containerOwner));
return new CraftInventoryView(((PlayerEntityBridge) containerOwner).bridge$getBukkitEntity(), viewing, container);
}
private static class ContainerInvWrapper implements Container, IInventoryBridge {
private final AbstractContainerMenu container;
private int size;
private InventoryHolder owner;
private final List<HumanEntity> viewers = new ArrayList<>();
public ContainerInvWrapper(AbstractContainerMenu container, int size, Player owner) {
public ContainerInvWrapper(AbstractContainerMenu container, Player owner) {
this.container = container;
this.size = size;
this.owner = ((PlayerEntityBridge) owner).bridge$getBukkitEntity();
}
public void setSize(int size) {
this.size = size;
}
@Override
public int getContainerSize() {
return size;
return this.container.lastSlots.size();
}
@Override
@ -163,31 +60,31 @@ public class ArclightContainer {
@Override
public @NotNull ItemStack getItem(int index) {
if (index >= size) return ItemStack.EMPTY;
if (index >= getContainerSize()) return ItemStack.EMPTY;
return container.getSlot(index).getItem();
}
@Override
public @NotNull ItemStack removeItem(int index, int count) {
if (index >= size) return ItemStack.EMPTY;
if (index >= getContainerSize()) return ItemStack.EMPTY;
return container.getSlot(index).remove(count);
}
@Override
public @NotNull ItemStack removeItemNoUpdate(int index) {
if (index >= size) return ItemStack.EMPTY;
if (index >= getContainerSize()) return ItemStack.EMPTY;
return container.getSlot(index).remove(Integer.MAX_VALUE);
}
@Override
public void setItem(int index, @NotNull ItemStack stack) {
if (index >= size) return;
if (index >= getContainerSize()) return;
container.getSlot(index).set(stack);
}
@Override
public int getMaxStackSize() {
if (size <= 0) return 0;
if (getContainerSize() <= 0) return 0;
return container.getSlot(0).getMaxStackSize();
}
@ -210,7 +107,7 @@ public class ArclightContainer {
@Override
public List<ItemStack> getContents() {
container.broadcastChanges();
return container.lastSlots.subList(0, size);
return container.lastSlots.subList(0, getContainerSize());
}
@Override