Package crazypants.enderio.conduit.redstone

Source Code of crazypants.enderio.conduit.redstone.RedstoneConduit

package crazypants.enderio.conduit.redstone;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.minecraft.block.Block;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.IIcon;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import crazypants.enderio.EnderIO;
import crazypants.enderio.conduit.AbstractConduit;
import crazypants.enderio.conduit.AbstractConduitNetwork;
import crazypants.enderio.conduit.ConduitUtil;
import crazypants.enderio.conduit.IConduit;
import crazypants.enderio.conduit.geom.CollidableComponent;
import crazypants.render.IconUtil;
import crazypants.util.BlockCoord;
import crazypants.util.DyeColor;
import powercrystals.minefactoryreloaded.api.rednet.IRedNetOutputNode;

public class RedstoneConduit extends AbstractConduit implements IRedstoneConduit {

  static final Map<String, IIcon> ICONS = new HashMap<String, IIcon>();

  @SideOnly(Side.CLIENT)
  public static void initIcons() {
    IconUtil.addIconProvider(new IconUtil.IIconProvider() {

      @Override
      public void registerIcons(IIconRegister register) {
        ICONS.put(KEY_CORE_OFF_ICON, register.registerIcon(KEY_CORE_OFF_ICON));
        ICONS.put(KEY_CORE_ON_ICON, register.registerIcon(KEY_CORE_ON_ICON));
        ICONS.put(KEY_CONDUIT_ICON, register.registerIcon(KEY_CONDUIT_ICON));
        ICONS.put(KEY_TRANSMISSION_ICON, register.registerIcon(KEY_TRANSMISSION_ICON));
      }

      @Override
      public int getTextureType() {
        return 0;
      }

    });
  }

  protected RedstoneConduitNetwork network;

  protected final List<Set<Signal>> externalSignals = new ArrayList<Set<Signal>>();

  protected boolean neighbourDirty = true;

  public RedstoneConduit() {
    for (ForgeDirection ignored : ForgeDirection.VALID_DIRECTIONS) {
      externalSignals.add(new HashSet<Signal>());
    }
  }

  @Override
  public ItemStack createItem() {
    return new ItemStack(EnderIO.itemRedstoneConduit, 1, 0);
  }

  @Override
  public Class<? extends IConduit> getBaseConduitType() {
    return IRedstoneConduit.class;
  }

  @Override
  public AbstractConduitNetwork<IRedstoneConduit, IRedstoneConduit> getNetwork() {
    return network;
  }

  @Override
  public boolean setNetwork(AbstractConduitNetwork<?, ?> network) {
    this.network = (RedstoneConduitNetwork) network;
    return true;
  }

  @Override
  public boolean canConnectToExternal(ForgeDirection direction, boolean ignoreDisabled) {
    return false;
  }

  @Override
  public void updateNetwork() {
    World world = getBundle().getEntity().getWorldObj();
    if(world != null) {
      updateNetwork(world);
    }
  }

  protected boolean acceptSignalsForDir(ForgeDirection dir) {
    BlockCoord loc = getLocation().getLocation(dir);
    return ConduitUtil.getConduit(getBundle().getEntity().getWorldObj(), loc.x, loc.y, loc.z, IRedstoneConduit.class) == null;
  }

  @Override
  public Set<Signal> getNetworkInputs() {
    return getNetworkInputs(null);
  }

  @Override
  public Set<Signal> getNetworkInputs(ForgeDirection side) {
    if(network != null) {
      network.setNetworkEnabled(false);
    }

    Set<Signal> res = new HashSet<Signal>();
    for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) {
      if((side == null || dir == side) && acceptSignalsForDir(dir)) {
        int input = getExternalPowerLevel(dir);
        if(input > 1) { // need to degrade external signals by one as they
                        // enter
          BlockCoord loc = getLocation().getLocation(dir);
          Signal signal = new Signal(loc.x, loc.y, loc.z, dir, input - 1, getSignalColor(dir));
          res.add(signal);
        }

        if (Loader.isModLoaded("MineFactoryReloaded")) {
          // Add stored RedNet input. See onInputsChanged below for more information.
          res.addAll(externalSignals.get(dir.ordinal()));

          // Manually check if neighbors are outputting bundled redstone signals.
          // This is required to directly support other blocks implementing the
          // RedNet API, without requiring a piece of RedNet cable in-between.
          int[] bundledInput = getExternalBundledPowerLevel(dir);
          if(bundledInput != null) {
            BlockCoord loc = getLocation().getLocation(dir);
            for (int subnet = 0; subnet < bundledInput.length; ++subnet) {
              if(bundledInput[subnet] > 1) { // force signal strength reduction to avoid cycles
                int color = convertColorForRedNet(subnet);
                Signal signal = new Signal(loc.x, loc.y, loc.z, dir, bundledInput[subnet] - 1, DyeColor.fromIndex(color));
                res.add(signal);
              }
            }
          }
        }
      }
    }

    if(network != null) {
      network.setNetworkEnabled(true);
    }

    return res;
  }

  @Override
  public DyeColor getSignalColor(ForgeDirection dir) {
    return DyeColor.RED;
  }

  @Override
  public Set<Signal> getNetworkOutputs(ForgeDirection side) {
    if(network == null) {
      return Collections.emptySet();
    }
    return network.getSignals();
  }

  @Override
  public boolean onNeighborBlockChange(Block blockId) {   
    World world = getBundle().getEntity().getWorldObj();
    if(world.isRemote) {
      return false;
    }
    boolean res = super.onNeighborBlockChange(blockId);
    if(network == null || network.updatingNetwork) {
      return false;
    }
    neighbourDirty |= blockId != EnderIO.blockConduitBundle;
    return res;
  }

  @Override
  public void updateEntity(World world) {
    super.updateEntity(world);
    if(!world.isRemote && neighbourDirty) {
      network.destroyNetwork();
      updateNetwork(world);
      neighbourDirty = false;
    }
  }

  //returns 16 for string power inputs
  protected int getExternalPowerLevel(ForgeDirection dir) {
    World world = getBundle().getEntity().getWorldObj();
    BlockCoord loc = getLocation();
    loc = loc.getLocation(dir);

    int strong = world.isBlockProvidingPowerTo(loc.x, loc.y, loc.z, dir.ordinal());
    if(strong > 0) {
      return 16;
    }

    int res = world.getIndirectPowerLevelTo(loc.x, loc.y, loc.z, dir.ordinal());
    if(res < 15 && world.getBlock(loc.x, loc.y, loc.z) == Blocks.redstone_wire) {
      int wireIn = world.getBlockMetadata(loc.x, loc.y, loc.z);
      res = Math.max(res, wireIn);
    }
    return res;
  }

  protected int[] getExternalBundledPowerLevel(ForgeDirection dir) {
    World world = getBundle().getEntity().getWorldObj();
    BlockCoord loc = getLocation();
    loc = loc.getLocation(dir);

    Block block = world.getBlock(loc.x, loc.y, loc.z);
    if(block instanceof IRedNetOutputNode) {
      return ((IRedNetOutputNode) block).getOutputValues(world, loc.x, loc.y, loc.z, dir.getOpposite());
    }

    return null;
  }

  @Override
  public int isProvidingStrongPower(ForgeDirection toDirection) {
    return isProvidingWeakPower(toDirection);
  }

  @Override
  public int isProvidingWeakPower(ForgeDirection toDirection) {
    if(network == null || !network.isNetworkEnabled()) {
      return 0;
    }
    int result = 0;
    for (Signal signal : getNetworkOutputs(toDirection.getOpposite())) {
      result = Math.max(result, signal.strength);
    }
    return result;
  }

  @Override
  public IIcon getTextureForState(CollidableComponent component) {
    if(component.dir == ForgeDirection.UNKNOWN) {
      return isActive() ? ICONS.get(KEY_CORE_ON_ICON) : ICONS.get(KEY_CORE_OFF_ICON);
    }
    return isActive() ? ICONS.get(KEY_TRANSMISSION_ICON) : ICONS.get(KEY_CONDUIT_ICON);
  }

  @Override
  public IIcon getTransmitionTextureForState(CollidableComponent component) {
    return null;
  }

  @Override
  public String toString() {
    return "RedstoneConduit [network=" + network + " connections=" + conduitConnections + " active=" + active + "]";
  }

  @Override
  public int[] getOutputValues(World world, int x, int y, int z, ForgeDirection side) {
    int[] result = new int[16];

    Set<Signal> outs = network != null ? network.getSignals() : null;
    if(outs != null) {
      BlockCoord loc = getLocation().getLocation(side);
      for (Signal s : outs) {
        // Avoid "feedback loops", i.e. don't report an output on a side where
        // we have an input (otherwise a RedNet cable connected to a conduit
        // will keep a signal high, even if the original source vanishes).
        // Note that it's still possible to get loops if there are two
        // connections between a conduit set and a RedNet network. I'm not
        // sure there's anything we could do to avoid this, though, nor am I
        // convinced we should.
        if(s.dir != side || s.x != loc.x || s.y != loc.y || s.z != loc.z) {
          int subnet = convertColorForRedNet(s.color.ordinal());
          result[subnet] = s.strength;
        }
      }
    }

    return result;
  }

  @Override
  public int getOutputValue(World world, int x, int y, int z, ForgeDirection side, int subnet) {
    Set<Signal> outs = network != null ? network.getSignals() : null;
    if(outs != null) {
      BlockCoord loc = getLocation().getLocation(side);
      int color = convertColorForRedNet(subnet);
      for (Signal s : outs) {
        // Avoid "feedback loops", see comment in getOutputValues.
        if(s.dir != side || s.x != loc.x || s.y != loc.y || s.z != loc.z) {
          if(s.color.ordinal() == color) {
            return s.strength;
          }
        }
      }
    }

    return 0;
  }

  @Override
  public void onInputsChanged(World world, int x, int y, int z, ForgeDirection side, int[] inputValues) {
    // Check if anything changed, if so mark neighbor dirty to trigger an
    // update in the next tick. We have to iterate over the colors in the
    // outer loop to make sure we check all of them, because for channels
    // with zero signal strength no signals are stored.
    Set<Signal> inputs = getNetworkInputs(side);
    externalSignals.get(side.ordinal()).clear();
    BlockCoord loc = getLocation().getLocation(side);
    for (int subnet = 0; subnet < inputValues.length; ++subnet) {
      int color = convertColorForRedNet(subnet);
      int newInput = inputValues[subnet];
      int oldInput = 0;
      for (Signal input : inputs) {
        if(input.color.ordinal() == color) {
          oldInput = input.strength;
          break;
        }
      }

      neighbourDirty |= oldInput != newInput;

      // Store external inputs to allow regenerating the global list of signals
      // in getNetworkInputs. This is required for RedNet cables to work, e.g.
      if(newInput > 1) { // force signal strength reduction to avoid cycles
        externalSignals.get(side.ordinal()).add(new Signal(loc.x, loc.y, loc.z, side, newInput - 1, DyeColor.fromIndex(color)));
      }
    }
  }
 
  @Override
  public boolean onNeighborChange(IBlockAccess world, int x, int y, int z, int tileX, int tileY, int tileZ) {   
    return false;
  }

  // RedNet refers to colors in inverse order...
  private static int convertColorForRedNet(int colorOrSubnet) {
    return 15 - colorOrSubnet;
  }
}
TOP

Related Classes of crazypants.enderio.conduit.redstone.RedstoneConduit

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.