Skip to content

Commit

Permalink
Electric pipes rework (GregTechCEu#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
brachy84 authored Aug 15, 2021
1 parent 757264a commit 7a9b1db
Show file tree
Hide file tree
Showing 11 changed files with 394 additions and 296 deletions.
34 changes: 28 additions & 6 deletions src/main/java/gregtech/api/capability/IEnergyContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,32 @@
public interface IEnergyContainer {

/**
* This method is basically {@link #changeEnergy(long)}, but it also handles amperes.
* This method should always be used when energy is passed between blocks.
*
* @param voltage amount of energy packets (energy to add / input voltage)
* @param amperage packet size (energy to add / input amperage)
* @return amount of used amperes. 0 if not accepted anything.
*/
long acceptEnergyFromNetwork(EnumFacing side, long voltage, long amperage);

/**
* @return if this container accepts energy from the given side
*/
boolean inputsEnergy(EnumFacing side);

/**
* @return if this container can output energy to the given side
*/
default boolean outputsEnergy(EnumFacing side) {
return false;
}

/**
* This changes the amount stored.
* <b>This should only be used internally</b> (f.e. draining while working or filling while generating).
* For transfer between blocks use {@link #acceptEnergyFromNetwork(EnumFacing, long, long)}!!!
*
* @param differenceAmount amount of energy to add (>0) or remove (<0)
* @return amount of energy added or removed
*/
Expand All @@ -41,45 +56,52 @@ default long removeEnergy(long energyToRemove) {
return changeEnergy(-energyToRemove);
}

/**
* @return the maximum amount of energy that can be inserted
*/
default long getEnergyCanBeInserted() {
return getEnergyCapacity() - getEnergyStored();
}

/**
* Gets the stored electric energy
* @return amount of currently stored energy
*/
long getEnergyStored();

/**
* Gets the largest electric energy capacity
* @return maximum amount of storable energy
*/
long getEnergyCapacity();

/**
* Gets the amount of energy packets per tick.
* @return maximum amount of outputable energy packets per tick
*/
default long getOutputAmperage() {
return 0L;
}

/**
* Gets the output in energy units per energy packet.
* @return output energy packet size
*/
default long getOutputVoltage() {
return 0L;
}

/**
* Gets the amount of energy packets this machine can receive
* @return maximum amount of receivable energy packets per tick
*/
long getInputAmperage();

/**
* Gets the maximum voltage this machine can receive in one energy packet.
* @return output energy packet size
* Overflowing this value will explode machine.
*/
long getInputVoltage();

/**
* @return true if information like energy capacity should be hidden from TOP.
* Useful for cables
*/
default boolean isOneProbeHidden() {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class EnergyContainerBatteryBuffer extends MTETrait implements IEnergyCon

private final BitSet batterySlotsUsedThisTick = new BitSet();
private final int tier;
private long amps = 0;

public EnergyContainerBatteryBuffer(MetaTileEntity metaTileEntity, int tier) {
super(metaTileEntity);
Expand All @@ -31,11 +32,14 @@ public EnergyContainerBatteryBuffer(MetaTileEntity metaTileEntity, int tier) {

@Override
public long acceptEnergyFromNetwork(EnumFacing side, long voltage, long amperage) {
long initialAmperage = amperage;
long usedAmps = 0;
amperage -= amps;
if(amperage <= 0)
return 0;
if (side == null || inputsEnergy(side)) {
if (voltage > getInputVoltage()) {
GTUtility.doOvervoltageExplosion(metaTileEntity, voltage);
return Math.min(amperage, getInputAmperage());
return Math.min(amperage, getInputAmperage() - amps);
}
IItemHandlerModifiable inventory = getInventory();
for (int i = 0; i < inventory.getSlots(); i++) {
Expand All @@ -47,15 +51,15 @@ public long acceptEnergyFromNetwork(EnumFacing side, long voltage, long amperage
chargeItemWithVoltage(electricItem, voltage, getTier(), false);
inventory.setStackInSlot(i, batteryStack);
this.batterySlotsUsedThisTick.set(i);
if (--amperage == 0) break;
if(++usedAmps == amperage) break;
}
}
}
long amperageUsed = initialAmperage - amperage;
if (amperageUsed > 0L) {
if (usedAmps > 0L) {
notifyEnergyListener(false);
}
return amperageUsed;
amps += usedAmps;
return usedAmps;
}

private static boolean chargeItemWithVoltage(IElectricItem electricItem, long voltage, int tier, boolean simulate) {
Expand All @@ -73,6 +77,7 @@ private static long chargeItem(IElectricItem electricItem, long amount, int tier

@Override
public void update() {
amps = 0;
if (!metaTileEntity.getWorld().isRemote) {
this.batterySlotsUsedThisTick.clear();
EnumFacing outFacing = metaTileEntity.getFrontFacing();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class EnergyContainerHandler extends MTETrait implements IEnergyContainer
private Predicate<EnumFacing> sideInputCondition;
private Predicate<EnumFacing> sideOutputCondition;

private long amps = 0;

public EnergyContainerHandler(MetaTileEntity tileEntity, long maxCapacity, long maxInputVoltage, long maxInputAmperage, long maxOutputVoltage, long maxOutputAmperage) {
super(tileEntity);
this.maxCapacity = maxCapacity;
Expand Down Expand Up @@ -133,6 +135,7 @@ public boolean dischargeOrRechargeEnergyContainers(IItemHandlerModifiable itemHa

@Override
public void update() {
amps = 0;
if (getMetaTileEntity().getWorld().isRemote)
return;
if (getEnergyStored() >= getOutputVoltage() && getOutputVoltage() > 0 && getOutputAmperage() > 0) {
Expand All @@ -159,16 +162,18 @@ public void update() {

@Override
public long acceptEnergyFromNetwork(EnumFacing side, long voltage, long amperage) {
if(amps >= getInputAmperage()) return 0;
long canAccept = getEnergyCapacity() - getEnergyStored();
if (voltage > 0L && amperage > 0L && (side == null || inputsEnergy(side))) {
if (voltage > 0L && (side == null || inputsEnergy(side))) {
if (voltage > getInputVoltage()) {
GTUtility.doOvervoltageExplosion(metaTileEntity, voltage);
return Math.min(amperage, getInputAmperage());
return Math.min(amperage, getInputAmperage() - amps);
}
if (canAccept >= voltage) {
long amperesAccepted = Math.min(canAccept / voltage, Math.min(amperage, getInputAmperage()));
long amperesAccepted = Math.min(canAccept / voltage, Math.min(amperage, getInputAmperage() - amps));
if (amperesAccepted > 0) {
setEnergyStored(getEnergyStored() + voltage * amperesAccepted);
amps += amperesAccepted;
return amperesAccepted;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
import gregtech.api.GTValues;
import gregtech.api.capability.impl.EnergyContainerHandler;
import gregtech.api.capability.impl.FilteredFluidHandler;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.capability.impl.RecipeLogicEnergy;
Expand Down Expand Up @@ -42,6 +43,23 @@ protected RecipeLogicEnergy createWorkable(RecipeMap<?> recipeMap) {
return new RecipeLogicEnergy(this, recipeMap, () -> energyContainer);
}

@Override
protected void reinitializeEnergyContainer() {
long tierVoltage = GTValues.V[getTier()];
if (isEnergyEmitter()) {
this.energyContainer = EnergyContainerHandler.emitterContainer(this,
tierVoltage * 64L, tierVoltage, getMaxInputOutputAmperage());
} else this.energyContainer = new EnergyContainerHandler(this, tierVoltage * 64L, tierVoltage, 2, 0L, 0L) {
@Override
public long getInputAmperage() {
if(getEnergyCapacity() / 2 > getEnergyStored() && workable.isActive()) {
return 2;
}
return 1;
}
};
}

@Override
protected long getMaxInputOutputAmperage() {
return 2L;
Expand Down
24 changes: 18 additions & 6 deletions src/main/java/gregtech/common/pipelike/cable/BlockCable.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
import gregtech.api.unification.material.MaterialRegistry;
import gregtech.api.unification.material.properties.WireProperties;
import gregtech.api.util.GTUtility;
import gregtech.common.ConfigHolder;
import gregtech.common.pipelike.cable.net.EnergyNet;
import gregtech.common.pipelike.cable.net.WorldENet;
import gregtech.common.pipelike.cable.tile.TileEntityCable;
import gregtech.common.pipelike.cable.tile.TileEntityCableTickable;
import gregtech.common.pipelike.fluidpipe.net.FluidPipeNet;
import gregtech.common.render.CableRenderer;
import gregtech.common.tools.DamageValues;
import net.minecraft.block.Block;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
Expand Down Expand Up @@ -111,6 +112,17 @@ public int onPipeToolUsed(ItemStack stack, EnumFacing coverSide, IPipeTile<Insul
return -1;
}

@Override
public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) {
super.neighborChanged(state, worldIn, pos, blockIn, fromPos);
if (!worldIn.isRemote) {
EnergyNet enet = getWorldPipeNet(worldIn).getNetFromPos(pos);
if (enet != null) {
enet.nodeNeighbourChanged(pos);
}
}
}

@Override
public boolean canPipesConnect(IPipeTile<Insulation, WireProperties> selfTile, EnumFacing side, IPipeTile<Insulation, WireProperties> sideTile) {
return selfTile instanceof TileEntityCable && sideTile instanceof TileEntityCable;
Expand All @@ -125,12 +137,12 @@ public boolean canPipeConnectToBlock(IPipeTile<Insulation, WireProperties> selfT
public void onEntityCollision(World worldIn, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Entity entityIn) {
if (worldIn.isRemote) return;
Insulation insulation = getPipeTileEntity(worldIn, pos).getPipeType();
if (!worldIn.isRemote && insulation.insulationLevel == -1 && entityIn instanceof EntityLivingBase) {
if (insulation.insulationLevel == -1 && entityIn instanceof EntityLivingBase) {
EntityLivingBase entityLiving = (EntityLivingBase) entityIn;
EnergyNet energyNet = getWorldPipeNet(worldIn).getNetFromPos(pos);
if (energyNet != null && (energyNet.getAllNodes().get(pos).data.lossPerBlock > 0)) {
long voltage = energyNet.getLastMaxVoltage();
long amperage = energyNet.getLastAmperage();
TileEntityCable cable = (TileEntityCable) getPipeTileEntity(worldIn, pos);
if (cable != null && cable.getNodeData().lossPerBlock > 0) {
long voltage = cable.getCurrentVoltage();
long amperage = cable.getCurrentAmperage();
if (voltage > 0L && amperage > 0L) {
float damageAmount = (GTUtility.getTierByVoltage(voltage) + 1) * amperage * 4;
entityLiving.attackEntityFrom(DamageSources.getElectricDamage(), damageAmount);
Expand Down
79 changes: 23 additions & 56 deletions src/main/java/gregtech/common/pipelike/cable/net/EnergyNet.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,83 +4,50 @@
import gregtech.api.pipenet.PipeNet;
import gregtech.api.pipenet.WorldPipeNet;
import gregtech.api.unification.material.properties.WireProperties;
import gregtech.api.util.PerTickLongCounter;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockPos.MutableBlockPos;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;
import java.util.Map;

public class EnergyNet extends PipeNet<WireProperties> {

private final PerTickLongCounter currentAmperageCounter = new PerTickLongCounter(0L);
private final PerTickLongCounter currentMaxVoltageCounter = new PerTickLongCounter(0L);
private final Map<BlockPos, List<RoutePath>> NET_DATA = new HashMap<>();

protected EnergyNet(WorldPipeNet<WireProperties, EnergyNet> world) {
super(world);
}

public long getLastAmperage() {
return currentAmperageCounter.getLast(worldData.getWorld());
public List<RoutePath> getNetData(BlockPos pipePos) {
List<RoutePath> data = NET_DATA.get(pipePos);
if (data == null) {
data = EnergyNetWalker.createNetData(this, getWorldData(), pipePos);
data.sort(Comparator.comparingInt(RoutePath::getDistance));
NET_DATA.put(pipePos, data);
}
return data;
}

public long getLastMaxVoltage() {
return currentMaxVoltageCounter.getLast(worldData.getWorld());
public void nodeNeighbourChanged(BlockPos pos) {
NET_DATA.clear();
}

public void incrementCurrentAmperage(long amperage, long voltage) {
currentAmperageCounter.increment(worldData.getWorld(), amperage);
long currentMaxVoltage = currentMaxVoltageCounter.get(worldData.getWorld());
if (voltage > currentMaxVoltage) {
currentMaxVoltageCounter.set(worldData.getWorld(), voltage);
}
@Override
protected void updateBlockedConnections(BlockPos nodePos, EnumFacing facing, boolean isBlocked) {
super.updateBlockedConnections(nodePos, facing, isBlocked);
NET_DATA.clear();
}

public List<RoutePath> computePatches(BlockPos startPos) {
ArrayList<RoutePath> readyPaths = new ArrayList<>();
RoutePath currentPath = new RoutePath();
Node<WireProperties> firstNode = getNodeAt(startPos);
currentPath.path.put(startPos, firstNode.data);
readyPaths.add(currentPath.cloneAndCompute(startPos));
HashSet<BlockPos> observedSet = new HashSet<>();
observedSet.add(startPos);
MutableBlockPos currentPos = new MutableBlockPos(startPos);
Stack<EnumFacing> moveStack = new Stack<>();
main:
while (true) {
for (EnumFacing facing : EnumFacing.VALUES) {
currentPos.move(facing);
Node<WireProperties> secondNode = getNodeAt(currentPos);
if (secondNode != null && canNodesConnect(firstNode, facing, secondNode, this) && !observedSet.contains(currentPos)) {
BlockPos immutablePos = currentPos.toImmutable();
observedSet.add(immutablePos);
firstNode = secondNode;
moveStack.push(facing.getOpposite());
currentPath.path.put(immutablePos, getNodeAt(immutablePos).data);
if (secondNode.isActive) {
//if we are on active node, this is end of our path
RoutePath finalizedPath = currentPath.cloneAndCompute(immutablePos);
readyPaths.add(finalizedPath);
}
continue main;
} else {
currentPos.move(facing.getOpposite());
}
}
if (!moveStack.isEmpty()) {
currentPos.move(moveStack.pop());
//also remove already visited block from path
currentPath.path.remove(currentPos);
} else break;
}
return readyPaths;
@Override
protected void transferNodeData(Map<BlockPos, Node<WireProperties>> transferredNodes, PipeNet<WireProperties> parentNet) {
super.transferNodeData(transferredNodes, parentNet);
NET_DATA.clear();
((EnergyNet) parentNet).NET_DATA.clear();
}


@Override
protected void writeNodeData(WireProperties nodeData, NBTTagCompound tagCompound) {
tagCompound.setInteger("voltage", nodeData.voltage);
Expand Down
Loading

0 comments on commit 7a9b1db

Please sign in to comment.