0d43ca15be
Moved all internal access to the internal `Api` class using a new static getter.
210 lines
7.5 KiB
Java
210 lines
7.5 KiB
Java
package appeng.container.implementations;
|
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
import net.minecraft.entity.player.PlayerInventory;
|
|
import net.minecraft.entity.player.ServerPlayerEntity;
|
|
import net.minecraft.inventory.container.INamedContainerProvider;
|
|
import net.minecraft.inventory.container.SimpleNamedContainerProvider;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.network.PacketBuffer;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.math.BlockPos;
|
|
import net.minecraft.util.text.ITextComponent;
|
|
import net.minecraft.util.text.StringTextComponent;
|
|
import net.minecraft.util.text.TranslationTextComponent;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.fml.network.NetworkHooks;
|
|
|
|
import appeng.api.config.SecurityPermissions;
|
|
import appeng.api.features.IWirelessTermHandler;
|
|
import appeng.api.implementations.guiobjects.IGuiItem;
|
|
import appeng.api.implementations.guiobjects.IGuiItemObject;
|
|
import appeng.api.parts.IPart;
|
|
import appeng.api.parts.IPartHost;
|
|
import appeng.container.AEBaseContainer;
|
|
import appeng.container.ContainerLocator;
|
|
import appeng.core.AELog;
|
|
import appeng.core.Api;
|
|
import appeng.helpers.ICustomNameObject;
|
|
import appeng.helpers.WirelessTerminalGuiObject;
|
|
import appeng.util.Platform;
|
|
|
|
/**
|
|
* Helper for containers that can be opened for a part <em>or</em> tile given
|
|
* that either implements a given interface.
|
|
*
|
|
* @param <C>
|
|
*/
|
|
public final class ContainerHelper<C extends AEBaseContainer, I> {
|
|
|
|
private final Class<I> interfaceClass;
|
|
|
|
private final ContainerFactory<C, I> factory;
|
|
|
|
private final SecurityPermissions requiredPermission;
|
|
|
|
public ContainerHelper(ContainerFactory<C, I> factory, Class<I> interfaceClass) {
|
|
this(factory, interfaceClass, null);
|
|
}
|
|
|
|
public ContainerHelper(ContainerFactory<C, I> factory, Class<I> interfaceClass,
|
|
SecurityPermissions requiredPermission) {
|
|
this.requiredPermission = requiredPermission;
|
|
this.interfaceClass = interfaceClass;
|
|
this.factory = factory;
|
|
}
|
|
|
|
/**
|
|
* Opens a container that is based around a single tile entity. The tile
|
|
* entity's position is encoded in the packet buffer.
|
|
*/
|
|
public C fromNetwork(int windowId, PlayerInventory inv, PacketBuffer packetBuf) {
|
|
I host = getHostFromLocator(inv.player, ContainerLocator.read(packetBuf));
|
|
if (host != null) {
|
|
return factory.create(windowId, inv, host);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public boolean open(PlayerEntity player, ContainerLocator locator) {
|
|
if (!(player instanceof ServerPlayerEntity)) {
|
|
// Cannot open containers on the client or for non-players
|
|
// FIXME logging?
|
|
return false;
|
|
}
|
|
|
|
I accessInterface = getHostFromLocator(player, locator);
|
|
|
|
if (accessInterface == null) {
|
|
return false;
|
|
}
|
|
|
|
if (!checkPermission(player, accessInterface)) {
|
|
return false;
|
|
}
|
|
|
|
ITextComponent title = findContainerTitle(player.world, locator, accessInterface);
|
|
|
|
INamedContainerProvider container = new SimpleNamedContainerProvider((wnd, p, pl) -> {
|
|
C c = factory.create(wnd, p, accessInterface);
|
|
// Set the original locator on the opened server-side container for it to more
|
|
// easily remember how to re-open after being closed.
|
|
c.setLocator(locator);
|
|
return c;
|
|
}, title);
|
|
NetworkHooks.openGui((ServerPlayerEntity) player, container, locator::write);
|
|
|
|
return true;
|
|
}
|
|
|
|
private ITextComponent findContainerTitle(World world, ContainerLocator locator, I accessInterface) {
|
|
|
|
if (accessInterface instanceof ICustomNameObject) {
|
|
ICustomNameObject customNameObject = (ICustomNameObject) accessInterface;
|
|
if (customNameObject.hasCustomInventoryName()) {
|
|
return customNameObject.getCustomInventoryName();
|
|
}
|
|
}
|
|
|
|
// Use block name at position
|
|
// FIXME: this is not right, we'd need to check the part's item stack, or custom
|
|
// naming interface impl
|
|
// FIXME: Should move this up, because at this point, it's hard to know where
|
|
// the terminal host came from (part or tile)
|
|
if (locator.hasBlockPos()) {
|
|
return new TranslationTextComponent(
|
|
world.getBlockState(locator.getBlockPos()).getBlock().getTranslationKey());
|
|
}
|
|
|
|
return new StringTextComponent("Unknown");
|
|
|
|
}
|
|
|
|
private I getHostFromLocator(PlayerEntity player, ContainerLocator locator) {
|
|
if (locator.hasItemIndex()) {
|
|
return getHostFromPlayerInventory(player, locator);
|
|
}
|
|
|
|
if (!locator.hasBlockPos()) {
|
|
return null; // No block was clicked
|
|
}
|
|
|
|
TileEntity tileEntity = player.world.getTileEntity(locator.getBlockPos());
|
|
|
|
// The tile entity itself can host a terminal (i.e. Chest!)
|
|
if (interfaceClass.isInstance(tileEntity)) {
|
|
return interfaceClass.cast(tileEntity);
|
|
}
|
|
|
|
if (!locator.hasSide()) {
|
|
return null;
|
|
}
|
|
|
|
if (tileEntity instanceof IPartHost) {
|
|
// But it could also be a part attached to the tile entity
|
|
IPartHost partHost = (IPartHost) tileEntity;
|
|
IPart part = partHost.getPart(locator.getSide());
|
|
if (part == null) {
|
|
return null;
|
|
}
|
|
|
|
if (interfaceClass.isInstance(part)) {
|
|
return interfaceClass.cast(part);
|
|
} else {
|
|
AELog.debug("Trying to open a container @ %s for a %s, but the container requires %s", locator,
|
|
part.getClass(), interfaceClass);
|
|
return null;
|
|
}
|
|
} else {
|
|
// FIXME: Logging? Dont know how to obtain the terminal host
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private I getHostFromPlayerInventory(PlayerEntity player, ContainerLocator locator) {
|
|
|
|
ItemStack it = player.inventory.getStackInSlot(locator.getItemIndex());
|
|
|
|
if (it.isEmpty()) {
|
|
AELog.debug("Cannot open container for player %s since they no longer hold the item in slot %d", player,
|
|
locator.hasItemIndex());
|
|
return null;
|
|
}
|
|
|
|
if (it.getItem() instanceof IGuiItem) {
|
|
IGuiItem guiItem = (IGuiItem) it.getItem();
|
|
// Optionally contains the block the item was used on to open the container
|
|
BlockPos blockPos = locator.hasBlockPos() ? locator.getBlockPos() : null;
|
|
IGuiItemObject guiObject = guiItem.getGuiObject(it, locator.getItemIndex(), player.world, blockPos);
|
|
if (interfaceClass.isInstance(guiObject)) {
|
|
return interfaceClass.cast(guiObject);
|
|
}
|
|
}
|
|
|
|
if (interfaceClass.isAssignableFrom(WirelessTerminalGuiObject.class)) {
|
|
final IWirelessTermHandler wh = Api.instance().registries().wireless().getWirelessTerminalHandler(it);
|
|
if (wh != null) {
|
|
return interfaceClass.cast(new WirelessTerminalGuiObject(wh, it, player, locator.getItemIndex()));
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
@FunctionalInterface
|
|
public interface ContainerFactory<C, I> {
|
|
C create(int windowId, PlayerInventory playerInv, I accessObj);
|
|
}
|
|
|
|
private boolean checkPermission(PlayerEntity player, Object accessInterface) {
|
|
|
|
if (requiredPermission != null) {
|
|
return Platform.checkPermissions(player, accessInterface, requiredPermission, true);
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|