Try to address #115

This commit is contained in:
IzzelAliz 2021-01-24 17:42:35 +08:00
parent f0b4f82f1f
commit 2238279647
4 changed files with 192 additions and 39 deletions

View File

@ -1229,7 +1229,9 @@ public abstract class ServerPlayNetHandlerMixin implements ServerPlayNetHandlerB
if (packet.getSlotId() < -1 && packet.getSlotId() != -999) {
return;
}
ArclightCaptures.captureContainerOwner(this.player);
InventoryView inventory = ((ContainerBridge) this.player.openContainer).bridge$getBukkitView();
ArclightCaptures.resetContainerOwner();
InventoryType.SlotType type = inventory.getSlotType(packet.getSlotId());
org.bukkit.event.inventory.ClickType click = org.bukkit.event.inventory.ClickType.UNKNOWN;
InventoryAction action = InventoryAction.UNKNOWN;

View File

@ -0,0 +1,35 @@
package io.izzel.arclight.common.mixin.forge;
import io.izzel.arclight.common.bridge.inventory.container.ContainerBridge;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.network.PacketBuffer;
import net.minecraftforge.fml.network.NetworkHooks;
import org.bukkit.craftbukkit.v.event.CraftEventFactory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.util.function.Consumer;
@Mixin(NetworkHooks.class)
public class NetworkHooksMixin {
@Inject(method = "openGui(Lnet/minecraft/entity/player/ServerPlayerEntity;Lnet/minecraft/inventory/container/INamedContainerProvider;Ljava/util/function/Consumer;)V",
cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/container/Container;getType()Lnet/minecraft/inventory/container/ContainerType;"))
private static void arclight$openContainer(ServerPlayerEntity player, INamedContainerProvider containerSupplier, Consumer<PacketBuffer> extraDataWriter, CallbackInfo ci,
int currentId, PacketBuffer extraData, PacketBuffer output, Container container) {
((ContainerBridge) container).bridge$setTitle(containerSupplier.getDisplayName());
container = CraftEventFactory.callInventoryOpenEvent(player, container);
if (container == null) {
if (containerSupplier instanceof IInventory) {
((IInventory) containerSupplier).closeInventory(player);
}
ci.cancel();
}
}
}

View File

@ -2,29 +2,37 @@ package io.izzel.arclight.common.mod.server;
import io.izzel.arclight.api.Unsafe;
import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge;
import io.izzel.arclight.common.bridge.inventory.IInventoryBridge;
import io.izzel.arclight.common.bridge.inventory.container.PosContainerBridge;
import io.izzel.arclight.common.mod.ArclightMod;
import io.izzel.arclight.common.mod.util.ArclightCaptures;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.CraftResultInventory;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
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;
import org.bukkit.craftbukkit.v.inventory.CraftInventoryCustom;
import org.bukkit.craftbukkit.v.inventory.CraftInventoryView;
import org.bukkit.entity.HumanEntity;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
public class ArclightContainer {
@ -76,50 +84,157 @@ public class ArclightContainer {
// todo check this
public static InventoryView createInvView(Container container) {
PlayerEntity candidate = null;
Set<IInventory> set = new HashSet<>();
for (Slot slot : container.inventorySlots) {
PlayerEntity candidate = ArclightCaptures.getContainerOwner();
int bottomBegin = -1, bottomEnd = -1;
for (ListIterator<Slot> iterator = container.inventorySlots.listIterator(); iterator.hasNext(); ) {
Slot slot = iterator.next();
IInventory inventory = getActualInventoryForSlot(slot);
if (inventory != null) {
if (inventory instanceof PlayerInventory) {
if (candidate != null && ((PlayerInventory) inventory).player != candidate) {
ArclightMod.LOGGER.warn("Multiple player found in {}/{}, previous {}, new {}", container, container.getClass(), candidate, ((PlayerInventory) inventory).player);
}
candidate = ((PlayerInventory) inventory).player;
if (inventory instanceof PlayerInventory) {
if (candidate != null && ((PlayerInventory) inventory).player != candidate) {
ArclightMod.LOGGER.warn("Multiple player found in {}/{}, previous {}, new {}", container, container.getClass(), candidate, ((PlayerInventory) inventory).player);
}
candidate = ((PlayerInventory) inventory).player;
if (bottomBegin == -1 || bottomBegin < bottomEnd) {
bottomBegin = iterator.previousIndex();
}
} else {
if (bottomEnd < bottomBegin) {
bottomEnd = iterator.previousIndex();
}
set.add(inventory);
}
}
if (candidate == null) {
if (ArclightCaptures.getContainerOwner() != null) {
candidate = ArclightCaptures.getContainerOwner();
} else {
throw new RuntimeException("candidate cannot be null, " + container + "/" + container.getClass());
throw new RuntimeException("candidate cannot be null, " + container + "/" + container.getClass());
}
if (bottomBegin < bottomEnd) {
bottomBegin = container.inventorySlots.size();
}
Inventory viewing = new CraftInventory(new ContainerInvWrapper(container, bottomBegin, candidate));
return new CraftInventoryView(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), viewing, container);
}
private static class ContainerInvWrapper implements IInventory, IInventoryBridge {
private final Container container;
private final int size;
private InventoryHolder owner;
private final List<HumanEntity> viewers = new ArrayList<>();
public ContainerInvWrapper(Container container, int size, PlayerEntity owner) {
this.container = container;
this.size = size;
this.owner = ((PlayerEntityBridge) owner).bridge$getBukkitEntity();
}
@Override
public int getSizeInventory() {
return size;
}
@Override
public boolean isEmpty() {
for (Slot slot : container.inventorySlots) {
if (!slot.getStack().isEmpty()) return false;
}
return true;
}
@Override
public @NotNull ItemStack getStackInSlot(int index) {
if (index >= size) return ItemStack.EMPTY;
return container.getSlot(index).getStack();
}
@Override
public @NotNull ItemStack decrStackSize(int index, int count) {
if (index >= size) return ItemStack.EMPTY;
return container.getSlot(index).decrStackSize(count);
}
@Override
public @NotNull ItemStack removeStackFromSlot(int index) {
if (index >= size) return ItemStack.EMPTY;
return container.getSlot(index).decrStackSize(Integer.MAX_VALUE);
}
@Override
public void setInventorySlotContents(int index, @NotNull ItemStack stack) {
if (index >= size) return;
container.putStackInSlot(index, stack);
}
@Override
public int getInventoryStackLimit() {
if (size <= 0) return 0;
return container.getSlot(0).getSlotStackLimit();
}
@Override
public void markDirty() {
}
@Override
public boolean isUsableByPlayer(@NotNull PlayerEntity player) {
return this.container.canInteractWith(player);
}
@Override
public void clear() {
for (Slot slot : this.container.inventorySlots) {
slot.decrStackSize(Integer.MAX_VALUE);
}
}
CraftResultInventory resultCandidate = null;
IInventory mainCandidate = null;
for (IInventory inventory : set) {
if (inventory instanceof CraftResultInventory) {
resultCandidate = (CraftResultInventory) inventory;
} else {
mainCandidate = inventory;
@Override
public List<ItemStack> getContents() {
container.detectAndSendChanges();
return container.inventoryItemStacks.subList(0, size);
}
@Override
public void onOpen(CraftHumanEntity who) {
viewers.add(who);
}
@Override
public void onClose(CraftHumanEntity who) {
viewers.remove(who);
}
@Override
public List<HumanEntity> getViewers() {
return viewers;
}
@Override
public InventoryHolder getOwner() {
return owner;
}
@Override
public void setOwner(InventoryHolder owner) {
this.owner = owner;
}
@Override
public void setMaxStackSize(int size) {
}
@Override
public Location getLocation() {
if (container instanceof PosContainerBridge) {
return ((PosContainerBridge) container).bridge$getWorldLocation();
}
return null;
}
Inventory inv;
if (mainCandidate == null && resultCandidate != null) {
mainCandidate = resultCandidate;
resultCandidate = null;
@Override
public IRecipe<?> getCurrentRecipe() {
return null;
}
if (mainCandidate != null) {
if (resultCandidate != null) {
inv = new org.bukkit.craftbukkit.v.inventory.CraftResultInventory(mainCandidate, resultCandidate);
} else {
inv = new CraftInventory(mainCandidate);
}
} else { // container has no slots
inv = new CraftInventoryCustom(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), 0);
@Override
public void setCurrentRecipe(IRecipe<?> recipe) {
}
return new CraftInventoryView(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), inv, container);
}
}

View File

@ -8,6 +8,7 @@
"mixins": [
"ForgeEventFactoryMixin",
"ForgeHooksMixin",
"ForgeInternalHandlerMixin"
"ForgeInternalHandlerMixin",
"NetworkHooksMixin"
]
}