package mcjty.rftools.blocks.storage;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.Side;
import mcjty.lib.container.InventoryHelper;
import mcjty.lib.entity.GenericTileEntity;
import mcjty.lib.network.Argument;
import mcjty.rftools.ClientInfo;
import mcjty.rftools.items.storage.StorageFilterCache;
import mcjty.rftools.items.storage.StorageFilterItem;
import mcjty.rftools.items.storage.StorageModuleItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.ISidedInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.util.Constants;
import java.util.Map;
public class ModularStorageTileEntity extends GenericTileEntity implements ISidedInventory {
public static final String CMD_SETTINGS = "settings";
public static final String CMD_COMPACT = "compact";
public static final String CMD_CYCLE = "cycle";
private int[] accessible = null;
private int maxSize = 0;
private StorageFilterCache filterCache = null;
private InventoryHelper inventoryHelper = new InventoryHelper(this, ModularStorageContainer.factory, ModularStorageContainer.SLOT_STORAGE + ModularStorageContainer.MAXSIZE_STORAGE);
private String sortMode = "";
private String viewMode = "";
private boolean groupMode = false;
private String filter = "";
private int numStacks = -1; // -1 means no storage cell.
private int remoteId = 0;
private int prevLevel = -3; // -3 means to check, -2 means invalid
private int timer = 10;
@Override
protected void checkStateServer() {
timer--;
if (timer > 0) {
return;
}
timer = 10;
if (isRemote()) {
// Only if we have a remote storage module do we have to do anything.
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
int si = -1;
if (storageTileEntity != null) {
si = storageTileEntity.findRemoteIndex(remoteId);
}
if (si == -1) {
if (prevLevel != -2) {
prevLevel = -2;
numStacks = -1;
setMaxSize(0);
}
return;
}
numStacks = storageTileEntity.getCount(si);
int newMaxSize = storageTileEntity.getMaxStacks(si);
if (newMaxSize != maxSize) {
setMaxSize(newMaxSize);
}
int level = getRenderLevel();
if (level != prevLevel) {
prevLevel = level;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
}
@Override
public int[] getAccessibleSlotsFromSide(int side) {
if (accessible == null) {
accessible = new int[maxSize];
for (int i = 0 ; i < maxSize ; i++) {
accessible[i] = ModularStorageContainer.SLOT_STORAGE + i;
}
}
return accessible;
}
public boolean isGroupMode() {
return groupMode;
}
public void setGroupMode(boolean groupMode) {
this.groupMode = groupMode;
markDirty();
}
public String getSortMode() {
return sortMode;
}
public void setSortMode(String sortMode) {
this.sortMode = sortMode;
markDirty();
}
public String getFilter() {
return filter;
}
public void setFilter(String filter) {
this.filter = filter;
markDirty();
}
public String getViewMode() {
return viewMode;
}
public void setViewMode(String viewMode) {
this.viewMode = viewMode;
markDirty();
}
public int getMaxSize() {
return maxSize;
}
@Override
public boolean canInsertItem(int index, ItemStack item, int side) {
return index >= ModularStorageContainer.SLOT_STORAGE && isItemValidForSlot(index, item);
}
@Override
public boolean canExtractItem(int index, ItemStack item, int side) {
return index >= ModularStorageContainer.SLOT_STORAGE && isItemValidForSlot(index, item);
}
@Override
public int getSizeInventory() {
return ModularStorageContainer.SLOT_STORAGE + maxSize;
}
private boolean containsItem(int index) {
if (isStorageAvailableRemotely(index)) {
index -= ModularStorageContainer.SLOT_STORAGE;
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return false;
}
ItemStack[] slots = storageTileEntity.findStacksForId(remoteId);
if (slots == null || index >= slots.length) {
return false;
}
return slots[index] != null;
} else {
return inventoryHelper.containsItem(index);
}
}
// On server, and if we have a remote storage module and if we're accessing a remote slot we check the remote storage.
private boolean isStorageAvailableRemotely(int index) {
return isServer() && isRemote() && index >= ModularStorageContainer.SLOT_STORAGE;
}
private boolean isRemote() {
return remoteId != 0;
}
public int getRemoteId() {
return remoteId;
}
@Override
public ItemStack getStackInSlot(int index) {
if (index >= getSizeInventory()) {
return null;
}
if (isStorageAvailableRemotely(index)) {
index -= ModularStorageContainer.SLOT_STORAGE;
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return null;
}
ItemStack[] slots = storageTileEntity.findStacksForId(remoteId);
if (slots == null || index >= slots.length) {
return null;
}
return slots[index];
}
return inventoryHelper.getStackInSlot(index);
}
private void handleNewAmount(boolean s1, int index) {
if (index < ModularStorageContainer.SLOT_STORAGE) {
return;
}
boolean s2 = containsItem(index);
if (s1 == s2) {
return;
}
int rlold = getRenderLevel();
if (s1) {
numStacks--;
} else {
numStacks++;
}
StorageModuleItem.updateStackSize(getStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE), numStacks);
int rlnew = getRenderLevel();
if (rlold != rlnew) {
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
public int getRenderLevel() {
if (numStacks == -1 || maxSize == 0) {
return -1;
}
return (numStacks+6) * 7 / maxSize;
}
public int getNumStacks() {
return numStacks;
}
private ItemStack decrStackSizeHelper(int index, int amount) {
if (isStorageAvailableRemotely(index)) {
index -= ModularStorageContainer.SLOT_STORAGE;
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return null;
}
int si = storageTileEntity.findRemoteIndex(remoteId);
if (si == -1) {
return null;
}
return storageTileEntity.decrStackSizeRemote(si, index, amount);
} else {
return inventoryHelper.decrStackSize(index, amount);
}
}
@Override
public ItemStack decrStackSize(int index, int amount) {
boolean s1 = containsItem(index);
ItemStack itemStack = decrStackSizeHelper(index, amount);
handleNewAmount(s1, index);
if (index == ModularStorageContainer.SLOT_STORAGE_MODULE) {
copyFromModule(inventoryHelper.getStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE));
}
return itemStack;
}
@Override
public ItemStack getStackInSlotOnClosing(int index) {
return null;
}
private void setInventorySlotContentsHelper(int limit, int index, ItemStack stack) {
if (isStorageAvailableRemotely(index)) {
index -= ModularStorageContainer.SLOT_STORAGE;
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return;
}
int si = storageTileEntity.findRemoteIndex(remoteId);
if (si == -1) {
return;
}
storageTileEntity.updateRemoteSlot(si, limit, index, stack);
} else {
inventoryHelper.setInventorySlotContents(getInventoryStackLimit(), index, stack);
}
}
public void syncToClient() {
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
public void setInventorySlotContents(int index, ItemStack stack) {
if (index == ModularStorageContainer.SLOT_STORAGE_MODULE) {
} else if (index == ModularStorageContainer.SLOT_TYPE_MODULE) {
// Make sure front side is updated.
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
} else if (index == ModularStorageContainer.SLOT_FILTER_MODULE) {
filterCache = null;
}
boolean s1 = containsItem(index);
setInventorySlotContentsHelper(getInventoryStackLimit(), index, stack);
if (index == ModularStorageContainer.SLOT_STORAGE_MODULE) {
if (isServer()) {
copyFromModule(stack);
}
}
handleNewAmount(s1, index);
}
@Override
public String getInventoryName() {
return "Modular Storage Inventory";
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public int getInventoryStackLimit() {
return 64;
}
@Override
public boolean isUseableByPlayer(EntityPlayer player) {
return canPlayerAccess(player);
}
@Override
public void openInventory() {
}
@Override
public void closeInventory() {
}
@Override
public boolean isItemValidForSlot(int index, ItemStack stack) {
if (index >= getSizeInventory()) {
return false;
}
if (index < ModularStorageContainer.SLOT_STORAGE) {
return true;
}
if (isStorageAvailableRemotely(index)) {
index -= ModularStorageContainer.SLOT_STORAGE;
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return false;
}
ItemStack[] stacks = storageTileEntity.findStacksForId(remoteId);
if (stacks == null || index >= stacks.length) {
return false;
}
}
if (inventoryHelper.containsItem(ModularStorageContainer.SLOT_FILTER_MODULE)) {
getFilterCache();
if (filterCache != null) {
return filterCache.match(stack);
}
}
return true;
}
private void getFilterCache() {
if (filterCache == null) {
filterCache = StorageFilterItem.getCache(inventoryHelper.getStackInSlot(ModularStorageContainer.SLOT_FILTER_MODULE));
}
}
public void copyToModule() {
ItemStack stack = inventoryHelper.getStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE);
if (stack == null) {
// Should be impossible.
return;
}
if (stack.getItemDamage() == StorageModuleItem.STORAGE_REMOTE) {
remoteId = 0;
return;
}
NBTTagCompound tagCompound = stack.getTagCompound();
if (tagCompound == null) {
tagCompound = new NBTTagCompound();
stack.setTagCompound(tagCompound);
}
int cnt = writeBufferToItemNBT(tagCompound);
tagCompound.setInteger("count", cnt);
}
public void copyFromModule(ItemStack stack) {
for (int i = ModularStorageContainer.SLOT_STORAGE ; i < inventoryHelper.getCount() ; i++) {
inventoryHelper.setInventorySlotContents(0, i, null);
}
if (stack == null) {
setMaxSize(0);
numStacks = -1;
return;
}
remoteId = 0;
if (stack.getItemDamage() == StorageModuleItem.STORAGE_REMOTE) {
NBTTagCompound tagCompound = stack.getTagCompound();
if (tagCompound == null || !tagCompound.hasKey("id")) {
setMaxSize(0);
numStacks = -1;
return;
}
remoteId = tagCompound.getInteger("id");
RemoteStorageTileEntity remoteStorageTileEntity = getRemoteStorage(remoteId);
if (remoteStorageTileEntity == null) {
setMaxSize(0);
numStacks = -1;
return;
}
ItemStack storageStack = remoteStorageTileEntity.findStorageWithId(remoteId);
if (storageStack == null) {
setMaxSize(0);
numStacks = -1;
return;
}
setMaxSize(StorageModuleItem.MAXSIZE[storageStack.getItemDamage()]);
} else {
setMaxSize(StorageModuleItem.MAXSIZE[stack.getItemDamage()]);
NBTTagCompound tagCompound = stack.getTagCompound();
if (tagCompound != null) {
readBufferFromItemNBT(tagCompound);
}
}
updateStackCount();
}
private RemoteStorageTileEntity getRemoteStorage(int id) {
World world = getWorld();
return RemoteStorageIdRegistry.getRemoteStorage(world, id);
}
private void updateStackCount() {
numStacks = 0;
if (isServer() && isRemote()) {
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return;
}
int si = storageTileEntity.findRemoteIndex(remoteId);
if (si == -1) {
return;
}
ItemStack[] stacks = storageTileEntity.getRemoteStacks(si);
for (int i = 0 ; i < Math.min(maxSize, stacks.length) ; i++) {
if (stacks[i] != null) {
numStacks++;
}
}
storageTileEntity.updateCount(si, numStacks);
} else {
for (int i = ModularStorageContainer.SLOT_STORAGE; i < ModularStorageContainer.SLOT_STORAGE + maxSize; i++) {
if (inventoryHelper.containsItem(i)) {
numStacks++;
}
}
}
StorageModuleItem.updateStackSize(getStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE), numStacks);
}
private boolean isServer() {
if (worldObj != null) {
return !worldObj.isRemote;
} else {
return FMLCommonHandler.instance().getEffectiveSide() == Side.SERVER;
}
}
private World getWorld() {
World world = worldObj;
if (world == null) {
if (FMLCommonHandler.instance().getEffectiveSide() == Side.CLIENT) {
world = ClientInfo.getWorld();
} else {
world = DimensionManager.getWorld(0);
}
}
return world;
}
private void setMaxSize(int ms) {
maxSize = ms;
inventoryHelper.setNewCount(ModularStorageContainer.SLOT_STORAGE + maxSize);
accessible = null;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
numStacks = tagCompound.getInteger("numStacks");
maxSize = tagCompound.getInteger("maxSize");
// System.out.println((isServer() ? "SERVER" : "CLIENT") + ": loc=" + xCoord + "," + yCoord + "," + zCoord + ", #stacks=" + numStacks + ", max=" + maxSize);
remoteId = tagCompound.getInteger("remoteId");
sortMode = tagCompound.getString("sortMode");
viewMode = tagCompound.getString("viewMode");
groupMode = tagCompound.getBoolean("groupMode");
filter = tagCompound.getString("filter");
inventoryHelper.setNewCount(ModularStorageContainer.SLOT_STORAGE + maxSize);
accessible = null;
readBufferFromNBT(tagCompound);
if (isServer()) {
updateStackCount();
}
}
private void readBufferFromItemNBT(NBTTagCompound tagCompound) {
NBTTagList bufferTagList = tagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND);
for (int i = 0 ; i < bufferTagList.tagCount() ; i++) {
NBTTagCompound nbtTagCompound = bufferTagList.getCompoundTagAt(i);
inventoryHelper.setStackInSlot(i+ModularStorageContainer.SLOT_STORAGE, ItemStack.loadItemStackFromNBT(nbtTagCompound));
}
}
private void readBufferFromNBT(NBTTagCompound tagCompound) {
NBTTagList bufferTagList = tagCompound.getTagList("Items", Constants.NBT.TAG_COMPOUND);
if (tagCompound.hasKey("SlotStorage")) {
// This is a new TE with separate NBT tags for the three special slots.
for (int i = 0 ; i < bufferTagList.tagCount() ; i++) {
NBTTagCompound nbtTagCompound = bufferTagList.getCompoundTagAt(i);
inventoryHelper.setStackInSlot(i+ModularStorageContainer.SLOT_STORAGE, ItemStack.loadItemStackFromNBT(nbtTagCompound));
}
inventoryHelper.setStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE, ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("SlotStorage")));
inventoryHelper.setStackInSlot(ModularStorageContainer.SLOT_TYPE_MODULE, ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("SlotType")));
inventoryHelper.setStackInSlot(ModularStorageContainer.SLOT_FILTER_MODULE, ItemStack.loadItemStackFromNBT(tagCompound.getCompoundTag("SlotFilter")));
} else {
// This is an old TE so we have to convert this to the new format.
int index = 0;
for (int i = 0 ; i < bufferTagList.tagCount() ; i++) {
NBTTagCompound nbtTagCompound = bufferTagList.getCompoundTagAt(i);
inventoryHelper.setStackInSlot(index, ItemStack.loadItemStackFromNBT(nbtTagCompound));
index++;
if (index == ModularStorageContainer.SLOT_FILTER_MODULE) {
index++; // Skip this slot since this TE will not have that.
}
}
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
writeBufferToNBT(tagCompound);
writeSlot(tagCompound, ModularStorageContainer.SLOT_STORAGE_MODULE, "SlotStorage");
writeSlot(tagCompound, ModularStorageContainer.SLOT_TYPE_MODULE, "SlotType");
writeSlot(tagCompound, ModularStorageContainer.SLOT_FILTER_MODULE, "SlotFilter");
tagCompound.setInteger("numStacks", numStacks);
tagCompound.setInteger("maxSize", maxSize);
tagCompound.setInteger("remoteId", remoteId);
tagCompound.setString("sortMode", sortMode);
tagCompound.setString("viewMode", viewMode);
tagCompound.setBoolean("groupMode", groupMode);
tagCompound.setString("filter", filter);
}
private void writeSlot(NBTTagCompound tagCompound, int index, String name) {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
ItemStack stack = inventoryHelper.getStackInSlot(index);
if (stack != null) {
stack.writeToNBT(nbtTagCompound);
}
tagCompound.setTag(name, nbtTagCompound);
}
private void writeBufferToNBT(NBTTagCompound tagCompound) {
// If sendToClient is true we have to send dummy information to the client
// so that it can remotely open gui's.
boolean sendToClient = isServer() && isRemote();
NBTTagList bufferTagList = new NBTTagList();
if (sendToClient) {
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity != null) {
ItemStack[] slots = storageTileEntity.findStacksForId(remoteId);
if (slots != null) {
for (ItemStack stack : slots) {
NBTTagCompound nbtTagCompound = new NBTTagCompound();
if (stack != null) {
stack.writeToNBT(nbtTagCompound);
}
bufferTagList.appendTag(nbtTagCompound);
}
}
}
} else {
for (int i = ModularStorageContainer.SLOT_STORAGE; i < inventoryHelper.getCount(); i++) {
ItemStack stack = inventoryHelper.getStackInSlot(i);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
if (stack != null) {
stack.writeToNBT(nbtTagCompound);
}
bufferTagList.appendTag(nbtTagCompound);
}
}
tagCompound.setTag("Items", bufferTagList);
}
private int writeBufferToItemNBT(NBTTagCompound tagCompound) {
int cnt = 0;
NBTTagList bufferTagList = new NBTTagList();
for (int i = ModularStorageContainer.SLOT_STORAGE; i < inventoryHelper.getCount(); i++) {
ItemStack stack = inventoryHelper.getStackInSlot(i);
NBTTagCompound nbtTagCompound = new NBTTagCompound();
if (stack != null) {
stack.writeToNBT(nbtTagCompound);
if (stack.stackSize > 0) {
cnt++;
}
}
bufferTagList.appendTag(nbtTagCompound);
}
tagCompound.setTag("Items", bufferTagList);
return cnt;
}
@Override
public boolean execute(EntityPlayerMP playerMP, String command, Map<String, Argument> args) {
boolean rc = super.execute(playerMP, command, args);
if (rc) {
return true;
}
if (CMD_SETTINGS.equals(command)) {
setFilter(args.get("filter").getString());
setViewMode(args.get("viewMode").getString());
setSortMode(args.get("sortMode").getString());
setGroupMode(args.get("groupMode").getBoolean());
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
return true;
} else if (CMD_COMPACT.equals(command)) {
compact();
return true;
} else if (CMD_CYCLE.equals(command)) {
cycle();
return true;
}
return false;
}
private void cycle() {
if (isRemote()) {
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return;
}
remoteId = storageTileEntity.cycle(remoteId);
getStackInSlot(ModularStorageContainer.SLOT_STORAGE_MODULE).getTagCompound().setInteger("id", remoteId);
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}
private void compact() {
if (isRemote()) {
RemoteStorageTileEntity storageTileEntity = getRemoteStorage(remoteId);
if (storageTileEntity == null) {
return;
}
storageTileEntity.compact(remoteId);
} else {
InventoryHelper.compactStacks(inventoryHelper, ModularStorageContainer.SLOT_STORAGE, maxSize);
}
updateStackCount();
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
}