Package net.mcft.copy.betterstorage.tile.crate

Source Code of net.mcft.copy.betterstorage.tile.crate.TileEntityCrate

package net.mcft.copy.betterstorage.tile.crate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;

import net.mcft.copy.betterstorage.api.crate.ICrateStorage;
import net.mcft.copy.betterstorage.api.crate.ICrateWatcher;
import net.mcft.copy.betterstorage.config.GlobalConfig;
import net.mcft.copy.betterstorage.container.ContainerBetterStorage;
import net.mcft.copy.betterstorage.container.ContainerCrate;
import net.mcft.copy.betterstorage.content.BetterStorageTiles;
import net.mcft.copy.betterstorage.inventory.InventoryCratePlayerView;
import net.mcft.copy.betterstorage.misc.Constants;
import net.mcft.copy.betterstorage.misc.ItemIdentifier;
import net.mcft.copy.betterstorage.tile.entity.TileEntityContainer;
import net.mcft.copy.betterstorage.utils.PlayerUtils;
import net.mcft.copy.betterstorage.utils.WorldUtils;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.network.play.server.S35PacketUpdateTileEntity;
import net.minecraftforge.common.util.ForgeDirection;

public class TileEntityCrate extends TileEntityContainer implements IInventory, ICrateStorage, ICrateWatcher {
 
  private static final ForgeDirection[] sideDirections = {
    ForgeDirection.NORTH, ForgeDirection.SOUTH, ForgeDirection.WEST, ForgeDirection.EAST
  };
 
  public static final int slotsPerCrate = 18;
 
  private CratePileData data;
  /** Crate pile id of this crate, used only for saving/loading. */
  private int id = -1;
 
  public int getID() { return id; }
 
  /** Get the pile data for this tile entity. */
  public CratePileData getPileData() {
    if (worldObj.isRemote)
      throw new IllegalStateException("Can't be called client-side.");
    if (data == null) {
      CratePileCollection collection = CratePileCollection.getCollection(worldObj);
      if (id == -1)
        setPileData(collection.createCratePile(), true);
      else setPileData(collection.getCratePile(id), false);
    }
    return data;
  }
  /** Sets the pile data and adds the crate to it if desired. <br>
   *  Removes the crate from the old pile data if it had one. */
  private void setPileData(CratePileData data, boolean addCrate) {
    if (this.data != null)
      this.data.removeCrate(this);
    this.data = data;
    if (data != null) {
      id = data.id;
      markForUpdate();
      if (addCrate) data.addCrate(this);
    } else id = -1;
  }
  /** Destroys all crates above, and makes sure when piles split,
   *  each pile gets their own CratePileData object. */
  private void checkPileConnections(CratePileData data) {
    int x = xCoord, y = yCoord, z = zCoord;
    // Destroy all crates above.
    TileEntityCrate crateAbove = WorldUtils.get(worldObj, x, y + 1, z, TileEntityCrate.class);
    if ((crateAbove != null) && (crateAbove.data == data)) {
      worldObj.setBlockToAir(x, y + 1, z);
      crateAbove.dropItem(new ItemStack(BetterStorageTiles.crate));
    }
    // If there's still some crates left and this is a
    // base crate, see which crates are still connected.
    if ((data.getNumCrates() > 0) && (y == data.getRegion().minY)) {
      List<HashSet<TileEntityCrate>> crateSets =
          new ArrayList<HashSet<TileEntityCrate>>();
      int checkedCrates = 0;
      neighborLoop: // Suck it :P
      for (ForgeDirection dir : sideDirections) {
        int nx = x + dir.offsetX;
        int nz = z + dir.offsetZ;
        // Continue if this neighbor block is not part of the crate pile.
        // TODO: Use data.hasCrate before?
        TileEntityCrate neighborCrate = WorldUtils.get(worldObj, nx, y, nz, TileEntityCrate.class);
        if ((neighborCrate == null) ||
            (neighborCrate.data != data)) continue;
        // See if the neighbor crate is already in a crate set,
        // in that case continue with the next neighbor block.
        for (HashSet<TileEntityCrate> set : crateSets)
          if (set.contains(neighborCrate)) continue neighborLoop;
        // Create a new set of crates and fill it with all connecting crates.
        HashSet<TileEntityCrate> set = new HashSet<TileEntityCrate>();
        set.add(neighborCrate);
        for (ForgeDirection ndir : sideDirections)
          checkConnections(nx + ndir.offsetX, y, nz + ndir.offsetZ, set);
        crateSets.add(set);
        // If we checked all crates, stop the loop.
        checkedCrates += set.size();
        if (checkedCrates == data.getNumCrates()) break;
      }
      // If there's more than one crate set, they need to split.
      if (crateSets.size() > 0) {
        // The first crate set will keep the original pile data.
        // All other sets will get new pile data objects.
        for (int i = 1; i < crateSets.size(); i++) {
          HashSet<TileEntityCrate> set = crateSets.get(i);
          CratePileData newPileData = data.collection.createCratePile();
          int numCrates = set.size();
          // Add the base crates from the set.
          for (TileEntityCrate newPileCrate : set) {
            newPileCrate.setPileData(newPileData, true);
            // Add all crates above the base crate.
            while (true) {
              newPileCrate = WorldUtils.get(worldObj, newPileCrate.xCoord, newPileCrate.yCoord + 1, newPileCrate.zCoord, TileEntityCrate.class);
              if (newPileCrate == null) break;
              newPileCrate.setPileData(newPileData, true);
              numCrates++;
            }
          }
          // Move some of the items over to the new crate pile.
          int count = numCrates * data.getOccupiedSlots() / (data.getNumCrates() + numCrates);
          for (ItemStack stack : data.getContents().getRandomStacks(count)) {
            data.removeItems(stack);
            newPileData.addItems(stack);
          }
        }
        // Trim the original map to the size it actually is.
        // This is needed because the crates may not be removed in
        // order, from outside to inside.
        data.trimMap();
      }
    }
  }
  private void checkConnections(int x, int y, int z, HashSet<TileEntityCrate> set) {
    TileEntityCrate crate = WorldUtils.get(worldObj, x, y, z, TileEntityCrate.class);
    if ((crate == null) || (data != crate.data) || set.contains(crate)) return;
    set.add(crate);
    for (ForgeDirection ndir : sideDirections)
      checkConnections(x + ndir.offsetX, y, z + ndir.offsetZ, set);
  }
 
  @Override
  public void updateEntity() {
    super.updateEntity();
    if (worldObj.isRemote || (data != null)) return;
    if (!isInvalid()) getPileData();
  }
 
  public void attemptConnect(ForgeDirection side) {
    if (worldObj.isRemote || (side == ForgeDirection.UP)) return;
    int x = xCoord + side.offsetX;
    int y = yCoord + side.offsetY;
    int z = zCoord + side.offsetZ;
    TileEntityCrate crateClicked = WorldUtils.get(worldObj, x, y, z, TileEntityCrate.class);
    if (crateClicked == null) return;
    CratePileData pileData = crateClicked.getPileData();
    if (pileData.canAdd(this))
      setPileData(pileData, true);
  }
 
  @Override
  public void invalidate() {
    super.invalidate();
    if (worldObj.isRemote) return;
    CratePileData data = getPileData();
    if (watcherRegistered)
      data.removeWatcher(this);
    setPileData(null, false);
    dropOverflowContents(data);
    checkPileConnections(data);
  }
 
  /** Drops a single item from the (destroyed) crate. */
  private void dropItem(ItemStack stack) {
    WorldUtils.dropStackFromBlock(worldObj, xCoord, yCoord, zCoord, stack);
  }
  /** Drops multiple item from the (destroyed) crate. */
  private void dropItems(List<ItemStack> stacks) {
    for (ItemStack stack : stacks)
      dropItem(stack);
  }
  /** Drops contents that don't fit into the
   *  crate pile after a crate got destroyed. */
  private void dropOverflowContents(CratePileData data) {
    int amount = -data.getFreeSlots();
    if (amount <= 0) return;
    List<ItemStack> items = data.getContents().getRandomStacks(amount);
    for (ItemStack stack : items) data.removeItems(stack);
    dropItems(items);
  }
 
  // TileEntityContainer stuff
 
  @Override
  protected int getSizeContents() { return 0; }
  @Override
  public String getName() { return Constants.containerCrate; }
 
  @Override
  public void openGui(EntityPlayer player) {
    if (!canPlayerUseContainer(player)) return;
    PlayerUtils.openGui(player, getName(), getColumns(), 2 * Math.min(data.getNumCrates(), 3),
                        getContainerTitle(), createContainer(player));
  }
 
  @Override
  public ContainerBetterStorage createContainer(EntityPlayer player) {
    return new ContainerCrate(player, new InventoryCratePlayerView(this));
  }
 
  // Comparator related
 
  private boolean watcherRegistered = false;
 
  @Override
  protected int getComparatorSignalStengthInternal() {
    if (worldObj.isRemote) return 0;
    CratePileData data = getPileData();
    return ((data.getOccupiedSlots() > 0)
        ? (1 + data.getOccupiedSlots() * 14 / data.getCapacity()) : 0);
  }
 
  @Override
  protected void markComparatorAccessed() {
    super.markComparatorAccessed();
    if (!watcherRegistered && !worldObj.isRemote) {
      getPileData().addWatcher(this);
      watcherRegistered = true;
    }
  }
 
  @Override
  protected void comparatorUpdateAndReset() {
    super.comparatorUpdateAndReset();
    if (watcherRegistered && !hasComparatorAccessed()) {
      getPileData().removeWatcher(this);
      watcherRegistered = false;
    }
  }
 
  @Override
  public void onCrateItemsModified(ItemStack stack) {
    markContentsChanged();
  }
 
  // IInventory implementation

  @Override
  public String getInventoryName() { return getName(); }
  @Override
  public int getInventoryStackLimit() { return 64; }
 
  @Override
  public int getSizeInventory() {
    if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) return 0;
    if (worldObj.isRemote) return 1;
    return getPileData().blockView.getSizeInventory();
  }
 
  @Override
  public boolean isItemValidForSlot(int slot, ItemStack stack) {
    if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) return false;
    return getPileData().blockView.isItemValidForSlot(slot, stack);
  }
 
  @Override
  public ItemStack getStackInSlot(int slot) {
    if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) return null;
    return getPileData().blockView.getStackInSlot(slot);
  }
  @Override
  public void setInventorySlotContents(int slot, ItemStack stack) {
    if (GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) {
      getPileData().blockView.setInventorySlotContents(slot, stack);
      markDirty();
    }
  }
  @Override
  public ItemStack getStackInSlotOnClosing(int slot) {
    if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) return null;
      return getPileData().blockView.getStackInSlotOnClosing(slot);
  }
  @Override
  public ItemStack decrStackSize(int slot, int amount) {
    if (!GlobalConfig.enableCrateInventoryInterfaceSetting.getValue()) return null;
    markDirty();
    return getPileData().blockView.decrStackSize(slot, amount);
  }
  @Override
  public void markDirty() {
    if (GlobalConfig.enableCrateInventoryInterfaceSetting.getValue())
      getPileData().blockView.markDirty();
  }
 
  @Override
  public boolean isUseableByPlayer(EntityPlayer player) { return false; }
  @Override
  public boolean hasCustomInventoryName() { return false; }
 
  @Override
  public void openInventory() { getPileData().blockView.openInventory(); }
  @Override
  public void closeInventory() { getPileData().blockView.closeInventory(); }
 
  // ICrateStorage implementation
 
  private static boolean isEnabled() {
    return GlobalConfig.enableCrateStorageInterfaceSetting.getValue();
  }
 
  @Override
  public Object getCrateIdentifier() { return getPileData(); }
 
  @Override
  public int getCapacity() { return (isEnabled() ? getPileData().getCapacity() : 0); }
  @Override
  public int getOccupiedSlots() { return (isEnabled() ? getPileData().getOccupiedSlots() : 0); }
  @Override
  public int getUniqueItems() { return (isEnabled() ? getPileData().getUniqueItems() : 0)}
 
  @Override
  public Iterable<ItemStack> getContents() {
    return (isEnabled() ? getPileData().getContents().getItems() : Collections.EMPTY_LIST);
  }
  @Override
  public Iterable<ItemStack> getRandomStacks() {
    return (isEnabled() ? getPileData().getContents().getRandomStacks() : Collections.EMPTY_LIST);
  }
 
  @Override
  public int getItemCount(ItemStack identifier) {
    return (isEnabled() ? getPileData().getContents().get(new ItemIdentifier(identifier)) : 0);
  }
  @Override
  public int getSpaceForItem(ItemStack identifier) {
    return (isEnabled() ? getPileData().getSpaceForItem(identifier) : 0);
  }
 
  @Override
  public ItemStack insertItems(ItemStack stack) {
    return (isEnabled() ? getPileData().addItems(stack) : stack);
  }
  @Override
  public ItemStack extractItems(ItemStack identifier, int amount) {
    return (isEnabled() ? getPileData().removeItems(new ItemIdentifier(identifier), amount) : null);
  }
 
  @Override
  public void registerCrateWatcher(ICrateWatcher watcher) { if (isEnabled()) getPileData().addWatcher(watcher); }
  @Override
  public void unregisterCrateWatcher(ICrateWatcher watcher) { if (isEnabled()) getPileData().removeWatcher(watcher); }
 
  // TileEntity synchronization
 
 
  @Override
  public Packet getDescriptionPacket() {
    NBTTagCompound compound = new NBTTagCompound();
    compound.setInteger("crateId", id);
        return new S35PacketUpdateTileEntity(xCoord, yCoord, zCoord, 0, compound);
  }
  @Override
  public void onDataPacket(NetworkManager net, S35PacketUpdateTileEntity packet) {
    id = packet.func_148857_g().getInteger("crateId");
    worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
  }
 
  // Reading from / writing to NBT
 
  @Override
  public void readFromNBT(NBTTagCompound compound) {
    super.readFromNBT(compound);
    id = compound.getInteger("crateId");
  }
  @Override
  public void writeToNBT(NBTTagCompound compound) {
    super.writeToNBT(compound);
    compound.setInteger("crateId", id);
    // TODO: This might not be the best place to save the crate data.
    getPileData().save();
  }
 
}
TOP

Related Classes of net.mcft.copy.betterstorage.tile.crate.TileEntityCrate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.