package mcjty.rftools.blocks.dimlets;
import mcjty.lib.container.InventoryHelper;
import mcjty.lib.entity.GenericEnergyReceiverTileEntity;
import mcjty.lib.network.Argument;
import mcjty.lib.network.PacketRequestIntegerFromServer;
import mcjty.lib.varia.BlockTools;
import mcjty.rftools.blocks.teleporter.TeleportDestinations;
import mcjty.rftools.blocks.teleporter.TeleporterSetup;
import mcjty.rftools.dimension.DimensionInformation;
import mcjty.rftools.dimension.DimensionStorage;
import mcjty.rftools.dimension.RfToolsDimensionManager;
import mcjty.rftools.dimension.world.WorldGenerationTools;
import mcjty.rftools.items.dimlets.*;
import mcjty.rftools.items.dimlets.types.IDimletType;
import mcjty.rftools.network.RFToolsMessages;
import mcjty.rftools.varia.Broadcaster;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
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 net.minecraftforge.common.util.ForgeDirection;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.util.Map;
public class DimensionEditorTileEntity extends GenericEnergyReceiverTileEntity implements ISidedInventory {
public static final String CMD_GETEDITING = "getEditing";
public static final String CLIENTCMD_GETEDITING = "getEditing";
private static int editPercentage = 0;
private int ticksLeft = -1;
private int ticksCost = -1;
private int rfPerTick = -1;
private InventoryHelper inventoryHelper = new InventoryHelper(this, DimensionEditorContainer.factory, 2);
public DimensionEditorTileEntity() {
super(DimletConfiguration.EDITOR_MAXENERGY, DimletConfiguration.EDITOR_RECEIVEPERTICK);
}
@Override
protected void checkStateServer() {
ItemStack injectableItemStack = validateInjectableItemStack();
if (injectableItemStack == null) {
return;
}
ItemStack dimensionItemStack = validateDimensionItemStack();
if (dimensionItemStack == null) {
return;
}
if (ticksLeft == -1) {
// We were not injecting. Start now.
if (isMatterReceiver(injectableItemStack)) {
ticksCost = DimletCosts.baseDimensionTickCost + 1000;
ticksLeft = ticksCost;
rfPerTick = DimletCosts.baseDimensionCreationCost + 200;
} else if (isTNT(injectableItemStack)) {
ticksCost = 600;
ticksLeft = ticksCost;
rfPerTick = 10;
} else {
DimletKey key = KnownDimletConfiguration.getDimletKey(injectableItemStack, worldObj);
DimletEntry dimletEntry = KnownDimletConfiguration.getEntry(key);
ticksCost = DimletCosts.baseDimensionTickCost + dimletEntry.getTickCost();
ticksLeft = ticksCost;
rfPerTick = DimletCosts.baseDimensionCreationCost + dimletEntry.getRfCreateCost();
}
} else {
int rf = getEnergyStored(ForgeDirection.DOWN);
int rfpt = rfPerTick;
rfpt = (int) (rfpt * (2.0f - getInfusedFactor()) / 2.0f);
if (rf >= rfpt) {
// Enough energy.
consumeEnergy(rfpt);
ticksLeft--;
if (ticksLeft <= 0) {
RfToolsDimensionManager dimensionManager = RfToolsDimensionManager.getDimensionManager(worldObj);
ItemStack dimensionTab = validateDimensionItemStack();
NBTTagCompound tagCompound = dimensionTab.getTagCompound();
int id = tagCompound.getInteger("id");
injectableItemStack = validateInjectableItemStack();
if (isMatterReceiver(injectableItemStack)) {
World dimWorld = dimensionManager.getWorldForDimension(id);
int y = findGoodReceiverLocation(dimWorld);
if (y == -1) {
y = dimWorld.getHeight() / 2;
}
dimWorld.setBlock(8, y, 8, TeleporterSetup.matterReceiverBlock, 0, 2);
TeleporterSetup.matterReceiverBlock.onBlockPlaced(dimWorld, 8, y, 8, 0, 0, 0, 0, 0);
TeleporterSetup.matterReceiverBlock.onBlockPlacedBy(dimWorld, 8, y, 8, null, injectableItemStack);
dimWorld.setBlockToAir(8, y + 1, 8);
dimWorld.setBlockToAir(8, y + 2, 8);
} else if (isTNT(injectableItemStack)) {
safeDeleteDimension(id, dimensionTab);
} else {
DimletKey key = KnownDimletConfiguration.getDimletKey(injectableItemStack, worldObj);
DimensionInformation information = dimensionManager.getDimensionInformation(id);
information.injectDimlet(key);
dimensionManager.save(worldObj);
}
inventoryHelper.decrStackSize(DimensionEditorContainer.SLOT_INJECTINPUT, 1);
stopInjecting();
}
}
}
markDirty();
setState();
}
private void safeDeleteDimension(int id, ItemStack dimensionTab) {
World w = DimensionManager.getWorld(id);
if (w != null) {
// Dimension is still loaded. Do nothing.
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Dimension cannot be deleted. It is still in use!", 10);
return;
}
RfToolsDimensionManager dimensionManager = RfToolsDimensionManager.getDimensionManager(worldObj);
DimensionInformation information = dimensionManager.getDimensionInformation(id);
if (information.getOwner() == null) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "You cannot delete a dimension without an owner!", 10);
return;
}
if (getOwnerUUID() == null) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "This machine has no proper owner and cannot delete dimensions!", 10);
return;
}
if (!getOwnerUUID().equals(information.getOwner())) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "This machine's owner differs from the dimensions owner!", 10);
return;
}
TeleportDestinations destinations = TeleportDestinations.getDestinations(worldObj);
destinations.removeDestinationsInDimension(id);
destinations.save(worldObj);
dimensionManager.removeDimension(id);
dimensionManager.reclaimId(id);
dimensionManager.save(worldObj);
DimensionStorage dimensionStorage = DimensionStorage.getDimensionStorage(worldObj);
dimensionStorage.removeDimension(id);
dimensionStorage.save(worldObj);
if (DimletConfiguration.dimensionFolderIsDeletedWithSafeDel) {
File rootDirectory = DimensionManager.getCurrentSaveRootDirectory();
try {
FileUtils.deleteDirectory(new File(rootDirectory.getPath() + File.separator + "DIM" + id));
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Dimension deleted and dimension folder succesfully wiped!", 10);
} catch (IOException e) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Dimension deleted but dimension folder could not be completely wiped!", 10);
}
} else {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Dimension deleted. Please remove the dimension folder from disk!", 10);
}
dimensionTab.getTagCompound().removeTag("id");
int tickCost = dimensionTab.getTagCompound().getInteger("tickCost");
dimensionTab.getTagCompound().setInteger("ticksLeft", tickCost);
}
private int findGoodReceiverLocation(World dimWorld) {
int y = WorldGenerationTools.findSuitableEmptySpot(dimWorld, 8, 8);
y++;
return y;
}
private ItemStack validateInjectableItemStack() {
ItemStack itemStack = inventoryHelper.getStackInSlot(DimensionEditorContainer.SLOT_INJECTINPUT);
if (itemStack == null || itemStack.stackSize == 0) {
stopInjecting();
return null;
}
if (isMatterReceiver(itemStack)) {
return itemStack;
}
if (isTNT(itemStack)) {
return canDeleteDimension(itemStack);
}
DimletKey key = KnownDimletConfiguration.getDimletKey(itemStack, worldObj);
DimletType type = key.getType();
IDimletType itype = type.dimletType;
if (itype.isInjectable()) {
return itemStack;
} else {
return null;
}
}
private ItemStack canDeleteDimension(ItemStack itemStack) {
if (!DimletConfiguration.playersCanDeleteDimensions) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Players cannot delete dimensions!", 10);
return null;
}
if (!DimletConfiguration.editorCanDeleteDimensions) {
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "Dimension deletion with the editor is not enabled!", 10);
return null;
}
ItemStack dimensionStack = inventoryHelper.getStackInSlot(DimensionEditorContainer.SLOT_DIMENSIONTARGET);
if (dimensionStack == null || dimensionStack.stackSize == 0) {
return null;
}
NBTTagCompound tagCompound = dimensionStack.getTagCompound();
int id = tagCompound.getInteger("id");
if (id == 0) {
return null;
}
DimensionInformation information = RfToolsDimensionManager.getDimensionManager(worldObj).getDimensionInformation(id);
if (getOwnerUUID() != null && getOwnerUUID().equals(information.getOwner())) {
return itemStack;
}
Broadcaster.broadcast(worldObj, xCoord, yCoord, zCoord, "This machine's owner differs from the dimensions owner!", 10);
return null;
}
private boolean isMatterReceiver(ItemStack itemStack) {
Block block = BlockTools.getBlock(itemStack);
if (block == TeleporterSetup.matterReceiverBlock) {
// We can inject matter receivers too.
return true;
}
return false;
}
private boolean isTNT(ItemStack itemStack) {
Block block = BlockTools.getBlock(itemStack);
if (block == Blocks.tnt) {
// We can inject TNT to destroy a dimension.
return true;
}
return false;
}
private ItemStack validateDimensionItemStack() {
ItemStack itemStack = inventoryHelper.getStackInSlot(DimensionEditorContainer.SLOT_DIMENSIONTARGET);
if (itemStack == null || itemStack.stackSize == 0) {
stopInjecting();
return null;
}
NBTTagCompound tagCompound = itemStack.getTagCompound();
int id = tagCompound.getInteger("id");
if (id == 0) {
// Not a valid dimension.
stopInjecting();
return null;
}
return itemStack;
}
private void stopInjecting() {
setState();
ticksLeft = -1;
ticksCost = -1;
rfPerTick = -1;
markDirty();
}
private void setState() {
int state = 0;
if (ticksLeft == 0) {
state = 0;
} else if (ticksLeft == -1) {
state = 1;
} else if (((ticksLeft >> 2) & 1) == 0) {
state = 2;
} else {
state = 3;
}
int metadata = worldObj.getBlockMetadata(xCoord, yCoord, zCoord);
int newmeta = BlockTools.setState(metadata, state);
if (newmeta != metadata) {
worldObj.setBlockMetadataWithNotify(xCoord, yCoord, zCoord, newmeta, 2);
}
}
@Override
public int[] getAccessibleSlotsFromSide(int side) {
return DimletResearcherContainer.factory.getAccessibleSlots();
}
@Override
public boolean canInsertItem(int index, ItemStack item, int side) {
return DimletResearcherContainer.factory.isInputSlot(index);
}
@Override
public boolean canExtractItem(int index, ItemStack item, int side) {
return DimletResearcherContainer.factory.isOutputSlot(index);
}
@Override
public int getSizeInventory() {
return inventoryHelper.getCount();
}
@Override
public ItemStack getStackInSlot(int index) {
return inventoryHelper.getStackInSlot(index);
}
@Override
public ItemStack decrStackSize(int index, int amount) {
return inventoryHelper.decrStackSize(index, amount);
}
@Override
public ItemStack getStackInSlotOnClosing(int index) {
return null;
}
@Override
public void setInventorySlotContents(int index, ItemStack stack) {
inventoryHelper.setInventorySlotContents(getInventoryStackLimit(), index, stack);
}
@Override
public String getInventoryName() {
return "Editor Inventory";
}
@Override
public boolean hasCustomInventoryName() {
return false;
}
@Override
public int getInventoryStackLimit() {
return DimletConfiguration.dimletStackSize;
}
@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) {
return true;
}
// Request the building percentage from the server. This has to be called on the client side.
public void requestBuildingPercentage() {
RFToolsMessages.INSTANCE.sendToServer(new PacketRequestIntegerFromServer(xCoord, yCoord, zCoord,
CMD_GETEDITING,
CLIENTCMD_GETEDITING));
}
@Override
public Integer executeWithResultInteger(String command, Map<String, Argument> args) {
Integer rc = super.executeWithResultInteger(command, args);
if (rc != null) {
return rc;
}
if (CMD_GETEDITING.equals(command)) {
if (ticksLeft == -1) {
return 0;
} else {
return (ticksCost - ticksLeft) * 100 / ticksCost;
}
}
return null;
}
@Override
public boolean execute(String command, Integer result) {
boolean rc = super.execute(command, result);
if (rc) {
return true;
}
if (CLIENTCMD_GETEDITING.equals(command)) {
editPercentage = result;
return true;
}
return false;
}
public static int getEditPercentage() {
return editPercentage;
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
readBufferFromNBT(tagCompound);
ticksLeft = tagCompound.getInteger("ticksLeft");
ticksCost = tagCompound.getInteger("ticksCost");
rfPerTick = tagCompound.getInteger("rfPerTick");
}
private void readBufferFromNBT(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, ItemStack.loadItemStackFromNBT(nbtTagCompound));
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
writeBufferToNBT(tagCompound);
tagCompound.setInteger("ticksLeft", ticksLeft);
tagCompound.setInteger("ticksCost", ticksCost);
tagCompound.setInteger("rfPerTick", rfPerTick);
}
private void writeBufferToNBT(NBTTagCompound tagCompound) {
NBTTagList bufferTagList = new NBTTagList();
for (int i = 0 ; 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);
}
}