Package mods.railcraft.common.carts

Source Code of mods.railcraft.common.carts.LinkageManager

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

import com.google.common.collect.MapMaker;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.apache.logging.log4j.Level;
import net.minecraft.entity.item.EntityMinecart;
import mods.railcraft.api.carts.CartTools;
import mods.railcraft.api.carts.ILinkableCart;
import mods.railcraft.api.carts.ILinkageManager;
import mods.railcraft.common.core.RailcraftConfig;
import mods.railcraft.common.util.misc.Game;

/**
* The LinkageManager contains all the functions needed to link and interacted
* with linked carts.
*
* One concept if import is that of the Linkage Id. Every cart is given a unique
* identifier by the LinkageManager the first time it encounters the cart.
*
* This identifier is stored in the entity's NBT data between world loads so
* that links are persistent rather than transitory.
*
* Links are also stored in NBT data as an Integer value that contains the
* Linkage Id of the cart it is linked to.
*
* Generally you can ignore most of this and use the functions that don't
* require or return Linkage Ids.
*
* @author CovertJaguar <http://www.railcraft.info>
*/
public class LinkageManager implements ILinkageManager {

    private final Map<UUID, EntityMinecart> carts = new MapMaker().weakValues().makeMap();
    private final Map<UUID, Train> trains = new HashMap<UUID, Train>();
    public static final String LINK_A_HIGH = "rcLinkAHigh";
    public static final String LINK_A_LOW = "rcLinkALow";
    public static final String LINK_B_HIGH = "rcLinkBHigh";
    public static final String LINK_B_LOW = "rcLinkBLow";
    public static final String TRAIN_HIGH = "rcTrainHigh";
    public static final String TRAIN_LOW = "rcTrainLow";

    private LinkageManager() {
    }

    /**
     * Return an instance of the LinkageManager
     *
     * @return LinkageManager
     */
    public static LinkageManager instance() {
        return (LinkageManager) CartTools.linkageManager;
    }

    public static void printDebug(String msg, Object... args) {
        if (RailcraftConfig.printLinkingDebug())
            Game.log(Level.DEBUG, msg, args);
    }

    public static void reset() {
        CartTools.linkageManager = new LinkageManager();
    }

    /**
     * Removes a id:cart pairing from the linkage registry.
     *
     * You should not need to call this function ever, it is needed only by the
     * LinkageHandler (internal RailcraftProxy code) in order to clean up dead
     * links left by dead carts.
     *
     * @param cart The cart to remove
     */
    public void removeLinkageId(EntityMinecart cart) {
        carts.remove(getLinkageId(cart));
    }

    /**
     * Returns the linkage id of the cart and adds the cart the linkage cache.
     *
     * @param cart The EntityMinecart
     * @return The linkage id
     */
    public UUID getLinkageId(EntityMinecart cart) {
        UUID id = cart.getPersistentID();
        if (!cart.isDead)
            carts.put(id, cart);
        return id;
    }

    /**
     * Returns a minecart from a persistent UUID.
     *
     * @param id
     * @return
     */
    @Override
    public EntityMinecart getCartFromUUID(UUID id) {
        EntityMinecart cart = carts.get(id);
        if (cart != null && cart.isDead) {
            carts.remove(id);
            return null;
        }
        return carts.get(id);
    }

    /**
     * Returns the square of the max distance two carts can be and still be
     * linkable.
     *
     * @param cart1
     * @param cart2
     * @return The square of the linkage distance
     */
    private float getLinkageDistanceSq(EntityMinecart cart1, EntityMinecart cart2) {
        float dist = 0;
        if (cart1 instanceof ILinkableCart)
            dist += ((ILinkableCart) cart1).getLinkageDistance(cart2);
        else
            dist += LINKAGE_DISTANCE;
        if (cart2 instanceof ILinkableCart)
            dist += ((ILinkableCart) cart2).getLinkageDistance(cart1);
        else
            dist += LINKAGE_DISTANCE;
        return dist * dist;
    }

    /**
     * Returns true if there is nothing preventing the two carts from being
     * linked.
     *
     * @param cart1
     * @param cart2
     * @return True if can be linked
     */
    private boolean canLinkCarts(EntityMinecart cart1, EntityMinecart cart2) {
        if (cart1 == null || cart2 == null)
            return false;

        if (cart1 == cart2)
            return false;

        if (cart1 instanceof ILinkableCart) {
            ILinkableCart link = (ILinkableCart) cart1;
            if (!link.isLinkable() || !link.canLinkWithCart(cart2))
                return false;
        }

        if (cart2 instanceof ILinkableCart) {
            ILinkableCart link = (ILinkableCart) cart2;
            if (!link.isLinkable() || !link.canLinkWithCart(cart1))
                return false;
        }

        if (areLinked(cart1, cart2))
            return false;

        if (cart1.getDistanceSqToEntity(cart2) > getLinkageDistanceSq(cart1, cart2))
            return false;

        if (!hasFreeLink(cart1) || !hasFreeLink(cart2))
            return false;

        return true;
    }

    /**
     * Creates a link between two carts, but only if there is nothing preventing
     * such a link.
     *
     * @param cart1
     * @param cart2
     * @return True if the link succeeded.
     */
    @Override
    public boolean createLink(EntityMinecart cart1, EntityMinecart cart2) {
        if (canLinkCarts(cart1, cart2)) {
            setLink(cart1, cart2);
            setLink(cart2, cart1);

            if (cart1 instanceof ILinkableCart)
                ((ILinkableCart) cart1).onLinkCreated(cart2);
            if (cart2 instanceof ILinkableCart)
                ((ILinkableCart) cart2).onLinkCreated(cart1);

//            sendLinkInfo(cart1);
//            sendLinkInfo(cart2);
            return true;
        }
        return false;
    }

    private boolean hasFreeLink(EntityMinecart cart) {
        return getLinkedCartA(cart) == null || (hasLinkB(cart) && getLinkedCartB(cart) == null);
    }

    private boolean hasLinkB(EntityMinecart cart) {
        if (cart instanceof ILinkableCart)
            return ((ILinkableCart) cart).hasTwoLinks();
        return true;
    }

    private void setLink(EntityMinecart cart1, EntityMinecart cart2) {
        if (getLinkedCartA(cart1) == null)
            setLinkA(cart1, cart2);
        else if (hasLinkB(cart1) && getLinkedCartB(cart1) == null)
            setLinkB(cart1, cart2);
    }

    public UUID getLinkA(EntityMinecart cart) {
        long high = cart.getEntityData().getLong(LINK_A_HIGH);
        long low = cart.getEntityData().getLong(LINK_A_LOW);
        return new UUID(high, low);
    }

    private void setLinkA(EntityMinecart cart1, EntityMinecart cart2) {
        resetTrain(cart1);
        resetTrain(cart2);
        UUID id = getLinkageId(cart2);
        cart1.getEntityData().setLong(LINK_A_HIGH, id.getMostSignificantBits());
        cart1.getEntityData().setLong(LINK_A_LOW, id.getLeastSignificantBits());
    }

    /**
     * Returns the cart linked to Link A or null if nothing is currently
     * occupying Link A.
     *
     * @param cart The cart for which to get the link
     * @return The linked cart or null
     */
    @Override
    public EntityMinecart getLinkedCartA(EntityMinecart cart) {
        return getCartFromUUID(getLinkA(cart));
    }

    public UUID getLinkB(EntityMinecart cart) {
        long high = cart.getEntityData().getLong(LINK_B_HIGH);
        long low = cart.getEntityData().getLong(LINK_B_LOW);
        return new UUID(high, low);
    }

    private void setLinkB(EntityMinecart cart1, EntityMinecart cart2) {
        if (!hasLinkB(cart1))
            return;
        resetTrain(cart1);
        resetTrain(cart2);
        UUID id = getLinkageId(cart2);
        cart1.getEntityData().setLong(LINK_B_HIGH, id.getMostSignificantBits());
        cart1.getEntityData().setLong(LINK_B_LOW, id.getLeastSignificantBits());
    }

    /**
     * Returns the cart linked to Link B or null if nothing is currently
     * occupying Link B.
     *
     * @param cart The cart for which to get the link
     * @return The linked cart or null
     */
    @Override
    public EntityMinecart getLinkedCartB(EntityMinecart cart) {
        return getCartFromUUID(getLinkB(cart));
    }

    public Train getTrain(EntityMinecart cart) {
        if (cart == null)
            return null;
        Train train = trains.get(getTrainUUID(cart));
        if (train != null && !train.containsCart(cart)) {
            train.releaseTrain();
            trains.remove(train.getUUID());
            train = null;
        }
        if (train == null) {
            train = new Train(cart);
            trains.put(train.getUUID(), train);
        }
        return train;
    }

    public UUID getTrainUUID(EntityMinecart cart) {
        long high = cart.getEntityData().getLong(TRAIN_HIGH);
        long low = cart.getEntityData().getLong(TRAIN_LOW);
        return new UUID(high, low);
    }

    private void resetTrain(EntityMinecart cart) {
        Train train = trains.remove(getTrainUUID(cart));
        if (train != null)
            train.releaseTrain();
    }

    public boolean areInSameTrain(EntityMinecart cart1, EntityMinecart cart2) {
        if (cart1 == null || cart2 == null)
            return false;
        if (cart1 == cart2)
            return true;

        return getTrain(cart1) == getTrain(cart2);
    }

    /**
     * Returns true if the two carts are linked directly to each other.
     *
     * @param cart1
     * @param cart2
     * @return True if linked
     */
    @Override
    public boolean areLinked(EntityMinecart cart1, EntityMinecart cart2) {
        if (cart1 == null || cart2 == null)
            return false;
        if (cart1 == cart2)
            return false;

//        System.out.println("cart2 id = " + getLinkageId(cart2));
//        System.out.println("cart2 A = " + getLinkA(cart2));
//        System.out.println("cart2 B = " + getLinkB(cart2));
//        System.out.println("cart1 id = " + getLinkageId(cart1));
//        System.out.println("cart1 A = " + getLinkA(cart1));
//        System.out.println("cart1 B = " + getLinkB(cart1));
        boolean cart1Linked = false;
        UUID id1 = getLinkageId(cart1);
        UUID id2 = getLinkageId(cart2);
        if (id2.equals(getLinkA(cart1)) || id2.equals(getLinkB(cart1)))
            cart1Linked = true; //            System.out.println("cart1 linked");

        boolean cart2Linked = false;
        if (id1.equals(getLinkA(cart2)) || id1.equals(getLinkB(cart2)))
            cart2Linked = true; //            System.out.println("cart2 linked");

        return cart1Linked && cart2Linked;
    }

    /**
     * Breaks a link between two carts, if any link exists.
     *
     * @param cart1
     * @param cart2
     */
    @Override
    public void breakLink(EntityMinecart cart1, EntityMinecart cart2) {
        UUID link = getLinkageId(cart2);
        if (link.equals(getLinkA(cart1)))
            breakLinkA(cart1);

        if (link.equals(getLinkB(cart1)))
            breakLinkB(cart1);
    }

    /**
     * Breaks all links the passed cart has.
     *
     * @param cart
     */
    @Override
    public void breakLinks(EntityMinecart cart) {
        breakLinkA(cart);
        breakLinkB(cart);
    }

    /**
     * Break only link A.
     *
     * @param cart
     */
    @Override
    public void breakLinkA(EntityMinecart cart) {
        resetTrain(cart);
        UUID link = getLinkA(cart);
        cart.getEntityData().setLong(LINK_A_HIGH, 0);
        cart.getEntityData().setLong(LINK_A_LOW, 0);
        EntityMinecart other = getCartFromUUID(link);
        if (other != null)
            breakLink(other, cart);
        if (cart instanceof ILinkableCart)
            ((ILinkableCart) cart).onLinkBroken(other);

        printDebug("Carts {0}({1}) and {2}({3}) unlinked (A).", getLinkageId(cart), cart, link, other != null ? other : "null");
    }

    /**
     * Break only link B.
     *
     * @param cart
     */
    @Override
    public void breakLinkB(EntityMinecart cart) {
        resetTrain(cart);
        UUID link = getLinkB(cart);
        cart.getEntityData().setLong(LINK_B_HIGH, 0);
        cart.getEntityData().setLong(LINK_B_LOW, 0);
        EntityMinecart other = getCartFromUUID(link);
        if (other != null)
            breakLink(other, cart);
        if (cart instanceof ILinkableCart)
            ((ILinkableCart) cart).onLinkBroken(other);

        printDebug("Carts {0}({1}) and {2}({3}) unlinked (B).", getLinkageId(cart), cart, link, other != null ? other : "null");
    }

    /**
     * Counts how many carts are in the train.
     *
     * @param cart Any cart in the train
     * @return The number of carts in the train
     */
    @Override
    public int countCartsInTrain(EntityMinecart cart) {
        Train train = getTrain(cart);
        return train.size();
    }

    @Override
    public Iterable<EntityMinecart> getCartsInTrain(EntityMinecart cart) {
        return getTrain(cart);
    }

}
TOP

Related Classes of mods.railcraft.common.carts.LinkageManager

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.