appeng.fmp.CableBusPart.java Source code

Java tutorial

Introduction

Here is the source code for appeng.fmp.CableBusPart.java

Source

/*
 * This file is part of Applied Energistics 2.
 * Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved.
 *
 * Applied Energistics 2 is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Applied Energistics 2 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Applied Energistics 2.  If not, see <http://www.gnu.org/licenses/lgpl>.
 */

package appeng.fmp;

import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.Vec3;
import net.minecraftforge.common.util.ForgeDirection;

import codechicken.lib.data.MCDataInput;
import codechicken.lib.data.MCDataOutput;
import codechicken.lib.raytracer.IndexedCuboid6;
import codechicken.lib.vec.Cuboid6;
import codechicken.lib.vec.Vector3;
import codechicken.multipart.IMaskedRedstonePart;
import codechicken.multipart.JCuboidPart;
import codechicken.multipart.JNormalOcclusion;
import codechicken.multipart.NormalOcclusionTest;
import codechicken.multipart.NormallyOccludedPart;
import codechicken.multipart.TMultiPart;
import codechicken.multipart.scalatraits.TIInventoryTile;

import appeng.api.implementations.parts.IPartCable;
import appeng.api.networking.IGridNode;
import appeng.api.parts.IFacadeContainer;
import appeng.api.parts.IFacadePart;
import appeng.api.parts.IPart;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartItem;
import appeng.api.parts.LayerFlags;
import appeng.api.parts.PartItemStack;
import appeng.api.parts.SelectedPart;
import appeng.api.util.AECableType;
import appeng.api.util.AEColor;
import appeng.api.util.DimensionalCoord;
import appeng.client.render.BusRenderHelper;
import appeng.client.render.BusRenderer;
import appeng.core.AEConfig;
import appeng.core.AELog;
import appeng.core.features.AEFeature;
import appeng.helpers.AEMultiTile;
import appeng.parts.BusCollisionHelper;
import appeng.parts.CableBusContainer;
import appeng.parts.PartPlacement;
import appeng.tile.networking.TileCableBus;
import appeng.util.Platform;

/**
 * Implementing these might help improve visuals for hollow covers
 *
 * TSlottedPart,ISidedHollowConnect
 */
public class CableBusPart extends JCuboidPart implements JNormalOcclusion, IMaskedRedstonePart, AEMultiTile {
    private static final ThreadLocal<Boolean> DISABLE_FACADE_OCCLUSION = new ThreadLocal<Boolean>();
    private static final double SHORTER = 6.0 / 16.0;
    private static final double LONGER = 10.0 / 16.0;
    private static final double MIN_DIRECTION = 0;
    private static final double MAX_DIRECTION = 1.0;
    private static final Cuboid6[] SIDE_TESTS = {

            // DOWN(0, -1, 0),
            new Cuboid6(SHORTER, MIN_DIRECTION, SHORTER, LONGER, SHORTER, LONGER),

            // UP(0, 1, 0),
            new Cuboid6(SHORTER, LONGER, SHORTER, LONGER, MAX_DIRECTION, LONGER),

            // NORTH(0, 0, -1),
            new Cuboid6(SHORTER, SHORTER, MIN_DIRECTION, LONGER, LONGER, SHORTER),

            // SOUTH(0, 0, 1),
            new Cuboid6(SHORTER, SHORTER, LONGER, LONGER, LONGER, MAX_DIRECTION),

            // WEST(-1, 0, 0),
            new Cuboid6(MIN_DIRECTION, SHORTER, SHORTER, SHORTER, LONGER, LONGER),

            // EAST(1, 0, 0),
            new Cuboid6(LONGER, SHORTER, SHORTER, MAX_DIRECTION, LONGER, LONGER), };

    /**
     * Mask for {@link IMaskedRedstonePart#getConnectionMask(int)}
     *
     * the bits are derived from the rotation, where 4 is the center
     */
    private static final int CONNECTION_MASK = 0x000010;
    private CableBusContainer cb = new CableBusContainer(this);
    private boolean canUpdate = false;

    @Override
    public boolean recolourBlock(final ForgeDirection side, final AEColor colour, final EntityPlayer who) {
        return this.getCableBus().recolourBlock(side, colour, who);
    }

    @Override
    public Cuboid6 getBounds() {
        AxisAlignedBB b = null;

        for (final AxisAlignedBB bx : this.getCableBus().getSelectedBoundingBoxesFromPool(false, true, null,
                true)) {
            if (b == null) {
                b = bx;
            } else {
                final double minX = Math.min(b.minX, bx.minX);
                final double minY = Math.min(b.minY, bx.minY);
                final double minZ = Math.min(b.minZ, bx.minZ);
                final double maxX = Math.max(b.maxX, bx.maxX);
                final double maxY = Math.max(b.maxY, bx.maxY);
                final double maxZ = Math.max(b.maxZ, bx.maxZ);
                b.setBounds(minX, minY, minZ, maxX, maxY, maxZ);
            }
        }

        if (b == null) {
            return new Cuboid6(0.0, 0.0, 0.0, 1.0, 1.0, 1.0);
        }

        return new Cuboid6(b.minX, b.minY, b.minZ, b.maxX, b.maxY, b.maxZ);
    }

    @Override
    public String getType() {
        return PartRegistry.CableBusPart.getName();
    }

    @Override
    public int getLightValue() {
        return this.getCableBus().getLightValue();
    }

    @Override
    public void onWorldJoin() {
        this.canUpdate = true;
        this.getCableBus().updateConnections();
        this.getCableBus().addToWorld();
    }

    @Override
    public boolean occlusionTest(final TMultiPart part) {
        return NormalOcclusionTest.apply(this, part);
    }

    @Override
    public boolean renderStatic(final Vector3 pos, final int pass) {
        if (pass == 0 || (pass == 1 && AEConfig.instance.isFeatureEnabled(AEFeature.AlphaPass))) {
            BusRenderHelper.INSTANCE.setPass(pass);
            BusRenderer.INSTANCE.getRenderer().renderAllFaces = true;
            BusRenderer.INSTANCE.getRenderer().blockAccess = this.world();
            BusRenderer.INSTANCE.getRenderer().overrideBlockTexture = null;
            this.getCableBus().renderStatic(pos.x, pos.y, pos.z);
            return BusRenderHelper.INSTANCE.getItemsRendered() > 0;
        }
        return false;
    }

    @Override
    public void renderDynamic(final Vector3 pos, final float frame, final int pass) {
        if (pass == 0 || (pass == 1 && AEConfig.instance.isFeatureEnabled(AEFeature.AlphaPass))) {
            BusRenderHelper.INSTANCE.setPass(pass);
            this.getCableBus().renderDynamic(pos.x, pos.y, pos.z);
        }
    }

    @Override
    public void onPartChanged(final TMultiPart part) {
        this.getCableBus().updateConnections();
    }

    @Override
    public void onEntityCollision(final Entity entity) {
        this.getCableBus().onEntityCollision(entity);
    }

    @Override
    public boolean activate(final EntityPlayer player, final MovingObjectPosition hit, final ItemStack item) {
        return this.getCableBus().activate(player, hit.hitVec.addVector(-hit.blockX, -hit.blockY, -hit.blockZ));
    }

    @Override
    public void load(final NBTTagCompound tag) {
        this.getCableBus().readFromNBT(tag);
    }

    @Override
    public void onWorldSeparate() {
        this.canUpdate = false;
        this.getCableBus().removeFromWorld();
    }

    @Override
    public void save(final NBTTagCompound tag) {
        this.getCableBus().writeToNBT(tag);
    }

    @Override
    public void writeDesc(final MCDataOutput packet) {
        final ByteBuf stream = Unpooled.buffer();

        try {
            this.getCableBus().writeToStream(stream);
            packet.writeInt(stream.readableBytes());
            stream.capacity(stream.readableBytes());
            packet.writeByteArray(stream.array());
        } catch (final IOException e) {
            AELog.error(e);
        }
    }

    @Override
    public ItemStack pickItem(final MovingObjectPosition hit) {
        final Vec3 v3 = hit.hitVec.addVector(-hit.blockX, -hit.blockY, -hit.blockZ);
        final SelectedPart sp = this.getCableBus().selectPart(v3);
        if (sp != null) {
            if (sp.part != null) {
                return sp.part.getItemStack(PartItemStack.Break);
            }
            if (sp.facade != null) {
                return sp.facade.getItemStack();
            }
        }
        return null;
    }

    @Override
    public Iterable<ItemStack> getDrops() {
        return this.getCableBus().getDrops(new ArrayList());
    }

    @Override
    public void onNeighborChanged() {
        this.getCableBus().onNeighborChanged();
    }

    @Override
    public boolean doesTick() {
        return false;
    }

    @Override
    public void invalidateConvertedTile() {
        this.getCableBus().setHost(this);
    }

    @Override
    public void readDesc(final MCDataInput packet) {
        final int len = packet.readInt();
        final byte[] data = packet.readByteArray(len);

        try {
            if (len > 0) {
                final ByteBuf byteBuffer = Unpooled.wrappedBuffer(data);
                this.getCableBus().readFromStream(byteBuffer);
            }
        } catch (final IOException e) {
            AELog.error(e);
        }
    }

    @Override
    public boolean canConnectRedstone(final int side) {
        return this.getCableBus().canConnectRedstone(EnumSet.of(ForgeDirection.getOrientation(side)));
    }

    @Override
    public int weakPowerLevel(final int side) {
        return this.getCableBus().isProvidingWeakPower(ForgeDirection.getOrientation(side));
    }

    @Override
    public int strongPowerLevel(final int side) {
        return this.getCableBus().isProvidingStrongPower(ForgeDirection.getOrientation(side));
    }

    public void convertFromTile(final TileEntity blockTileEntity) {
        final TileCableBus tcb = (TileCableBus) blockTileEntity;
        this.setCableBus(tcb.getCableBus());
    }

    @Override
    public Iterable<Cuboid6> getOcclusionBoxes() {
        final LinkedList<Cuboid6> l = new LinkedList<Cuboid6>();
        for (final AxisAlignedBB b : this.getCableBus().getSelectedBoundingBoxesFromPool(true,
                DISABLE_FACADE_OCCLUSION.get() == null, null, true)) {
            l.add(new Cuboid6(b.minX, b.minY, b.minZ, b.maxX, b.maxY, b.maxZ));
        }
        return l;
    }

    @Override
    public IGridNode getGridNode(final ForgeDirection dir) {
        return this.getCableBus().getGridNode(dir);
    }

    @Override
    public AECableType getCableConnectionType(final ForgeDirection dir) {
        return this.getCableBus().getCableConnectionType(dir);
    }

    @Override
    public void securityBreak() {
        this.getCableBus().securityBreak();
    }

    // @Override
    public int getHollowSize(final int side) {
        final IPartCable cable = (IPartCable) this.getPart(ForgeDirection.UNKNOWN);

        final ForgeDirection dir = ForgeDirection.getOrientation(side);
        if (cable != null && cable.isConnected(dir)) {
            final List<AxisAlignedBB> boxes = new ArrayList<AxisAlignedBB>();

            final BusCollisionHelper bch = new BusCollisionHelper(boxes, ForgeDirection.EAST, ForgeDirection.UP,
                    ForgeDirection.SOUTH, null, true);

            for (final ForgeDirection whichSide : ForgeDirection.values()) {
                final IPart fPart = this.getPart(whichSide);

                if (fPart != null) {
                    fPart.getBoxes(bch);
                }
            }

            AxisAlignedBB b = null;
            final AxisAlignedBB pb = Platform.getPrimaryBox(dir, 2);

            for (final AxisAlignedBB bb : boxes) {
                if (bb.intersectsWith(pb)) {
                    if (b == null) {
                        b = bb;
                    } else {
                        b.maxX = Math.max(b.maxX, bb.maxX);
                        b.maxY = Math.max(b.maxY, bb.maxY);
                        b.maxZ = Math.max(b.maxZ, bb.maxZ);
                        b.minX = Math.min(b.minX, bb.minX);
                        b.minY = Math.min(b.minY, bb.minY);
                        b.minZ = Math.min(b.minZ, bb.minZ);
                    }
                }
            }

            if (b == null) {
                return 0;
            }

            switch (dir) {
            case WEST:
            case EAST:
                return this.getSize(b.minZ, b.maxZ, b.minY, b.maxY);
            case DOWN:
            case NORTH:
                return this.getSize(b.minX, b.maxX, b.minZ, b.maxZ);
            case SOUTH:
            case UP:
                return this.getSize(b.minX, b.maxX, b.minY, b.maxY);
            default:
            }
        }

        return 12;
    }

    private int getSize(final double a, final double b, final double c, final double d) {
        double r = Math.abs(a - 0.5);
        r = Math.max(Math.abs(b - 0.5), r);
        r = Math.max(Math.abs(c - 0.5), r);
        return (8 * (int) Math.max(Math.abs(d - 0.5), r));
    }

    // @Override
    public int getSlotMask() {
        int mask = 0;

        for (final ForgeDirection side : ForgeDirection.values()) {
            if (this.getPart(side) != null) {
                mask |= 1 << side.ordinal();
            } else if (side != ForgeDirection.UNKNOWN && this.getFacadeContainer().getFacade(side) != null) {
                mask |= 1 << side.ordinal();
            }
        }

        return mask;
    }

    @Override
    public IFacadeContainer getFacadeContainer() {
        return this.getCableBus().getFacadeContainer();
    }

    @Override
    public boolean canAddPart(ItemStack is, final ForgeDirection side) {
        final IFacadePart fp = PartPlacement.isFacade(is, side);
        if (fp != null) {
            if (!(side == null || side == ForgeDirection.UNKNOWN || this.tile() == null)) {
                final List<AxisAlignedBB> boxes = new ArrayList<AxisAlignedBB>();
                final IPartCollisionHelper bch = new BusCollisionHelper(boxes, side, null, true);
                fp.getBoxes(bch, null);
                for (final AxisAlignedBB bb : boxes) {
                    DISABLE_FACADE_OCCLUSION.set(true);
                    final boolean canAdd = this.tile().canAddPart(new NormallyOccludedPart(new Cuboid6(bb)));
                    DISABLE_FACADE_OCCLUSION.remove();
                    if (!canAdd) {
                        return false;
                    }
                }
            }
            return true;
        }

        if (is.getItem() instanceof IPartItem) {
            final IPartItem bi = (IPartItem) is.getItem();

            is = is.copy();
            is.stackSize = 1;

            final IPart bp = bi.createPartFromItemStack(is);
            if (!(side == null || side == ForgeDirection.UNKNOWN || this.tile() == null)) {
                final List<AxisAlignedBB> boxes = new ArrayList<AxisAlignedBB>();
                final IPartCollisionHelper bch = new BusCollisionHelper(boxes, side, null, true);
                if (bp != null) {
                    bp.getBoxes(bch);
                }
                for (final AxisAlignedBB bb : boxes) {
                    if (!this.tile().canAddPart(new NormallyOccludedPart(new Cuboid6(bb)))) {
                        return false;
                    }
                }
            }
        }

        return this.getCableBus().canAddPart(is, side);
    }

    @Override
    public ForgeDirection addPart(final ItemStack is, final ForgeDirection side, final EntityPlayer owner) {
        return this.getCableBus().addPart(is, side, owner);
    }

    @Override
    public IPart getPart(final ForgeDirection side) {
        return this.getCableBus().getPart(side);
    }

    @Override
    public void removePart(final ForgeDirection side, final boolean suppressUpdate) {
        this.getCableBus().removePart(side, suppressUpdate);
    }

    @Override
    public void markForUpdate() {
        if (Platform.isServer() && this.canUpdate) {
            this.sendDescUpdate();
        }
    }

    @Override
    public DimensionalCoord getLocation() {
        return new DimensionalCoord(this.tile());
    }

    @Override
    public AEColor getColor() {
        return this.getCableBus().getColor();
    }

    @Override
    public void clearContainer() {
        this.setCableBus(new CableBusContainer(this));
    }

    @Override
    public boolean isBlocked(final ForgeDirection side) {
        if (side == null || side == ForgeDirection.UNKNOWN || this.tile() == null) {
            return false;
        }

        DISABLE_FACADE_OCCLUSION.set(true);

        final int ordinal = side.ordinal();
        final Cuboid6 sideTest = SIDE_TESTS[ordinal];
        final NormallyOccludedPart occludedPart = new NormallyOccludedPart(sideTest);
        final boolean blocked = !this.tile().canAddPart(occludedPart);
        DISABLE_FACADE_OCCLUSION.remove();

        return blocked;
    }

    @Override
    public SelectedPart selectPart(final Vec3 pos) {
        return this.getCableBus().selectPart(pos);
    }

    @Override
    public void markForSave() {
        // mark the chunk for save...
        final TileEntity te = this.tile();
        if (te != null && te.getWorldObj() != null) {
            te.getWorldObj().getChunkFromBlockCoords(this.x(), this.z()).isModified = true;
        }
    }

    @Override
    public void partChanged() {
        if (this.isInWorld()) {
            this.notifyNeighbors();
        }
    }

    @Override
    public boolean hasRedstone(final ForgeDirection side) {
        return this.getCableBus().hasRedstone(side);
    }

    @Override
    public boolean isEmpty() {
        return this.getCableBus().isEmpty();
    }

    @Override
    public Set<LayerFlags> getLayerFlags() {
        return this.getCableBus().getLayerFlags();
    }

    @Override
    public void cleanup() {
        this.tile().remPart(this);
    }

    @Override
    public void notifyNeighbors() {
        if (this.tile() instanceof TIInventoryTile) {
            ((TIInventoryTile) this.tile()).rebuildSlotMap();
        }

        if (this.world() != null && this.world().blockExists(this.x(), this.y(), this.z())
                && !CableBusContainer.isLoading()) {
            Platform.notifyBlocksOfNeighbors(this.world(), this.x(), this.y(), this.z());
        }
    }

    @Override
    public boolean isInWorld() {
        return this.getCableBus().isInWorld();
    }

    @Override
    public Iterable<Cuboid6> getCollisionBoxes() {
        final LinkedList<Cuboid6> l = new LinkedList<Cuboid6>();
        for (final AxisAlignedBB b : this.getCableBus().getSelectedBoundingBoxesFromPool(false, true, null, true)) {
            l.add(new Cuboid6(b.minX, b.minY, b.minZ, b.maxX, b.maxY, b.maxZ));
        }
        return l;
    }

    @Override
    public Iterable<IndexedCuboid6> getSubParts() {
        final LinkedList<IndexedCuboid6> l = new LinkedList<IndexedCuboid6>();
        for (final Cuboid6 c : this.getCollisionBoxes()) {
            l.add(new IndexedCuboid6(0, c));
        }
        return l;
    }

    @Override
    public int getConnectionMask(final int side) {
        return CONNECTION_MASK;
    }

    public CableBusContainer getCableBus() {
        return this.cb;
    }

    private void setCableBus(final CableBusContainer cb) {
        this.cb = cb;
    }
}