Package mods.railcraft.common.blocks.signals

Source Code of mods.railcraft.common.blocks.signals.SignalBlock

/*
* 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.signals;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.logging.log4j.Level;
import net.minecraft.entity.item.EntityMinecart;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.MathHelper;
import mods.railcraft.api.carts.CartTools;
import mods.railcraft.api.core.WorldCoordinate;
import mods.railcraft.api.signals.AbstractPair;
import mods.railcraft.api.signals.SignalAspect;
import mods.railcraft.common.blocks.RailcraftTileEntity;
import mods.railcraft.common.blocks.tracks.TrackTools;
import mods.railcraft.common.core.RailcraftConfig;
import mods.railcraft.common.util.misc.Game;
import net.minecraft.world.World;

/**
*
* @author CovertJaguar <http://www.railcraft.info>
*/
public abstract class SignalBlock extends AbstractPair {

    Map<WorldCoordinate, WorldCoordinate> trackCache = new HashMap<WorldCoordinate, WorldCoordinate>();
    Set<WorldCoordinate> waitingForRetest = new HashSet<WorldCoordinate>();
    private WorldCoordinate trackLocation;
    private int update = rand.nextInt();

    public SignalBlock(RailcraftTileEntity tile, int numPairs) {
        super(tile.getName(), tile, numPairs);
    }

    public SignalBlock getSignalAt(WorldCoordinate coord) {
        TileEntity recv = getPairAt(coord);
        if (recv != null)
            return ((ISignalBlockTile) recv).getSignalBlock();
        return null;
    }

    public abstract SignalAspect getSignalAspect();

    private void printDebug(String msg, Object... args) {
        if (RailcraftConfig.printSignalDebug())
            Game.log(Level.DEBUG, msg, args);
    }

    public void clearSignalBlockPairing(WorldCoordinate other, String reason, Object... args) {
        printDebug(reason, args);
        if (other == null)
            clearPairings();
        else
            clearPairing(other);
    }

    @Override
    public boolean isValidPair(TileEntity tile) {
        boolean isValid = false;
        if (tile instanceof ISignalBlockTile) {
            SignalBlock block = ((ISignalBlockTile) tile).getSignalBlock();
            isValid = block.isPairedWith(getCoords());
        }
        if (!isValid)
            if (tile != null)
                printDebug("Signal Block dropped because pair was no longer paired or was not a valid Signal [{0}, {1}, {2}]", tile.xCoord, tile.yCoord, tile.zCoord);
            else
                printDebug("Signal Block dropped because pair was no longer paired or was not a valid Signal [null]");
        return isValid;
    }

//    @Override
//    public void startPairing() {
//        clearSignalBlockPairing("Signal Block pairing cleared in preperation to start a new pairing.  [{0}, {1}, {2}]", tile.xCoord, tile.yCoord, tile.zCoord);
//        super.startPairing();
//    }
    public boolean createSignalBlock(SignalBlock other) {
        locateTrack();
        other.locateTrack();
        WorldCoordinate tA = getTrackLocation();
        WorldCoordinate tB = other.getTrackLocation();
        if (tA == null || tB == null)
            return false;
        if (!TrackTools.areTracksConnectedAlongAxis(tile.getWorldObj(), tA.x, tA.y, tA.z, tB.x, tB.y, tB.z))
            return false;
        addPairing(other.getCoords());
        other.addPairing(getCoords());
        endPairing();
        other.endPairing();
        return true;
    }

    protected abstract void updateSignalAspect();

    protected abstract SignalAspect getSignalAspectForPair(WorldCoordinate otherCoord);

    protected SignalAspect determineAspect(WorldCoordinate otherCoord) {
        if (isWaitingForRetest() || isBeingPaired())
            return SignalAspect.BLINK_YELLOW;
        if (!isPaired())
            return SignalAspect.BLINK_RED;
        SignalAspect otherAspect = SignalAspect.GREEN;
        SignalBlock other = getSignalAt(otherCoord);
        if (other != null)
            otherAspect = other.getSignalAspectForPair(getCoords());
        SignalAspect myAspect = determineMyAspect(otherCoord);
        return SignalAspect.mostRestrictive(myAspect, otherAspect);
    }

    private SignalAspect determineMyAspect(WorldCoordinate otherCoord) {
        WorldCoordinate myTrack = getTrackLocation();
        if (myTrack == null)
            return SignalAspect.RED;
        WorldCoordinate otherTrack = getOtherTrackLocation(otherCoord);
        if (otherTrack == null)
            return SignalAspect.YELLOW;
        int x1 = Math.min(myTrack.x, otherTrack.x);
        int y1 = Math.min(myTrack.y, otherTrack.y);
        int z1 = Math.min(myTrack.z, otherTrack.z);
        int x2 = Math.max(myTrack.x, otherTrack.x) + 1;
        int y2 = Math.max(myTrack.y, otherTrack.y) + 1;
        int z2 = Math.max(myTrack.z, otherTrack.z) + 1;

        boolean zAxis = Math.abs(myTrack.x - otherTrack.x) < Math.abs(myTrack.z - otherTrack.z);
        int xOffset = otherTrack.x > myTrack.x ? -3 : 3;
        int zOffset = otherTrack.z > myTrack.z ? -3 : 3;

        List<EntityMinecart> carts = CartTools.getMinecartsIn(tile.getWorldObj(), x1, y1, z1, x2, y2, z2);
//        System.out.printf("%d, %d, %d, %d, %d, %d\n", i1, j1, k1, i2, j2, k2);
//        System.out.println("carts = " + carts.size());
        SignalAspect newAspect = SignalAspect.GREEN;
        for (EntityMinecart cart : carts) {
            int cartX = MathHelper.floor_double(cart.posX);
            int cartZ = MathHelper.floor_double(cart.posZ);
            if (Math.abs(cart.motionX) < 0.08 && Math.abs(cart.motionZ) < 0.08)
                return SignalAspect.RED;
            else if (zAxis)
                if (cartZ > myTrack.z + zOffset && cart.motionZ < 0)
                    return SignalAspect.RED;
                else if (cartZ < myTrack.z + zOffset && cart.motionZ > 0)
                    return SignalAspect.RED;
                else
                    newAspect = SignalAspect.YELLOW;
            else if (cartX > myTrack.x + xOffset && cart.motionX < 0)
                return SignalAspect.RED;
            else if (cartX < myTrack.x + xOffset && cart.motionX > 0)
                return SignalAspect.RED;
            else
                newAspect = SignalAspect.YELLOW;
        }
        return newAspect;
    }

    protected WorldCoordinate getOtherTrackLocation(WorldCoordinate otherCoord) {
        SignalBlock other = getSignalAt(otherCoord);
        if (other != null) {
            WorldCoordinate track = other.getTrackLocation();
            trackCache.put(otherCoord, track);
            return track;
        }
        return trackCache.get(otherCoord);
    }

    private boolean isSignalBlockValid(WorldCoordinate other) {
        if (other == null)
            return true;
        if (getSignalAt(other) == null)
            return true;
        WorldCoordinate tA = getTrackLocation();
        WorldCoordinate tB = getOtherTrackLocation(other);
        if (tA == null || tB == null)
            return false;
        if (!TrackTools.areTracksConnectedAlongAxis(tile.getWorldObj(), tA.x, tA.y, tA.z, tB.x, tB.y, tB.z))
            return false;
        return true;
    }

    @Override
    public void tickServer() {
        super.tickServer();
        update++;
        if (update % Signals.getSignalUpdateInterval() == 0)
            updateSignalAspect();
        if (update % Signals.VALIDATION_CHECK_INTERVAL == 0) {
            Status trackStatus = getTrackStatus();
            switch (trackStatus) {
                case INVALID:
                    clearSignalBlockPairing(null, "Signal Block dropped because no track was found near Signal. [{0}, {1}, {2}]", tile.xCoord, tile.yCoord, tile.zCoord);
                    break;
                case VALID:
                    for (WorldCoordinate otherCoord : waitingForRetest) {
                        if (!isSignalBlockValid(otherCoord))
                            clearSignalBlockPairing(otherCoord, "Signal Block dropped because track between Signals was invalid. [{0}, {1}, {2}]", tile.xCoord, tile.yCoord, tile.zCoord);
                    }
                    waitingForRetest.clear();
                    for (WorldCoordinate otherCoord : pairings) {
                        if (!isSignalBlockValid(otherCoord))
                            waitingForRetest.add(otherCoord);
                    }
                    break;
            }
        }
    }

    public boolean isWaitingForRetest() {
        return !waitingForRetest.isEmpty();
    }

    @Override
    protected String getTagName() {
        return "SignalBlock";
    }

    public WorldCoordinate getTrackLocation() {
        if (trackLocation == null)
            locateTrack();
        return trackLocation;
    }

    public static enum Status {

        VALID, INVALID, UNKNOWN
    }

    private Status getTrackStatus() {
        if (trackLocation == null)
            return locateTrack();
        if (!tile.getWorldObj().blockExists(trackLocation.x, trackLocation.y, trackLocation.z))
            return Status.UNKNOWN;
        if (!TrackTools.isRailBlockAt(tile.getWorldObj(), trackLocation.x, trackLocation.y, trackLocation.z)) {
            trackLocation = null;
            return Status.INVALID;
        }
        return Status.VALID;
    }

    private Status locateTrack() {
        int x = tile.xCoord;
        int y = tile.yCoord;
        int z = tile.zCoord;
        Status status = testForTrack(x, y, z);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x - 1, y, z);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x + 1, y, z);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x, y, z - 1);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x, y, z + 1);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x - 2, y, z);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x + 2, y, z);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x, y, z - 2);
        if (status != Status.INVALID)
            return status;
        status = testForTrack(x, y, z + 2);
        if (status != Status.INVALID)
            return status;
        return Status.INVALID;
    }

    private Status testForTrack(int x, int y, int z) {
        World world = tile.getWorldObj();
        for (int jj = -2; jj < 4; jj++) {
            if (!world.blockExists(x, y - jj, z))
                return Status.UNKNOWN;
            if (TrackTools.isRailBlockAt(world, x, y - jj, z)) {
                trackLocation = new WorldCoordinate(world.provider.dimensionId, x, y - jj, z);
                return Status.VALID;
            }
        }
        return Status.INVALID;
    }

}
TOP

Related Classes of mods.railcraft.common.blocks.signals.SignalBlock

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.