Package mods.railcraft.common.blocks.machine

Source Code of mods.railcraft.common.blocks.machine.TileMultiBlock

/*
* Copyright (c) CovertJaguar, 2014 http://railcraft.info
*
* This code is the property of CovertJaguar
* and may only be used with explicit written
* permission unless otherwise specified on the
* license page at http://railcraft.info/wiki/info:license.
*/
package mods.railcraft.common.blocks.machine;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.relauncher.Side;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.*;
import mods.railcraft.common.plugins.forge.WorldPlugin;
import mods.railcraft.common.util.inventory.InvTools;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.AxisAlignedBB;
import net.minecraftforge.common.util.ForgeDirection;
import mods.railcraft.common.util.misc.Game;
import mods.railcraft.common.util.misc.MiscTools;
import mods.railcraft.common.util.misc.Timer;
import mods.railcraft.common.util.network.PacketDispatcher;
import mods.railcraft.common.util.network.PacketTileRequest;
import net.minecraft.block.Block;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.inventory.IInventory;

public abstract class TileMultiBlock extends TileMachineBase {

    public enum MultiBlockState {

        VALID, INVALID, UNKNOWN
    };

    public enum MultiBlockStateReturn {

        VALID(MultiBlockState.VALID, "railcraft.multiblock.state.valid"),
        ENTITY_IN_WAY(MultiBlockState.INVALID, "railcraft.multiblock.state.invalid.entity"),
        PATTERN_DOES_NOT_MATCH(MultiBlockState.INVALID, "railcraft.multiblock.state.invalid.pattern"),
        NOT_LOADED(MultiBlockState.UNKNOWN, "railcraft.multiblock.state.unknown.unloaded");
        public final MultiBlockState type;
        public final String message;

        private MultiBlockStateReturn(MultiBlockState type, String msg) {
            this.type = type;
            this.message = msg;
        }

    }
    private static final int UNKNOWN_STATE_RECHECK = 256;
    private static final int NETWORK_RECHECK = 64;
    protected boolean isMaster;
    private byte patternX;
    private byte patternY;
    private byte patternZ;
    private boolean tested;
    private boolean requestPacket;
    private final Timer netTimer = new Timer();
    private MultiBlockState state;
    public ListMultimap<MultiBlockStateReturn, Integer> patternStates = ArrayListMultimap.create();
    private TileMultiBlock masterBlock;
    private MultiBlockPattern currentPattern;
    private final List<? extends MultiBlockPattern> patterns;
    private UUID uuid;
    private UUID uuidMaster;
    private final List<TileEntity> components = new LinkedList<TileEntity>();
    private final List<TileEntity> componentsImmutable = Collections.unmodifiableList(components);

    public TileMultiBlock(List<? extends MultiBlockPattern> patterns) {
        this.patterns = patterns;
        currentPattern = patterns.get(0);
        tested = FMLCommonHandler.instance().getEffectiveSide() != Side.SERVER;
    }

    public UUID getUUID() {
        if (uuid == null)
            uuid = UUID.randomUUID();
        return uuid;
    }

    public UUID getMasterUUID() {
        return uuidMaster;
    }

    public List<TileEntity> getComponents() {
        return componentsImmutable;
    }

    protected void onMasterChanged() {
    }

    private void setMaster(TileMultiBlock master) {
        this.masterBlock = master;

        if (uuidMaster != null && !uuidMaster.equals(master.getUUID()))
            onMasterChanged();

        this.uuidMaster = master.getUUID();
    }

    protected void onPatternLock(MultiBlockPattern pattern) {
    }

    protected void onPatternChanged() {
        if (!isMaster && this instanceof IInventory)
            InvTools.dropInventory((IInventory) this, worldObj, xCoord, yCoord, zCoord);
    }

    public final char getPatternMarker() {
        if (currentPattern == null || !isStructureValid())
            return 'O';
        return currentPattern.getPatternMarker(patternX, patternY, patternZ);
    }

    public final int getPatternPositionX() {
        return patternX;
    }

    public final int getPatternPositionY() {
        return patternY;
    }

    public final int getPatternPositionZ() {
        return patternZ;
    }

    private void setPatternPosition(byte x, byte y, byte z) {
        patternX = x;
        patternY = y;
        patternZ = z;
    }

    public final void setPattern(MultiBlockPattern pattern) {
        if (currentPattern != pattern)
            onPatternChanged();
        this.currentPattern = pattern;
        onPatternLock(pattern);
    }

    public final MultiBlockPattern getPattern() {
        return currentPattern;
    }

    public final byte getPatternIndex() {
        return (byte) patterns.indexOf(currentPattern);
    }

    protected int getMaxRecursionDepth() {
        return 12;
    }

    public MultiBlockState getState() {
        return state;
    }

    @Override
    public final boolean canUpdate() {
        return true;
    }

    @Override
    public void updateEntity() {
        super.updateEntity();
        if (Game.isHost(worldObj)) {
            if (!tested && (state != MultiBlockState.UNKNOWN || clock % UNKNOWN_STATE_RECHECK == 0))
                testIfMasterBlock(); //                ClientProxy.getMod().totalMultiBlockUpdates++;
        } else if (requestPacket && netTimer.hasTriggered(worldObj, NETWORK_RECHECK)) {
            PacketDispatcher.sendToServer(new PacketTileRequest(this));
            requestPacket = false;
        }
    }

    private void testIfMasterBlock() {
//        System.out.println("testing structure");
        state = getMasterBlockState();
        tested = true;
        components.clear();

        if (state == MultiBlockState.UNKNOWN)
            tested = false;
        else if (state == MultiBlockState.VALID) {
            isMaster = true;
//             System.out.println("structure complete");

            int xWidth = currentPattern.getPatternWidthX();
            int zWidth = currentPattern.getPatternWidthZ();
            int height = currentPattern.getPatternHeight();

            int xOffset = xCoord - currentPattern.getMasterOffsetX();
            int yOffset = yCoord - currentPattern.getMasterOffsetY();
            int zOffset = zCoord - currentPattern.getMasterOffsetZ();

            for (byte px = 0; px < xWidth; px++) {
                for (byte py = 0; py < height; py++) {
                    for (byte pz = 0; pz < zWidth; pz++) {

                        char marker = currentPattern.getPatternMarker(px, py, pz);
                        if (isMapPositionOtherBlock(marker))
                            continue;

                        int x = px + xOffset;
                        int y = py + yOffset;
                        int z = pz + zOffset;

                        TileEntity tile = worldObj.getTileEntity(x, y, z);
                        if (tile instanceof TileMultiBlock) {
                            TileMultiBlock multiBlock = (TileMultiBlock) tile;
                            if (multiBlock != this)
                                multiBlock.components.clear();
                            components.add(multiBlock);
                            multiBlock.tested = true;
                            multiBlock.setMaster(this);
                            multiBlock.setPattern(currentPattern);
                            multiBlock.setPatternPosition(px, py, pz);
                            multiBlock.sendUpdateToClient();
                        }
                    }
                }
            }
        } else if (isMaster) {
            isMaster = false;
            onMasterReset();
            sendUpdateToClient();
        }
    }

    protected void onMasterReset() {
        components.clear();
    }

    protected boolean isMapPositionOtherBlock(char mapPos) {
        switch (mapPos) {
            case 'A':
            case 'O':
            case '*':
                return true;
            default:
                return false;
        }
    }

    protected boolean isMapPositionValid(int x, int y, int z, char mapPos) {
        Block block = WorldPlugin.getBlock(worldObj, x, y, z);
        switch (mapPos) {
            case 'O': // Other
                if (block == getBlockType() && worldObj.getBlockMetadata(x, y, z) == getBlockMetadata())
                    return false;
                break;
            case 'W': // Window
            case 'B': // Block
                if (block != getBlockType() || worldObj.getBlockMetadata(x, y, z) != getBlockMetadata())
                    return false;
                break;
            case 'A': // Air
                if (!worldObj.isAirBlock(x, y, z))
                    return false;
                break;
            case '*': // Anything
                return true;
        }
        return true;
    }

    private MultiBlockState getMasterBlockState() {
        MultiBlockState endResult = MultiBlockState.INVALID;
        patternStates.clear();
        for (MultiBlockPattern map : patterns) {
            MultiBlockStateReturn result = isPatternValid(map);
            patternStates.put(result, patterns.indexOf(map));
            switch (result.type) {
                case VALID:
                    setPattern(map);
                    return result.type;
                case UNKNOWN:
                    endResult = MultiBlockState.UNKNOWN;
            }
        }

        return endResult;
    }

    private MultiBlockStateReturn isPatternValid(MultiBlockPattern map) {
        int xWidth = map.getPatternWidthX();
        int zWidth = map.getPatternWidthZ();
        int height = map.getPatternHeight();

        int xOffset = xCoord - map.getMasterOffsetX();
        int yOffset = yCoord - map.getMasterOffsetY();
        int zOffset = zCoord - map.getMasterOffsetZ();

        for (int patX = 0; patX < xWidth; patX++) {
            for (int patY = 0; patY < height; patY++) {
                for (int patZ = 0; patZ < zWidth; patZ++) {
                    int x = patX + xOffset;
                    int y = patY + yOffset;
                    int z = patZ + zOffset;
                    if (!worldObj.blockExists(x, y, z))
                        return MultiBlockStateReturn.NOT_LOADED;
                    if (!isMapPositionValid(x, y, z, map.getPatternMarker(patX, patY, patZ)))
                        return MultiBlockStateReturn.PATTERN_DOES_NOT_MATCH;
                }
            }
        }

        AxisAlignedBB entityCheckBounds = map.getEntityCheckBounds(xCoord, yCoord, zCoord);
//                if(entityCheckBounds != null) {
//                    System.out.println("test entitys: " + entityCheckBounds.toString());
//                }
        if (entityCheckBounds != null && !worldObj.getEntitiesWithinAABB(EntityLivingBase.class, entityCheckBounds).isEmpty())
            return MultiBlockStateReturn.ENTITY_IN_WAY;
        return MultiBlockStateReturn.VALID;
    }

    @Override
    public void onBlockAdded() {
        super.onBlockAdded();
        if (Game.isNotHost(worldObj)) return;
        onBlockChange();
    }

    @Override
    public void onBlockRemoval() {
        super.onBlockRemoval();
        if (Game.isNotHost(worldObj)) return;
        onBlockChange();
        isMaster = false;
    }

    @Override
    public void onChunkUnload() {
        super.onChunkUnload();
        if (Game.isNotHost(worldObj)) return;
        tested = false;
        scheduleMasterRetest();
    }

    @Override
    public void invalidate() {
        if (worldObj == null || Game.isHost(worldObj)) {
            tested = false;
            scheduleMasterRetest();
        }
        super.invalidate();
    }

    private void onBlockChange() {
        for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
            TileEntity tile = tileCache.getTileOnSide(side);
            if (isStructureTile(tile))
                ((TileMultiBlock) tile).onBlockChange(getMaxRecursionDepth());
        }
    }

    private void onBlockChange(int depth) {
        depth--;
        if (depth < 0)
            return;
        if (tested) {
            tested = false;

            TileMultiBlock mBlock = getMasterBlock();
            if (mBlock != null) {
                mBlock.onBlockChange(getMaxRecursionDepth());
                return;
            }

            for (ForgeDirection side : ForgeDirection.VALID_DIRECTIONS) {
                TileEntity tile = tileCache.getTileOnSide(side);
                if (isStructureTile(tile))
                    ((TileMultiBlock) tile).onBlockChange(depth);
            }
        }
    }

    protected boolean isStructureTile(TileEntity tile) {
        return tile != null && tile.getClass() == getClass();
    }

    @Override
    public void markDirty() {
        super.markDirty();
        if (!isMaster) {
            TileMultiBlock mBlock = (TileMultiBlock) getMasterBlock();
            if (mBlock != null)
                mBlock.markDirty();
        }
    }

    @Override
    public void writeToNBT(NBTTagCompound data) {
        super.writeToNBT(data);

        data.setBoolean("master", isMaster);
        data.setByte("pattern", getPatternIndex());

        MiscTools.writeUUID(data, "uuid", uuid);
        MiscTools.writeUUID(data, "uuidMaster", uuidMaster);
    }

    @Override
    public void readFromNBT(NBTTagCompound data) {
        super.readFromNBT(data);

        isMaster = data.getBoolean("master");
        try {
            currentPattern = patterns.get(data.getByte("pattern"));
        } catch (Exception ex) {
        }

        uuid = MiscTools.readUUID(data, "uuid");
        uuidMaster = MiscTools.readUUID(data, "uuidMaster");
    }

    @Override
    public void writePacketData(DataOutputStream data) throws IOException {
        super.writePacketData(data);
        boolean hasMaster = getMasterBlock() != null;
        data.writeBoolean(hasMaster);
        if (hasMaster) {
            byte patternIndex = getPatternIndex();
            data.writeByte(patternIndex);

            data.writeByte(patternX);
            data.writeByte(patternY);
            data.writeByte(patternZ);
        }
    }

    @Override
    public void readPacketData(DataInputStream data) throws IOException {
        super.readPacketData(data);

        requestPacket = false;
        boolean needsRenderUpdate = false;

        boolean hasMaster = data.readBoolean();
        if (hasMaster) {
            byte patternIndex = data.readByte();
            patternIndex = (byte) Math.max(patternIndex, 0);
            patternIndex = (byte) Math.min(patternIndex, patterns.size() - 1);
            MultiBlockPattern pat = patterns.get(patternIndex);

            byte pX = data.readByte();
            byte pY = data.readByte();
            byte pZ = data.readByte();

            if (patternX != pX || patternY != pY || patternZ != pZ) {
                patternX = pX;
                patternY = pY;
                patternZ = pZ;
                needsRenderUpdate = true;
            }

            isMaster = pX == pat.getMasterOffsetX() && pY == pat.getMasterOffsetY() && pZ == pat.getMasterOffsetZ();

            setPattern(pat);

            int masterX = pat.getMasterRelativeX(xCoord, pX);
            int masterY = pat.getMasterRelativeY(yCoord, pY);
            int masterZ = pat.getMasterRelativeZ(zCoord, pZ);

            TileEntity tile = null;
            if (worldObj != null)
                tile = worldObj.getTileEntity(masterX, masterY, masterZ);
            if (tile != null)
                if (masterBlock != tile && isStructureTile(tile)) {
                    needsRenderUpdate = true;
                    masterBlock = (TileMultiBlock) tile;
                }
            if (getMasterBlock() == null)
                requestPacket = true;
        } else if (masterBlock != null) {
            needsRenderUpdate = true;
            masterBlock = null;
            isMaster = false;
        }

        if (needsRenderUpdate)
            markBlockForUpdate();

//
//        System.out.printf("marker=%c, pattern=%d, x=%d, y=%d, z=%d%n", currentPattern.getPatternMarkerChecked(patternX, patternY, patternZ), patternIndex, patternX, patternY, patternZ);
//        if(masterBlock != null)
//        System.out.printf("tested=%b, invalid=%b, isMaster=%b%n" ,masterBlock.tested, masterBlock.isInvalid(), masterBlock.isMaster());
    }

    public final boolean isMaster() {
        return isMaster;
    }

    public final void setMaster(boolean m) {
        isMaster = m;
    }

    public final void scheduleMasterRetest() {
        if (Game.isNotHost(worldObj))
            return;
        if (masterBlock != null)
            masterBlock.tested = false;
    }

    public final boolean isStructureValid() {
        return masterBlock != null && masterBlock.tested && masterBlock.isMaster && !masterBlock.isInvalid();
    }

    public final TileMultiBlock getMasterBlock() {
        if (masterBlock != null && !isStructureValid()) {
            masterBlock = null;
            sendUpdateToClient();
        }
        return masterBlock;
    }

    @Override
    public boolean canCreatureSpawn(EnumCreatureType type) {
        return (isStructureValid() && getPatternPositionY() < 2) ? false : super.canCreatureSpawn(type);
    }

}
TOP

Related Classes of mods.railcraft.common.blocks.machine.TileMultiBlock

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.