Find players from forge wrapper classes
This commit is contained in:
parent
6c8d6d832a
commit
401a290c68
|
@ -4,11 +4,13 @@ import com.google.common.collect.ImmutableMap;
|
|||
import io.izzel.arclight.common.bridge.block.FireBlockBridge;
|
||||
import io.izzel.arclight.common.bridge.bukkit.MaterialBridge;
|
||||
import io.izzel.arclight.common.mod.ArclightMod;
|
||||
import io.izzel.arclight.common.mod.server.block.ArclightTileInventory;
|
||||
import io.izzel.arclight.i18n.LocalizedException;
|
||||
import io.izzel.arclight.i18n.conf.MaterialPropertySpec;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.block.FallingBlock;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
|
@ -334,6 +336,7 @@ public abstract class MaterialMixin implements MaterialBridge {
|
|||
this.setupBlockStateFunc();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
private void setupBlockStateFunc() {
|
||||
if (arclight$spec.blockStateClass != null) {
|
||||
try {
|
||||
|
@ -368,6 +371,9 @@ public abstract class MaterialMixin implements MaterialBridge {
|
|||
if (this.arclight$stateFunc == null) {
|
||||
this.arclight$stateFunc = b -> {
|
||||
TileEntity tileEntity = b.getCraftWorld().getHandle().getTileEntity(b.getPosition());
|
||||
if (tileEntity instanceof IInventory) {
|
||||
return new ArclightTileInventory(b, tileEntity.getClass());
|
||||
}
|
||||
return tileEntity == null ? new CraftBlockState(b) : new CraftBlockEntityState<>(b, tileEntity.getClass());
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,18 +1,15 @@
|
|||
package io.izzel.arclight.common.mixin.core.inventory.container;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
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.ContainerBridge;
|
||||
import io.izzel.arclight.common.bridge.inventory.container.SlotBridge;
|
||||
import io.izzel.arclight.common.mod.ArclightMod;
|
||||
import io.izzel.arclight.common.mod.util.ArclightCaptures;
|
||||
import io.izzel.arclight.common.mod.server.ArclightContainer;
|
||||
import net.minecraft.entity.item.ItemEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.entity.player.PlayerInventory;
|
||||
import net.minecraft.entity.player.ServerPlayerEntity;
|
||||
import net.minecraft.inventory.CraftResultInventory;
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.inventory.container.ClickType;
|
||||
import net.minecraft.inventory.container.Container;
|
||||
import net.minecraft.inventory.container.ContainerType;
|
||||
|
@ -25,13 +22,10 @@ import org.bukkit.Bukkit;
|
|||
import org.bukkit.Material;
|
||||
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.craftbukkit.v.inventory.CraftItemStack;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
|
@ -42,7 +36,6 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -75,54 +68,9 @@ public abstract class ContainerMixin implements ContainerBridge {
|
|||
public boolean checkReachable = true;
|
||||
private InventoryView bukkitView;
|
||||
|
||||
// todo check this
|
||||
public InventoryView getBukkitView() {
|
||||
if (bukkitView == null) {
|
||||
PlayerEntity candidate = null;
|
||||
Set<IInventory> set = new HashSet<>();
|
||||
for (Slot slot : this.inventorySlots) {
|
||||
if (slot.inventory != null) {
|
||||
if (slot.inventory instanceof PlayerInventory) {
|
||||
if (candidate != null && ((PlayerInventory) slot.inventory).player != candidate) {
|
||||
ArclightMod.LOGGER.warn("Duplicate PlayerInventory inside {}, previous {}, new {}", this, candidate, slot.inventory);
|
||||
}
|
||||
candidate = ((PlayerInventory) slot.inventory).player;
|
||||
} else {
|
||||
set.add(slot.inventory);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (candidate == null) {
|
||||
if (ArclightCaptures.getContainerOwner() != null) {
|
||||
candidate = ArclightCaptures.getContainerOwner();
|
||||
} else {
|
||||
throw new RuntimeException("candidate cannot be null");
|
||||
}
|
||||
}
|
||||
CraftResultInventory resultCandidate = null;
|
||||
IInventory mainCandidate = null;
|
||||
for (IInventory inventory : set) {
|
||||
if (inventory instanceof CraftResultInventory) {
|
||||
resultCandidate = (CraftResultInventory) inventory;
|
||||
} else {
|
||||
mainCandidate = inventory;
|
||||
}
|
||||
}
|
||||
Inventory inv;
|
||||
if (mainCandidate == null && resultCandidate != null) {
|
||||
mainCandidate = resultCandidate;
|
||||
resultCandidate = 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);
|
||||
}
|
||||
bukkitView = new CraftInventoryView(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), inv, (Container) (Object) this);
|
||||
bukkitView = ArclightContainer.createInvView((Container) (Object) this);
|
||||
}
|
||||
return bukkitView;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
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.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.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.craftbukkit.v.inventory.CraftInventory;
|
||||
import org.bukkit.craftbukkit.v.inventory.CraftInventoryCustom;
|
||||
import org.bukkit.craftbukkit.v.inventory.CraftInventoryView;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
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 IInventory getActualInventoryForSlot(Slot slot) {
|
||||
if (slot instanceof SlotItemHandler) {
|
||||
return getInventoryFromWrapper(((SlotItemHandler) slot).getItemHandler());
|
||||
} else {
|
||||
return slot.inventory;
|
||||
}
|
||||
}
|
||||
|
||||
private static IInventory getInventoryFromWrapper(IItemHandler handler) {
|
||||
if (handler instanceof CombinedInvWrapper) {
|
||||
IItemHandlerModifiable[] handlers = ((IItemHandlerModifiable[]) Unsafe.getObject(handler, HANDLERS_OFFSET));
|
||||
IInventory last = null;
|
||||
for (IItemHandlerModifiable modifiable : handlers) {
|
||||
IInventory inventory = getInventoryFromWrapper(modifiable);
|
||||
if (inventory instanceof PlayerInventory) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// todo check this
|
||||
public static InventoryView createInvView(Container container) {
|
||||
PlayerEntity candidate = null;
|
||||
Set<IInventory> set = new HashSet<>();
|
||||
for (Slot slot : container.inventorySlots) {
|
||||
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;
|
||||
}
|
||||
set.add(inventory);
|
||||
}
|
||||
}
|
||||
if (candidate == null) {
|
||||
if (ArclightCaptures.getContainerOwner() != null) {
|
||||
candidate = ArclightCaptures.getContainerOwner();
|
||||
} else {
|
||||
throw new RuntimeException("candidate cannot be null, " + container + "/" + container.getClass());
|
||||
}
|
||||
}
|
||||
CraftResultInventory resultCandidate = null;
|
||||
IInventory mainCandidate = null;
|
||||
for (IInventory inventory : set) {
|
||||
if (inventory instanceof CraftResultInventory) {
|
||||
resultCandidate = (CraftResultInventory) inventory;
|
||||
} else {
|
||||
mainCandidate = inventory;
|
||||
}
|
||||
}
|
||||
Inventory inv;
|
||||
if (mainCandidate == null && resultCandidate != null) {
|
||||
mainCandidate = resultCandidate;
|
||||
resultCandidate = 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);
|
||||
}
|
||||
return new CraftInventoryView(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), inv, container);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package io.izzel.arclight.common.mod.server.block;
|
||||
|
||||
import net.minecraft.inventory.IInventory;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.craftbukkit.v.block.CraftBlockEntityState;
|
||||
import org.bukkit.craftbukkit.v.inventory.CraftInventory;
|
||||
import org.bukkit.inventory.BlockInventoryHolder;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ArclightTileInventory<T extends TileEntity & IInventory> extends CraftBlockEntityState<T> implements BlockInventoryHolder {
|
||||
|
||||
public ArclightTileInventory(Block block, Class<T> tileEntityClass) {
|
||||
super(block, tileEntityClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Inventory getInventory() {
|
||||
return new CraftInventory(this.getTileEntity());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user