package advancedsystemsmanager.tileentities; import advancedsystemsmanager.api.tileentities.ITileInterfaceProvider; import advancedsystemsmanager.api.tileentities.IActivateListener; import advancedsystemsmanager.containers.ContainerRelay; import advancedsystemsmanager.client.gui.GuiRelay; import advancedsystemsmanager.network.ASMPacket; import advancedsystemsmanager.network.PacketHandler; import advancedsystemsmanager.util.UserPermission; import advancedsystemsmanager.util.wrappers.InventoryWrapper; import advancedsystemsmanager.util.wrappers.InventoryWrapperHorse; import advancedsystemsmanager.util.wrappers.InventoryWrapperPlayer; import com.mojang.authlib.GameProfile; import cpw.mods.fml.common.network.ByteBufUtils; import cpw.mods.fml.relauncher.Side; import cpw.mods.fml.relauncher.SideOnly; import net.minecraft.client.gui.GuiScreen; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityLivingBase; import net.minecraft.entity.passive.EntityHorse; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.inventory.Container; import net.minecraft.inventory.IInventory; import net.minecraft.inventory.ISidedInventory; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.FluidTankInfo; import net.minecraftforge.fluids.IFluidHandler; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class TileEntityRelay extends TileEntityElementRotation implements IInventory, ISidedInventory, IFluidHandler, ITileInterfaceProvider, IActivateListener { private static final int MAX_CHAIN_LENGTH = 512; private static final String NBT_OWNER = "Owner"; private static final String NBT_UUID = "UUID"; private static final String NBT_CREATIVE = "Creative"; private static final String NBT_LIST = "ShowList"; private static final String NBT_PERMISSIONS = "Permissions"; private static final String NBT_NAME = "Name"; private static final String NBT_ACTIVE = "Active"; private static final String NBT_EDITOR = "Editor"; public static int PERMISSION_MAX_LENGTH = 255; private int[] cachedAllSlots; private boolean blockingUsage; private int chainLength; private Entity[] cachedEntities = new Entity[2]; private InventoryWrapper cachedInventoryWrapper; //used by the advanced version private List<UserPermission> permissions = new ArrayList<UserPermission>(); private boolean doesListRequireOp = false; private GameProfile owner; private boolean creativeMode; public String getOwnerName() { return owner == null ? "Unknown" : owner.getName(); } public GameProfile getOwner() { return owner; } public void setOwner(EntityLivingBase entity) { if (entity != null && entity instanceof EntityPlayer) { owner = ((EntityPlayer)entity).getGameProfile(); } } public void setListRequireOp(boolean val) { doesListRequireOp = val; } public List<UserPermission> getPermissions() { return permissions; } @Override public int[] getAccessibleSlotsFromSide(int var1) { try { IInventory inventory = getInventory(); if (inventory != null) { if (inventory instanceof ISidedInventory) { return ((ISidedInventory)inventory).getAccessibleSlotsFromSide(var1); } else { int size = inventory.getSizeInventory(); if (cachedAllSlots == null || cachedAllSlots.length != size) { cachedAllSlots = new int[size]; for (int i = 0; i < size; i++) { cachedAllSlots[i] = i; } } return cachedAllSlots; } } return new int[0]; } finally { unBlockUsage(); } } @Override public boolean canInsertItem(int i, ItemStack itemstack, int j) { try { IInventory inventory = getInventory(); if (inventory != null) { if (inventory instanceof ISidedInventory) { return ((ISidedInventory)inventory).canInsertItem(i, itemstack, j); } else { return inventory.isItemValidForSlot(i, itemstack); } } return false; } finally { unBlockUsage(); } } @Override public boolean canExtractItem(int i, ItemStack itemstack, int j) { try { IInventory inventory = getInventory(); if (inventory != null) { if (inventory instanceof ISidedInventory) { return ((ISidedInventory)inventory).canExtractItem(i, itemstack, j); } else { return inventory.isItemValidForSlot(i, itemstack); } } return false; } finally { unBlockUsage(); } } private IInventory getInventory() { return getContainer(IInventory.class, 0); } private void unBlockUsage() { blockingUsage = false; chainLength = 0; } private <T> T getContainer(Class<T> type, int id) { if (isBlockingUsage()) { return null; } blockUsage(); if (cachedEntities[id] != null) { if (cachedEntities[id].isDead) { cachedEntities[id] = null; if (id == 0) { cachedInventoryWrapper = null; } } else { return getEntityContainer(id); } } ForgeDirection direction = getFacing(); int x = xCoord + direction.offsetX; int y = yCoord + direction.offsetY; int z = zCoord + direction.offsetZ; World world = getWorldObj(); if (world != null) { TileEntity te = world.getTileEntity(x, y, z); if (te != null && type.isInstance(te)) { if (te instanceof TileEntityRelay) { TileEntityRelay relay = (TileEntityRelay)te; relay.chainLength = chainLength + 1; } return (T)te; } List<Entity> entities = world.getEntitiesWithinAABB(Entity.class, AxisAlignedBB.getBoundingBox(x, y, z, x + 1, y + 1, z + 1)); if (entities != null) { double closest = Double.MAX_VALUE; for (Entity entity : entities) { double distance = entity.getDistanceSq(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5); if (isEntityValid(entity, type, id) && distance < closest) { closest = distance; cachedEntities[id] = entity; } } if (id == 0 && cachedEntities[id] != null) { cachedInventoryWrapper = getInventoryWrapper(cachedEntities[id]); } return getEntityContainer(id); } } return null; } public boolean isBlockingUsage() { return blockingUsage || chainLength >= MAX_CHAIN_LENGTH; } private void blockUsage() { blockingUsage = true; } private <T> T getEntityContainer(int id) { if (id == 0 && cachedInventoryWrapper != null) { return (T)cachedInventoryWrapper; } return (T)cachedEntities[id]; } private boolean isEntityValid(Entity entity, Class type, int id) { return type.isInstance(entity) || (id == 0 && ((entity instanceof EntityPlayer && allowPlayerInteraction((EntityPlayer)entity)) || entity instanceof EntityHorse)); } private InventoryWrapper getInventoryWrapper(Entity entity) { if (entity instanceof EntityPlayer) { return new InventoryWrapperPlayer((EntityPlayer)entity); } else if (entity instanceof EntityHorse) { return new InventoryWrapperHorse((EntityHorse)entity); } else { return null; } } public boolean allowPlayerInteraction(EntityPlayer player) { return isAdvanced() && (creativeMode != isPlayerActive(player)); } private boolean isAdvanced() { return subtype != 0; } private boolean isPlayerActive(EntityPlayer player) { if (player != null) { for (UserPermission permission : permissions) { if (permission.getUser().equals(player.getGameProfile())) { return permission.isActive(); } } } return true; } @Override public int getSizeInventory() { try { IInventory inventory = getInventory(); if (inventory != null) { return inventory.getSizeInventory(); } return 0; } finally { unBlockUsage(); } } @Override public ItemStack getStackInSlot(int i) { try { IInventory inventory = getInventory(); if (inventory != null) { return inventory.getStackInSlot(i); } return null; } finally { unBlockUsage(); } } @Override public ItemStack decrStackSize(int i, int j) { try { IInventory inventory = getInventory(); if (inventory != null) { return inventory.decrStackSize(i, j); } return null; } finally { unBlockUsage(); } } @Override public ItemStack getStackInSlotOnClosing(int i) { //don't drop the things twice return null; } @Override public void setInventorySlotContents(int i, ItemStack itemstack) { try { IInventory inventory = getInventory(); if (inventory != null) { inventory.setInventorySlotContents(i, itemstack); } } finally { unBlockUsage(); } } @Override public String getInventoryName() { try { IInventory inventory = getInventory(); if (inventory != null) { return inventory.getInventoryName(); } return "Unknown"; } finally { unBlockUsage(); } } @Override public boolean hasCustomInventoryName() { try { IInventory inventory = getInventory(); return inventory != null && inventory.hasCustomInventoryName(); } finally { unBlockUsage(); } } @Override public int getInventoryStackLimit() { try { IInventory inventory = getInventory(); if (inventory != null) { return inventory.getInventoryStackLimit(); } return 0; } finally { unBlockUsage(); } } @Override public boolean isUseableByPlayer(EntityPlayer entityplayer) { try { IInventory inventory = getInventory(); return inventory != null && inventory.isUseableByPlayer(entityplayer); } finally { unBlockUsage(); } } @Override public void openInventory() { try { IInventory inventory = getInventory(); if (inventory != null) { inventory.openInventory(); } } finally { unBlockUsage(); } } @Override public void closeInventory() { try { IInventory inventory = getInventory(); if (inventory != null) { inventory.closeInventory(); } } finally { unBlockUsage(); } } @Override public boolean isItemValidForSlot(int i, ItemStack itemstack) { try { IInventory inventory = getInventory(); return inventory != null && inventory.isItemValidForSlot(i, itemstack); } finally { unBlockUsage(); } } @Override public int fill(ForgeDirection from, FluidStack resource, boolean doFill) { try { IFluidHandler tank = getTank(); if (tank != null) { return tank.fill(from, resource, doFill); } return 0; } finally { unBlockUsage(); } } @Override public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) { try { IFluidHandler tank = getTank(); if (tank != null) { return tank.drain(from, resource, doDrain); } return null; } finally { unBlockUsage(); } } @Override public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) { try { IFluidHandler tank = getTank(); if (tank != null) { return tank.drain(from, maxDrain, doDrain); } return null; } finally { unBlockUsage(); } } @Override public boolean canFill(ForgeDirection from, Fluid fluid) { try { IFluidHandler tank = getTank(); return tank != null && tank.canFill(from, fluid); } finally { unBlockUsage(); } } @Override public boolean canDrain(ForgeDirection from, Fluid fluid) { try { IFluidHandler tank = getTank(); return tank != null && tank.canDrain(from, fluid); } finally { unBlockUsage(); } } @Override public FluidTankInfo[] getTankInfo(ForgeDirection from) { try { IFluidHandler tank = getTank(); if (tank != null) { return tank.getTankInfo(from); } return new FluidTankInfo[0]; } finally { unBlockUsage(); } } private IFluidHandler getTank() { return getContainer(IFluidHandler.class, 1); } @Override public void updateEntity() { cachedEntities[0] = null; cachedEntities[1] = null; cachedInventoryWrapper = null; } @Override public void markDirty() { //super.onInventoryChanged(); try { IInventory inventory = getInventory(); if (inventory != null) { inventory.markDirty(); } } finally { unBlockUsage(); } } @Override public Container getContainer(EntityPlayer player) { return new ContainerRelay(this, player.inventory); } @SideOnly(Side.CLIENT) @Override public GuiScreen getGui(EntityPlayer player) { return new GuiRelay(this, player.inventory); } @Override public boolean readData(ASMPacket buf, EntityPlayer player) { readUpdatedData(buf, player); return false; } public void readUpdatedData(ASMPacket dr, EntityPlayer player) { if (!worldObj.isRemote) { boolean action = dr.readBoolean(); if (action) { return; } } GameProfile user = player.getGameProfile(); boolean isOp = false; if (worldObj.isRemote || user.equals(owner)) { isOp = true; } else { for (UserPermission permission : permissions) { if (user.equals(permission.getUser())) { isOp = permission.isOp(); break; } } } boolean userData = dr.readBoolean(); if (userData) { boolean added = dr.readBoolean(); if (added) { UserPermission permission = new UserPermission(dr.readStringFromBuffer(), dr.readUUID()); for (UserPermission userPermission : permissions) { if (userPermission.getUser().equals(permission.getUser())) { return; } } if (worldObj.isRemote) { permission.setActive(dr.readBoolean()); permission.setOp(dr.readBoolean()); } if (permissions.size() < TileEntityRelay.PERMISSION_MAX_LENGTH && (worldObj.isRemote || permission.getUser().equals(user))) { permissions.add(permission); } } else { int id = dr.readByte(); if (id >= 0 && id < permissions.size()) { boolean deleted = dr.readBoolean(); if (deleted) { UserPermission permission = permissions.get(id); if (isOp || permission.getUser().equals(user)) { permissions.remove(id); } } else if (isOp) { UserPermission permission = permissions.get(id); permission.setActive(dr.readBoolean()); permission.setOp(dr.readBoolean()); } } } } else if (isOp) { creativeMode = dr.readBoolean(); doesListRequireOp = dr.readBoolean(); } } public void updateData(ContainerRelay container) { if (container.oldCreativeMode != isCreativeMode() || container.oldOpList != doesListRequireOp()) { container.oldOpList = doesListRequireOp(); container.oldCreativeMode = isCreativeMode(); ASMPacket dw = PacketHandler.getWriterForUpdate(container); dw.writeBoolean(false); //no user data dw.writeBoolean(creativeMode); dw.writeBoolean(doesListRequireOp); PacketHandler.sendDataToListeningClients(container, dw); } //added if (permissions.size() > container.oldPermissions.size()) { int id = container.oldPermissions.size(); UserPermission permission = permissions.get(id); ASMPacket dw = PacketHandler.getWriterForUpdate(container); dw.writeBoolean(true); //user data dw.writeBoolean(true); //added dw.writeStringToBuffer(permission.getUser().getName()); dw.writeUUID(permission.getUser().getId()); dw.writeBoolean(permission.isActive()); dw.writeBoolean(permission.isOp()); PacketHandler.sendDataToListeningClients(container, dw); container.oldPermissions.add(permission.copy()); //removed } else if (permissions.size() < container.oldPermissions.size()) { for (int i = 0; i < container.oldPermissions.size(); i++) { if (i >= permissions.size() || !permissions.get(i).getUser().equals(container.oldPermissions.get(i).getUser())) { ASMPacket dw = PacketHandler.getWriterForUpdate(container); dw.writeBoolean(true); //user data dw.writeBoolean(false); //existing dw.writeInt(i); dw.writeBoolean(true); //deleted PacketHandler.sendDataToListeningClients(container, dw); container.oldPermissions.remove(i); break; } } //updated } else { for (int i = 0; i < permissions.size(); i++) { UserPermission permission = permissions.get(i); UserPermission oldPermission = container.oldPermissions.get(i); if (permission.isOp() != oldPermission.isOp() || permission.isActive() != oldPermission.isActive()) { ASMPacket dw = PacketHandler.getWriterForUpdate(container); dw.writeBoolean(true); //user data dw.writeBoolean(false); //existing dw.writeInt(i); dw.writeBoolean(false); //update dw.writeBoolean(permission.isActive()); dw.writeBoolean(permission.isOp()); PacketHandler.sendDataToListeningClients(container, dw); oldPermission.setActive(permission.isActive()); oldPermission.setOp(permission.isOp()); } } } } public boolean doesListRequireOp() { return doesListRequireOp; } public boolean isCreativeMode() { return creativeMode; } public void setCreativeMode(boolean creativeMode) { this.creativeMode = creativeMode; } @Override public boolean writeData(ASMPacket packet) { NBTTagCompound tagCompound = new NBTTagCompound(); writeToTileNBT(tagCompound); ByteBufUtils.writeTag(packet, tagCompound); return true; } @Override public void writeToTileNBT(NBTTagCompound tag) { super.writeToTileNBT(tag); if (isAdvanced()) { if (owner != null) { tag.setString(NBT_OWNER, owner.getName()); tag.setString(NBT_UUID, owner.getId().toString()); } tag.setBoolean(NBT_CREATIVE, creativeMode); tag.setBoolean(NBT_LIST, doesListRequireOp); NBTTagList permissionTags = new NBTTagList(); for (UserPermission permission : permissions) { NBTTagCompound permissionTag = new NBTTagCompound(); tag.setString(NBT_NAME, permission.getUser().getName()); tag.setString(NBT_UUID, permission.getUser().getId().toString()); permissionTag.setBoolean(NBT_ACTIVE, permission.isActive()); permissionTag.setBoolean(NBT_EDITOR, permission.isOp()); permissionTags.appendTag(permissionTag); } tag.setTag(NBT_PERMISSIONS, permissionTags); } } @Override public void readFromTileNBT(NBTTagCompound tag) { super.readFromTileNBT(tag); if (tag.hasKey(NBT_OWNER)) { String name = tag.getString(NBT_OWNER); UUID id = UUID.fromString(tag.getString(NBT_UUID)); owner = new GameProfile(id, name); creativeMode = tag.getBoolean(NBT_CREATIVE); doesListRequireOp = tag.getBoolean(NBT_LIST); permissions.clear(); NBTTagList permissionTags = tag.getTagList(NBT_PERMISSIONS, 10); for (int i = 0; i < permissionTags.tagCount(); i++) { NBTTagCompound permissionTag = permissionTags.getCompoundTagAt(i); UserPermission permission = new UserPermission(permissionTag.getString(NBT_NAME), UUID.fromString(tag.getString(NBT_UUID))); permission.setActive(permissionTag.getBoolean(NBT_ACTIVE)); permission.setOp(permissionTag.getBoolean(NBT_EDITOR)); permissions.add(permission); } } } }