package crazypants.enderio.conduit.power; import java.util.ArrayList; import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import net.minecraft.block.Block; import net.minecraft.client.renderer.texture.IIconRegister; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IIcon; import net.minecraft.util.MathHelper; import net.minecraft.world.World; import net.minecraftforge.common.util.ForgeDirection; import com.enderio.core.client.render.BoundingBox; import com.enderio.core.client.render.IconUtil; import com.enderio.core.common.util.DyeColor; import com.enderio.core.common.vecmath.Vector3d; import crazypants.enderio.EnderIO; import crazypants.enderio.conduit.AbstractConduit; import crazypants.enderio.conduit.AbstractConduitNetwork; import crazypants.enderio.conduit.ConduitUtil; import crazypants.enderio.conduit.ConnectionMode; import crazypants.enderio.conduit.IConduit; import crazypants.enderio.conduit.IConduitBundle; import crazypants.enderio.conduit.RaytraceResult; import crazypants.enderio.conduit.geom.CollidableCache.CacheKey; import crazypants.enderio.conduit.geom.CollidableComponent; import crazypants.enderio.conduit.geom.ConduitGeometryUtil; import crazypants.enderio.config.Config; import crazypants.enderio.item.PacketConduitProbe; import crazypants.enderio.machine.RedstoneControlMode; import crazypants.enderio.power.BasicCapacitor; import crazypants.enderio.power.ICapacitor; import crazypants.enderio.power.IPowerInterface; import crazypants.enderio.power.PowerHandlerUtil; import crazypants.enderio.tool.ToolUtil; public class PowerConduit extends AbstractConduit implements IPowerConduit { static final Map<String, IIcon> ICONS = new HashMap<String, IIcon>(); private static ICapacitor[] capacitors; static final String[] POSTFIX = new String[] { "", "Enhanced", "Ender" }; static ICapacitor[] getCapacitors() { if(capacitors == null) { capacitors = new BasicCapacitor[] { new BasicCapacitor(Config.powerConduitTierOneRF, Config.powerConduitTierOneRF), new BasicCapacitor(Config.powerConduitTierTwoRF, Config.powerConduitTierTwoRF), new BasicCapacitor(Config.powerConduitTierThreeRF, Config.powerConduitTierThreeRF) }; } return capacitors; } static ItemStack createItemStackForSubtype(int subtype) { ItemStack result = new ItemStack(EnderIO.itemPowerConduit, 1, subtype); return result; } public static void initIcons() { IconUtil.addIconProvider(new IconUtil.IIconProvider() { @Override public void registerIcons(IIconRegister register) { for (String pf : POSTFIX) { ICONS.put(ICON_KEY + pf, register.registerIcon(ICON_KEY + pf)); ICONS.put(ICON_KEY_INPUT + pf, register.registerIcon(ICON_KEY_INPUT + pf)); ICONS.put(ICON_KEY_OUTPUT + pf, register.registerIcon(ICON_KEY_OUTPUT + pf)); ICONS.put(ICON_CORE_KEY + pf, register.registerIcon(ICON_CORE_KEY + pf)); } ICONS.put(ICON_TRANSMISSION_KEY, register.registerIcon(ICON_TRANSMISSION_KEY)); } @Override public int getTextureType() { return 0; } }); } public static final float WIDTH = 0.075f; public static final float HEIGHT = 0.075f; public static final Vector3d MIN = new Vector3d(0.5f - WIDTH, 0.5 - HEIGHT, 0.5 - WIDTH); public static final Vector3d MAX = new Vector3d(MIN.x + WIDTH, MIN.y + HEIGHT, MIN.z + WIDTH); public static final BoundingBox BOUNDS = new BoundingBox(MIN, MAX); protected PowerConduitNetwork network; private int energyStoredRF; private int subtype; protected final EnumMap<ForgeDirection, RedstoneControlMode> rsModes = new EnumMap<ForgeDirection, RedstoneControlMode>(ForgeDirection.class); protected final EnumMap<ForgeDirection, DyeColor> rsColors = new EnumMap<ForgeDirection, DyeColor>(ForgeDirection.class); protected EnumMap<ForgeDirection, Long> recievedTicks; private final Map<ForgeDirection, Integer> externalRedstoneSignals = new HashMap<ForgeDirection, Integer>(); private boolean redstoneStateDirty = true; public PowerConduit() { } public PowerConduit(int meta) { this.subtype = meta; } @Override public boolean getConnectionsDirty() { return connectionsDirty; } @Override public boolean onBlockActivated(EntityPlayer player, RaytraceResult res, List<RaytraceResult> all) { DyeColor col = DyeColor.getColorFromDye(player.getCurrentEquippedItem()); if(ConduitUtil.isProbeEquipped(player)) { if(!player.worldObj.isRemote) { new PacketConduitProbe().sendInfoMessage(player, this); } return true; } else if(col != null && res.component != null && isColorBandRendered(res.component.dir)) { setExtractionSignalColor(res.component.dir, col); return true; } else if(ToolUtil.isToolEquipped(player)) { if(!getBundle().getEntity().getWorldObj().isRemote) { if(res != null && res.component != null) { ForgeDirection connDir = res.component.dir; ForgeDirection faceHit = ForgeDirection.getOrientation(res.movingObjectPosition.sideHit); if(connDir == ForgeDirection.UNKNOWN || connDir == faceHit) { if(getConnectionMode(faceHit) == ConnectionMode.DISABLED) { setConnectionMode(faceHit, getNextConnectionMode(faceHit)); return true; } // Attempt to join networks return ConduitUtil.joinConduits(this, faceHit); } else if(externalConnections.contains(connDir)) { setConnectionMode(connDir, getNextConnectionMode(connDir)); return true; } else if(containsConduitConnection(connDir)) { ConduitUtil.disconectConduits(this, connDir); return true; } } } } return false; } private boolean isColorBandRendered(ForgeDirection dir) { return getConnectionMode(dir) != ConnectionMode.DISABLED && getExtractionRedstoneMode(dir) != RedstoneControlMode.IGNORE; } @Override public ICapacitor getCapacitor() { return getCapacitors()[subtype]; } @Override public void setExtractionRedstoneMode(RedstoneControlMode mode, ForgeDirection dir) { rsModes.put(dir, mode); setClientStateDirty(); } @Override public RedstoneControlMode getExtractionRedstoneMode(ForgeDirection dir) { RedstoneControlMode res = rsModes.get(dir); if(res == null) { res = RedstoneControlMode.IGNORE; } return res; } @Override public void setExtractionSignalColor(ForgeDirection dir, DyeColor col) { rsColors.put(dir, col); setClientStateDirty(); } @Override public DyeColor getExtractionSignalColor(ForgeDirection dir) { DyeColor res = rsColors.get(dir); if(res == null) { res = DyeColor.RED; } return res; } @Override protected void readTypeSettings(ForgeDirection dir, NBTTagCompound dataRoot) { setExtractionSignalColor(dir, DyeColor.values()[dataRoot.getShort("extractionSignalColor")]); setExtractionRedstoneMode(RedstoneControlMode.values()[dataRoot.getShort("extractionRedstoneMode")], dir); } @Override protected void writeTypeSettingsToNbt(ForgeDirection dir, NBTTagCompound dataRoot) { dataRoot.setShort("extractionSignalColor", (short)getExtractionSignalColor(dir).ordinal()); dataRoot.setShort("extractionRedstoneMode", (short)getExtractionRedstoneMode(dir).ordinal()); } @Override public void writeToNBT(NBTTagCompound nbtRoot) { super.writeToNBT(nbtRoot); nbtRoot.setShort("subtype", (short) subtype); nbtRoot.setInteger("energyStoredRF", energyStoredRF); for (Entry<ForgeDirection, RedstoneControlMode> entry : rsModes.entrySet()) { if(entry.getValue() != null) { short ord = (short) entry.getValue().ordinal(); nbtRoot.setShort("pRsMode." + entry.getKey().name(), ord); } } for (Entry<ForgeDirection, DyeColor> entry : rsColors.entrySet()) { if(entry.getValue() != null) { short ord = (short) entry.getValue().ordinal(); nbtRoot.setShort("pRsCol." + entry.getKey().name(), ord); } } } @Override public void readFromNBT(NBTTagCompound nbtRoot, short nbtVersion) { super.readFromNBT(nbtRoot, nbtVersion); subtype = nbtRoot.getShort("subtype"); if(nbtRoot.hasKey("energyStored")) { nbtRoot.setInteger("energyStoredRF", (int)(nbtRoot.getFloat("energyStored") * 10)); } setEnergyStored(nbtRoot.getInteger("energyStoredRF")); for (ForgeDirection dir : ForgeDirection.VALID_DIRECTIONS) { String key = "pRsMode." + dir.name(); if(nbtRoot.hasKey(key)) { short ord = nbtRoot.getShort(key); if(ord >= 0 && ord < RedstoneControlMode.values().length) { rsModes.put(dir, RedstoneControlMode.values()[ord]); } } key = "pRsCol." + dir.name(); if(nbtRoot.hasKey(key)) { short ord = nbtRoot.getShort(key); if(ord >= 0 && ord < DyeColor.values().length) { rsColors.put(dir, DyeColor.values()[ord]); } } } } @Override public void onTick() { } @Override public int getEnergyStored() { return energyStoredRF; } @Override public void setEnergyStored(int energyStored) { energyStoredRF = MathHelper.clamp_int(energyStored, 0, getMaxEnergyStored()); } private boolean isRedstoneEnabled(ForgeDirection dir) { boolean result; RedstoneControlMode mode = getExtractionRedstoneMode(dir); if(mode == RedstoneControlMode.NEVER) { return false; } if(mode == RedstoneControlMode.IGNORE) { return true; } DyeColor col = getExtractionSignalColor(dir); int signal = ConduitUtil.getInternalSignalForColor(getBundle(), col); int exSig = getExternalRedstoneSignalForDir(dir); boolean res; if(mode == RedstoneControlMode.OFF) { //if checking for no signal, must be no signal from both res = mode.isConditionMet(mode, signal) && (col != DyeColor.RED || mode.isConditionMet(mode, exSig)); } else { //if checking for a signal, either is fine res = mode.isConditionMet(mode, signal) || (col == DyeColor.RED && mode.isConditionMet(mode, exSig)); } return res; } private int getExternalRedstoneSignalForDir(ForgeDirection dir) { if(redstoneStateDirty) { externalRedstoneSignals.clear(); redstoneStateDirty = false; } Integer cached = externalRedstoneSignals.get(dir); int result; if(cached == null) { TileEntity te = getBundle().getEntity(); result = te.getWorldObj().getStrongestIndirectPower(te.xCoord, te.yCoord, te.zCoord); externalRedstoneSignals.put(dir, result); } else { result = cached; } return result; } @Override public int getMaxEnergyRecieved(ForgeDirection dir) { ConnectionMode mode = getConnectionMode(dir); if(mode == ConnectionMode.OUTPUT || mode == ConnectionMode.DISABLED || !isRedstoneEnabled(dir)) { return 0; } return getCapacitor().getMaxEnergyReceived(); } @Override public int getMaxEnergyExtracted(ForgeDirection dir) { ConnectionMode mode = getConnectionMode(dir); if(mode == ConnectionMode.INPUT || mode == ConnectionMode.DISABLED || !isRedstoneEnabled(dir)) { return 0; } if(recievedRfThisTick(dir)) { return 0; } return getCapacitor().getMaxEnergyExtracted(); } private boolean recievedRfThisTick(ForgeDirection dir) { if(recievedTicks == null || dir == null || recievedTicks.get(dir) == null || getBundle() == null || getBundle().getWorld() == null) { return false; } long curTick = getBundle().getWorld().getTotalWorldTime(); long recT = recievedTicks.get(dir); if(curTick - recT <= 5) { return true; } return false; } @Override public boolean onNeighborBlockChange(Block blockId) { redstoneStateDirty = true; if(network != null && network.powerManager != null) { network.powerManager.receptorsChanged(); } return super.onNeighborBlockChange(blockId); } @Override public void setConnectionMode(ForgeDirection dir, ConnectionMode mode) { super.setConnectionMode(dir, mode); recievedTicks = null; } @Override public int receiveEnergy(ForgeDirection from, int maxReceive, boolean simulate) { if(getMaxEnergyRecieved(from) == 0 || maxReceive <= 0) { return 0; } int freeSpace = getMaxEnergyStored() - getEnergyStored(); int result = (int) Math.min(maxReceive, freeSpace); if(!simulate && result > 0) { setEnergyStored(getEnergyStored() + result); if(getBundle() != null) { if(recievedTicks == null) { recievedTicks = new EnumMap<ForgeDirection, Long>(ForgeDirection.class); } recievedTicks.put(from, getBundle().getWorld().getTotalWorldTime()); } } return result; } @Override public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) { return 0; } @Override public boolean canConnectEnergy(ForgeDirection from) { return true; } @Override public int getEnergyStored(ForgeDirection from) { return getEnergyStored(); } @Override public int getMaxEnergyStored(ForgeDirection from) { return getMaxEnergyStored(); } @Override public AbstractConduitNetwork<?, ?> getNetwork() { return network; } @Override public boolean setNetwork(AbstractConduitNetwork<?, ?> network) { this.network = (PowerConduitNetwork) network; return true; } @Override public boolean canConnectToExternal(ForgeDirection direction, boolean ignoreDisabled) { IPowerInterface rec = getExternalPowerReceptor(direction); return rec != null && rec.canConduitConnect(direction); } @Override public boolean canConnectToConduit(ForgeDirection direction, IConduit conduit) { boolean res = super.canConnectToConduit(direction, conduit); if(!res) { return false; } if(Config.powerConduitCanDifferentTiersConnect) { return res; } if( !(conduit instanceof IPowerConduit)) { return false; } IPowerConduit pc = (IPowerConduit)conduit; return pc.getMaxEnergyStored() == getMaxEnergyStored(); } @Override public void externalConnectionAdded(ForgeDirection direction) { super.externalConnectionAdded(direction); if(network != null) { TileEntity te = bundle.getEntity(); network.powerReceptorAdded(this, direction, te.xCoord + direction.offsetX, te.yCoord + direction.offsetY, te.zCoord + direction.offsetZ, getExternalPowerReceptor(direction)); } } @Override public void externalConnectionRemoved(ForgeDirection direction) { super.externalConnectionRemoved(direction); if(network != null) { TileEntity te = bundle.getEntity(); network.powerReceptorRemoved(te.xCoord + direction.offsetX, te.yCoord + direction.offsetY, te.zCoord + direction.offsetZ); } } @Override public IPowerInterface getExternalPowerReceptor(ForgeDirection direction) { TileEntity te = bundle.getEntity(); World world = te.getWorldObj(); if(world == null) { return null; } TileEntity test = world.getTileEntity(te.xCoord + direction.offsetX, te.yCoord + direction.offsetY, te.zCoord + direction.offsetZ); if(test == null) { return null; } if(test instanceof IConduitBundle) { return null; } return PowerHandlerUtil.create(test); } @Override public ItemStack createItem() { return createItemStackForSubtype(subtype); } @Override public Class<? extends IConduit> getBaseConduitType() { return IPowerConduit.class; } // Rendering @Override public IIcon getTextureForState(CollidableComponent component) { if(component.dir == ForgeDirection.UNKNOWN) { return ICONS.get(ICON_CORE_KEY + POSTFIX[subtype]); } if(COLOR_CONTROLLER_ID.equals(component.data)) { return IconUtil.whiteTexture; } return ICONS.get(ICON_KEY + POSTFIX[subtype]); } @Override public IIcon getTextureForInputMode() { return ICONS.get(ICON_KEY_INPUT + POSTFIX[subtype]); } @Override public IIcon getTextureForOutputMode() { return ICONS.get(ICON_KEY_OUTPUT + POSTFIX[subtype]); } @Override public IIcon getTransmitionTextureForState(CollidableComponent component) { return null; } @Override public Collection<CollidableComponent> createCollidables(CacheKey key) { Collection<CollidableComponent> baseCollidables = super.createCollidables(key); if(key.dir == ForgeDirection.UNKNOWN) { return baseCollidables; } BoundingBox bb = ConduitGeometryUtil.instance.createBoundsForConnectionController(key.dir, key.offset); CollidableComponent cc = new CollidableComponent(IPowerConduit.class, bb, key.dir, COLOR_CONTROLLER_ID); List<CollidableComponent> result = new ArrayList<CollidableComponent>(); result.addAll(baseCollidables); result.add(cc); return result; } @Override public int getMaxEnergyStored() { return getCapacitors()[subtype].getMaxEnergyStored(); } @Override public boolean displayPower() { return true; } }