com.builtbroken.icbm.content.missile.tile.TileCrashedMissile.java Source code

Java tutorial

Introduction

Here is the source code for com.builtbroken.icbm.content.missile.tile.TileCrashedMissile.java

Source

package com.builtbroken.icbm.content.missile.tile;

import com.builtbroken.icbm.ICBM;
import com.builtbroken.icbm.api.blast.IBlastTileMissile;
import com.builtbroken.icbm.api.blast.IExHandlerTileMissile;
import com.builtbroken.icbm.api.missile.ICustomMissileRender;
import com.builtbroken.icbm.api.missile.IMissileItem;
import com.builtbroken.icbm.api.missile.ITileMissile;
import com.builtbroken.icbm.api.modules.IMissile;
import com.builtbroken.icbm.client.Assets;
import com.builtbroken.icbm.content.crafting.missile.MissileModuleBuilder;
import com.builtbroken.icbm.content.missile.EntityMissile;
import com.builtbroken.mc.api.edit.IWorldChangeAction;
import com.builtbroken.mc.api.event.TriggerCause;
import com.builtbroken.mc.api.explosive.IExplosiveHandler;
import com.builtbroken.mc.core.network.IPacketIDReceiver;
import com.builtbroken.mc.lib.render.RenderUtility;
import com.builtbroken.mc.lib.transform.region.Cube;
import com.builtbroken.mc.lib.transform.vector.Pos;
import com.builtbroken.mc.lib.world.explosive.ExplosiveRegistry;
import com.builtbroken.mc.prefab.inventory.InventoryUtility;
import com.builtbroken.mc.prefab.tile.Tile;
import com.builtbroken.mc.prefab.tile.TileEnt;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.network.ByteBufUtils;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.IIcon;
import net.minecraft.world.Explosion;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.IFluidBlock;
import org.lwjgl.opengl.GL11;

import java.util.ArrayList;
import java.util.List;

/**
 * @see <a href="https://github.com/BuiltBrokenModding/VoltzEngine/blob/development/license.md">License</a> for what you can and can't do with the code.
 * Created by Dark(DarkGuardsman, Robert) on 4/30/2016.
 */
public class TileCrashedMissile extends TileEnt implements IPacketIDReceiver, ITileMissile {
    public static int DECAY_TICKS = 20 * 60 * 60; //1 hour
    /** List of blocks to mimic as part of the model */
    public static List<Block> blocksToMimic = new ArrayList();

    static {
        blocksToMimic.add(Blocks.tallgrass);
        blocksToMimic.add(Blocks.snow_layer);
        blocksToMimic.add(Blocks.cake);
        blocksToMimic.add(ICBM.blockCake);
        blocksToMimic.add(Blocks.fire);
        blocksToMimic.add(Blocks.ice);
        blocksToMimic.add(Blocks.glass);
    }

    /** Missile object that defines render and blast information */
    public IMissile missile;

    private ForgeDirection attachedSide;
    /** Render rotation yaw of the entity */
    private float yaw = 0;
    /** Render rotation pitch of the entity */
    private float pitch = -90;
    /** Slightly random offset to improve render randomization */
    private Pos posOffset = new Pos();

    /** Currently blast running in the missile */
    private IBlastTileMissile blast;
    /** Called to do the blast reguardless of what the blast code is */
    private boolean doBlast = false;
    /** Cause to use if triggering the blast */
    private TriggerCause cause;

    /** Amount of time to run the engine */
    private int ticksForEngine;
    /** Amount of time to generate smoke */
    private int ticksForSmoke;

    private int ticksAlive = 0;

    private Pos misislePos = toPos().add(0.5);

    private Block block;
    private int meta;

    //TODO add engine flames for a few seconds after landing
    //TODO generate smoke for a few mins after landing

    public TileCrashedMissile() {
        super("missile", Material.iron);
        this.hardness = 10f;
        this.resistance = 10f;
        this.itemBlock = ItemBlockMissile.class;
        this.renderNormalBlock = false;
        this.renderTileEntity = true;
        this.isOpaque = false;
        this.bounds = new Cube(0.3, 0, 0.3, .7, .7, .7);
    }

    @Override
    public Tile newTile() {
        return new TileCrashedMissile();
    }

    @Override
    public ItemStack toItemStack() {
        return missile != null ? missile.toStack() : null;
    }

    /**
     * Called to place this tile into the world from a missile entity
     *
     * @param missile
     * @param world
     * @param x
     * @param y
     * @param z
     */
    public static void placeFromMissile(EntityMissile missile, World world, int x, int y, int z) {
        //TODO if block is a fluid place an entity version of this tile instead, fixed fluid renderer
        Block block = world.getBlock(x, y, z);
        int meta = world.getBlockMetadata(x, y, z);
        while (y < 255 && !blocksToMimic.contains(block)
                && !(block.isAir(world, x, y, z) || block.isReplaceable(world, x, y, z))) {
            y += 1;
            block = world.getBlock(x, y, z);
            meta = world.getBlockMetadata(x, y, z);
        }
        if (block == Blocks.lava || block == Blocks.flowing_lava) {
            //Missile is destroyed
            return;
        }
        if (block instanceof IFluidBlock) {
            Fluid fluid = ((IFluidBlock) block).getFluid();
            if (fluid != null && fluid.getTemperature(world, x, y, z) > 1000) {
                //Missile is destroyed
                return;
            }
        }
        if (world.setBlock(x, y, z, ICBM.blockCrashMissile)) {
            ICBM.INSTANCE.logger()
                    .info(String.format("Placed missile %d@dim %dx %dy %dz", world.provider.dimensionId, x, y, z));
            TileEntity tile = world.getTileEntity(x, y, z);
            if (tile instanceof TileCrashedMissile) {
                if (blocksToMimic.contains(block)) {
                    ((TileCrashedMissile) tile).block = block;
                    ((TileCrashedMissile) tile).meta = meta;
                    switch (missile.sideTile) {
                    case 0:
                        ((TileCrashedMissile) tile).posOffset.sub(0, block.getBlockBoundsMinY(), 0);
                        break;
                    case 1:
                        ((TileCrashedMissile) tile).posOffset.add(0, block.getBlockBoundsMaxY(), 0);
                        break;
                    }
                }
                if (missile.getMissile() != null) {
                    ((TileCrashedMissile) tile).missile = missile.getMissile();
                }
                ((TileCrashedMissile) tile).yaw = missile.rotationYaw;
                ((TileCrashedMissile) tile).pitch = missile.rotationPitch;
                ((TileCrashedMissile) tile).cause = new TriggerCause.TriggerCauseEntity(missile);
                ((TileCrashedMissile) tile).attachedSide = ForgeDirection.getOrientation(missile.sideTile);
            }
        }
        missile.setDead();
    }

    @Override
    public void firstTick() {
        super.firstTick();
        misislePos = misislePos.add(posOffset);
    }

    @Override
    public void update() {
        super.update();
        if (isServer()) {
            //TODO implement gravity
            //TODO check if block inside moves
            //TODO allow to be pushed a little bit
            //TODO on punched by entity push a little
            if (blast == null && ticks % 20 == 0) {
                if (missile != null && missile.getWarhead() != null
                        && missile.getWarhead().getExplosiveStack() != null) {
                    IExplosiveHandler handler = ExplosiveRegistry.get(missile.getWarhead().getExplosiveStack());

                    if (doBlast || handler instanceof IExHandlerTileMissile
                            && ((IExHandlerTileMissile) handler).doesSpawnMissileTile(missile, null)) {
                        IWorldChangeAction action = handler.createBlastForTrigger(world(), xi() + 0.5, yi() + 0.5,
                                zi() + 0.5, cause, missile.getWarhead().getExplosiveSize(),
                                missile.getWarhead().getAdditionalExplosiveData());
                        if (action != null) {
                            if (action instanceof IBlastTileMissile) {
                                blast = (IBlastTileMissile) action;
                            } else {
                                missile.getWarhead().trigger(cause, world(), xi() + 0.5, yi() + 0.5, zi() + 0.5);
                            }
                        }
                    }
                }
            }

            //Tick the explosive
            if (blast != null) {
                blast.tickBlast(this, missile);
                if (blast.isCompleted()) {
                    blast = null;
                    missile.getWarhead().setExplosiveStack(null);
                }
            } else {
                ticksAlive++;
                if (ticksAlive > DECAY_TICKS) {
                    world().setBlockToAir(xi(), yi(), zi());
                    return;
                }
            }

            if (missile != null && missile.getEngine() != null) {

            }
            //TODO if block we are in is not solid fall
            //TODO if block is no full sized offset render pos and collision box
            if (ticks % 5 == 0) {
                if (attachedSide != null) {
                    Pos pos = toPos().add(attachedSide.getOpposite());
                    if (pos.isAirBlock(world())) {
                        attemptToFall();
                    }
                } else {
                    attemptToFall();
                }
            }
        }
    }

    /**
     * Used to cause the block to drop a bit
     */
    protected void attemptToFall() {
        Pos pos = toPos().sub(0, 1, 0);
        if (pos.isAirBlock(world())) {
            EntityMissile missile = new EntityMissile(world());
            missile.setPosition(x() + 0.5, y() + 0.5, z() + 0.5);
            missile.setMissile(this.missile);
            missile.rotationYaw = yaw;
            missile.rotationPitch = pitch;
            toPos().setBlockToAir(world());
        } else {
            attachedSide = ForgeDirection.UP;
        }
    }

    @Override
    public Iterable<Cube> getCollisionBoxes(Cube intersect, Entity entity) {
        List<Cube> boxes = new ArrayList<>();
        boxes.add(getCollisionBounds());
        if (block != null) {
            AxisAlignedBB bb = block.getCollisionBoundingBoxFromPool(world(), xi(), yi(), zi());
            if (bb != null) {
                boxes.add(new Cube(bb).subtract(xi(), yi(), zi()));
            } else {
                Cube cube = new Cube(block.getBlockBoundsMinX(), block.getBlockBoundsMinY(),
                        block.getBlockBoundsMinZ(), block.getBlockBoundsMaxX(), block.getBlockBoundsMaxY(),
                        block.getBlockBoundsMaxZ());
                if (cube.isValid()) {
                    //Not sure why but BB can go null
                    boxes.add(cube);
                }
            }
        }
        return boxes;
    }

    @Override
    public boolean onPlayerActivated(EntityPlayer player, int side, Pos hit) {
        //Removed wrench support
        return onPlayerRightClick(player, side, hit);
    }

    @Override
    protected boolean onPlayerRightClick(EntityPlayer player, int side, Pos hit) {
        if (block != null) {
            //TODO do collisions check for block,
        }
        if (isServer()) {
            if (missile != null) {
                ItemStack stack = missile.toStack();

                if (player.inventory.addItemStackToInventory(stack)) {
                    //stack size is only one so no need to do checks
                    toPos().setBlock(world(), block != null ? block : Blocks.air, block != null ? meta : 0);
                    player.inventoryContainer.detectAndSendChanges();
                }
            }
        }
        return true;
    }

    @Override
    public boolean removeByPlayer(EntityPlayer player, boolean willHarvest) {
        //TODO chance to blow up missile
        if (missile != null && willHarvest) {
            ItemStack stack = missile.toStack();
            InventoryUtility.dropItemStack(world(), x() + 0.5, y() + 0.5, z() + 0.5, stack, 10, 0);
        }
        if (block != null) {
            return world().setBlock(xi(), yi(), zi(), block, meta, 3);
        }
        return world().setBlockToAir(xi(), yi(), zi());
    }

    @Override
    public void onCollide(Entity entity) {
        if (isServer() && entity != null && entity.worldObj != null && missile != null && blast == null) {
            if (world().rand.nextFloat() <= 0.3 && missile.getWarhead() != null) {
                missile.getWarhead().trigger(new TriggerCause.TriggerCauseEntity(entity), world(), x() + 0.5,
                        y() + 0.5, z() + 0.5);
            } else {
                //TODO push missile around
            }
        }
    }

    @Override
    public boolean onPlayerLeftClick(EntityPlayer player) {
        if (world().rand.nextFloat() <= 0.3 && missile.getWarhead() != null && blast == null) {
            missile.getWarhead().trigger(new TriggerCause.TriggerCauseEntity(player), world(), x() + 0.5, y() + 0.5,
                    z() + 0.5);
        } else {
            //TODO push missile around
        }
        return false;
    }

    @Override
    public void onDestroyedByExplosion(Explosion ex) {
        //TODO attempt to set off warhead
        if (missile != null && missile.getWarhead() != null && blast == null) {
            missile.getWarhead().trigger(new TriggerCause.TriggerCauseExplosion(ex), world(), x() + 0.5, y() + 0.5,
                    z() + 0.5);
        }
    }

    @Override
    public void onFillRain() {
        //TODO decrease smoke timer faster
        //TODO make pop noise like car engine cooling down
        //TODO make metal rain noise
    }

    @Override
    public void readFromNBT(NBTTagCompound nbt) {
        super.readFromNBT(nbt);
        if (nbt.hasKey("missile")) {
            ItemStack stack = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("missile"));
            missile = stack.getItem() instanceof IMissileItem ? ((IMissileItem) stack.getItem()).toMissile(stack)
                    : MissileModuleBuilder.INSTANCE.buildMissile(stack);
        }
        yaw = nbt.getFloat("yaw");
        pitch = nbt.getFloat("pitch");
        if (nbt.hasKey("offset")) {
            posOffset = new Pos(nbt.getCompoundTag("offset"));
        }
        if (nbt.hasKey("block")) {
            block = Block.getBlockFromName(nbt.getString("block"));
            meta = nbt.getInteger("blockMeta");
        }
        ticksAlive = nbt.getInteger("ticksAlive");
    }

    @Override
    public void writeToNBT(NBTTagCompound nbt) {
        super.writeToNBT(nbt);
        if (missile != null) {
            ItemStack stack = missile.toStack();
            nbt.setTag("missile", stack.writeToNBT(new NBTTagCompound()));
        }
        nbt.setFloat("yaw", yaw);
        nbt.setFloat("pitch", pitch);
        if (posOffset != null) {
            nbt.setTag("offset", posOffset.toNBT());
        }
        if (block != null) {
            nbt.setString("block", Block.blockRegistry.getNameForObject(block));
            nbt.setInteger("blockMeta", meta);
        }
        nbt.setInteger("ticksAlive", ticksAlive);
    }

    @Override
    public void readDescPacket(ByteBuf buf) {
        ItemStack stack = ByteBufUtils.readItemStack(buf);
        missile = stack.getItem() instanceof IMissileItem ? ((IMissileItem) stack.getItem()).toMissile(stack)
                : null;
        yaw = buf.readFloat();
        pitch = buf.readFloat();
        posOffset = new Pos(buf);
        if (buf.readBoolean()) {
            block = Block.getBlockFromName(ByteBufUtils.readUTF8String(buf));
            meta = buf.readShort();
        }
    }

    @Override
    public void writeDescPacket(ByteBuf buf) {
        if (missile != null) {
            ByteBufUtils.writeItemStack(buf, missile.toStack());
        } else {
            ByteBufUtils.writeItemStack(buf, new ItemStack(Items.stone_axe)); //random sync data, set the missile to null
        }
        buf.writeFloat(yaw);
        buf.writeFloat(pitch);
        posOffset.writeByteBuf(buf);
        buf.writeBoolean(block != null);
        if (block != null) {
            ByteBufUtils.writeUTF8String(buf, Block.blockRegistry.getNameForObject(block));
            buf.writeShort(meta);
        }
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void renderDynamic(Pos pos, float frame, int pass) {
        GL11.glPushMatrix();
        if (missile != null) {
            GL11.glTranslated(pos.x() + 0.5,
                    pos.y() + (float) (missile.getHeight() / 2.0) - (float) (missile.getHeight() / 3.0),
                    pos.z() + 0.5);
            if (block != null) {
                GL11.glTranslated(0, block.getBlockBoundsMaxY(), 0);
            }
            if (posOffset != null) {
                GL11.glTranslated(posOffset.x(), posOffset.y(), posOffset.z());
            }
            if (!(missile instanceof ICustomMissileRender)
                    || !((ICustomMissileRender) missile).renderMissileInWorld(yaw - 90, pitch - 90, frame)) {
                renderDefaultMissile();
            }
        } else {
            GL11.glTranslated(pos.x() + 0.5, pos.y() + .4, pos.z() + 0.5);
            if (posOffset != null) {
                GL11.glTranslated(posOffset.x(), posOffset.y(), posOffset.z());
            }
            renderDefaultMissile();
        }
        GL11.glPopMatrix();
        if (block != null) {
            GL11.glPushMatrix();
            GL11.glTranslated(pos.x() + 0.5, pos.y() + 0.5, pos.z() + 0.5);
            RenderUtility.renderInventoryBlock(RenderUtility.renderBlocks, block, meta);
            GL11.glPopMatrix();
        }
    }

    private final void renderDefaultMissile() {
        GL11.glTranslated(0.5, 2, 0.5);
        GL11.glRotatef(yaw, 0.0F, 1.0F, 0.0F);
        GL11.glRotatef(pitch - 90, 0.0F, 0.0F, 1.0F);
        GL11.glScalef(.5f, .5f, .5f);
        FMLClientHandler.instance().getClient().renderEngine.bindTexture(Assets.CLASSIC_MISSILE_TEXTURE);
        if (missile == null || missile.getWarhead() != null) {
            Assets.CLASSIC_MISSILE_MODEL.renderOnly("WARHEAD 1", "WARHEAD 2", "WARHEAD 3", "WARHEAD 4");
        }
        Assets.CLASSIC_MISSILE_MODEL.renderAllExcept("WARHEAD 1", "WARHEAD 2", "WARHEAD 3", "WARHEAD 4");
    }

    @Override
    public ArrayList<ItemStack> getDrops(int metadata, int fortune) {
        ArrayList<ItemStack> drops = new ArrayList();
        if (missile != null) {
            ItemStack m = missile.toStack();
            if (m != null && m.getItem() != null) {
                //TODO implement dropping scrap parts instead of full missile
                drops.add(m);
            }
        }
        return drops;
    }

    @Override
    @SideOnly(Side.CLIENT)
    public IIcon getIcon() {
        return Blocks.iron_block.getIcon(0, 0);
    }

    @Override
    @SideOnly(Side.CLIENT)
    public IIcon getIcon(int meta, int side) {
        return Blocks.iron_block.getIcon(0, 0);
    }

    public void setTextureName(String value) {
        textureName = value;
    }

    @SideOnly(Side.CLIENT)
    public void registerIcons(IIconRegister iconRegister) {
    }
}