package me.dmillerw.remoteio.tile;

import me.dmillerw.remoteio.block.BlockRemoteInterface;
import me.dmillerw.remoteio.block.ModBlocks;
import me.dmillerw.remoteio.core.frequency.DeviceRegistry;
import me.dmillerw.remoteio.core.frequency.IFrequencyProvider;
import me.dmillerw.remoteio.lib.property.RenderState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

/**
 * Created by dmillerw
 */
public class TileRemoteInterface extends TileCore implements ITickable, IFrequencyProvider {

    private BlockPos remotePosition;
    private int frequency = 0;

    @Override
    public void writeToDisk(NBTTagCompound compound) {
        compound.setInteger("_frequency", frequency);
    }

    @Override
    public void readFromDisk(NBTTagCompound compound) {
        frequency = compound.getInteger("_frequency");
    }

    @Override
    public void writeDescription(NBTTagCompound compound) {
        if (remotePosition != null)
            compound.setLong("_remote_position", remotePosition.toLong());

        compound.setInteger("_frequency", frequency);
    }

    @Override
    public void readDescription(NBTTagCompound compound) {
        if (compound.hasKey("_remote_position"))
            remotePosition = BlockPos.fromLong(compound.getLong("_remote_position"));
        else
            remotePosition = null;

        frequency = compound.getInteger("_frequency");
    }

    @Override
    public void onLoad() {
        if (!worldObj.isRemote) {
            remotePosition = DeviceRegistry.getWatchedBlock(worldObj.provider.getDimension(), getFrequency());
        }
    }

    @Override
    public void update() {
        if (!worldObj.isRemote) {
            BlockPos pos = DeviceRegistry.getWatchedBlock(worldObj.provider.getDimension(), getFrequency());
            if (pos == null) {
                if (remotePosition != null) {
                    this.remotePosition = null;

                    notifyNeighbors();
                    markDirtyAndNotify();
                }
            } else if (!pos.equals(remotePosition)) {
                this.remotePosition = pos;

                notifyNeighbors();
                markDirtyAndNotify();
            }
        }
    }

    @Override
    public boolean hasFastRenderer() {
        TileEntity remote = getRemoteTile();
        if (remote != null)
            return remote.hasFastRenderer();
        else
            return false;
    }

    @Override
    public int getFrequency() {
        return frequency;
    }

    @Override
    public void setFrequency(int frequency) {
        this.frequency = frequency;

        notifyNeighbors();
        markDirtyAndNotify();
    }

    @Override
    public BlockPos getPosition() {
        return pos;
    }

    public BlockPos getRemotePosition() {
        return remotePosition;
    }

    public IBlockState getRemoteState() {
        if (remotePosition != null) {
            IBlockState state = worldObj.getBlockState(remotePosition);
            if (state.getBlock().isAir(state, worldObj, remotePosition))
                return null;

            if (state.getBlock() == ModBlocks.analyzer || state.getBlock() == ModBlocks.remote_interface)
                return null;

            return state;
        }
        else
            return null;
    }

    @SideOnly(Side.CLIENT)
    public IExtendedBlockState getExtendedBlockState(IBlockState state) {
        IBlockState connected = getRemoteState();
        if (connected == null) {
            return ((IExtendedBlockState) state)
                    .withProperty(BlockRemoteInterface.RENDER_STATE, RenderState.BLANK);
        }

        TileEntity tile = worldObj.getTileEntity(getRemotePosition());
        boolean tileRender = false;
        if (tile != null) {
            tileRender = TileEntityRendererDispatcher.instance.getSpecialRenderer(tile) != null;
        }

        RenderState renderState = new RenderState();
        renderState.blockState = connected.getActualState(worldObj, getRemotePosition());
        renderState.extendedBlockState = connected.getBlock().getExtendedState(renderState.blockState, worldObj, getRemotePosition());
        renderState.camouflage = true;
        renderState.tileRender = tileRender;

        return ((IExtendedBlockState) state)
                .withProperty(BlockRemoteInterface.RENDER_STATE, renderState);
    }

    /* START CAPABILITY HANDLING */

    private TileEntity getRemoteTile() {
        if (remotePosition != null)
            return worldObj.getTileEntity(remotePosition);
        else
            return null;
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
        TileEntity remoteTile = getRemoteTile();
        return remoteTile != null && remoteTile.hasCapability(capability, facing);
    }

    @Override
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        return getRemoteTile().getCapability(capability, facing);
    }
}

@@ -3769,24 +3769,166 @@
 ull;%0A    %7D%0A%0A
+    private TileEntity getRemoteTile() %7B%0A        return getRemoteState() == null ? null : worldObj.getTileEntity(getRemotePosition());%0A    %7D%0A%0A
     @SideOnl
@@ -5026,189 +5026,8 @@
 */%0A%0A
-    private TileEntity getRemoteTile() %7B%0A        if (remotePosition != null)%0A            return worldObj.getTileEntity(remotePosition);%0A        else%0A            return null;%0A    %7D%0A%0A
     

Fix stack overflow