Network energy cables (#2493)
This commit is contained in:
parent
9d6890946d
commit
086ad25a47
4 changed files with 297 additions and 133 deletions
|
@ -24,7 +24,7 @@
|
||||||
|
|
||||||
package techreborn.blockentity.cable;
|
package techreborn.blockentity.cable;
|
||||||
|
|
||||||
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
import net.fabricmc.fabric.api.lookup.v1.block.BlockApiCache;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
import net.minecraft.block.entity.BlockEntity;
|
import net.minecraft.block.entity.BlockEntity;
|
||||||
|
@ -34,6 +34,7 @@ import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.nbt.NbtHelper;
|
import net.minecraft.nbt.NbtHelper;
|
||||||
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
|
import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
import net.minecraft.text.LiteralText;
|
import net.minecraft.text.LiteralText;
|
||||||
import net.minecraft.text.Text;
|
import net.minecraft.text.Text;
|
||||||
import net.minecraft.text.TranslatableText;
|
import net.minecraft.text.TranslatableText;
|
||||||
|
@ -49,45 +50,49 @@ import reborncore.common.network.NetworkManager;
|
||||||
import reborncore.common.powerSystem.PowerSystem;
|
import reborncore.common.powerSystem.PowerSystem;
|
||||||
import reborncore.common.util.StringUtils;
|
import reborncore.common.util.StringUtils;
|
||||||
import team.reborn.energy.api.EnergyStorage;
|
import team.reborn.energy.api.EnergyStorage;
|
||||||
import team.reborn.energy.api.EnergyStorageUtil;
|
|
||||||
import team.reborn.energy.api.base.SimpleSidedEnergyContainer;
|
import team.reborn.energy.api.base.SimpleSidedEnergyContainer;
|
||||||
import techreborn.blocks.cable.CableBlock;
|
import techreborn.blocks.cable.CableBlock;
|
||||||
import techreborn.init.TRBlockEntities;
|
import techreborn.init.TRBlockEntities;
|
||||||
import techreborn.init.TRContent;
|
import techreborn.init.TRContent;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
|
||||||
* Created by modmuss50 on 19/05/2017.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CableBlockEntity extends BlockEntity
|
public class CableBlockEntity extends BlockEntity
|
||||||
implements BlockEntityTicker<CableBlockEntity>, IListInfoProvider, IToolDrop {
|
implements BlockEntityTicker<CableBlockEntity>, IListInfoProvider, IToolDrop {
|
||||||
private final SimpleSidedEnergyContainer energyContainer = new SimpleSidedEnergyContainer() {
|
// Can't use SimpleEnergyStorage because the cable type is not available when the BE is constructed.
|
||||||
|
final SimpleSidedEnergyContainer energyContainer = new SimpleSidedEnergyContainer() {
|
||||||
@Override
|
@Override
|
||||||
public long getCapacity() {
|
public long getCapacity() {
|
||||||
return getCableType().transferRate * 4;
|
return getCableType().transferRate * 4L;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxInsert(@Nullable Direction side) {
|
public long getMaxInsert(Direction side) {
|
||||||
if (!canAcceptEnergy(side)) {
|
if (allowTransfer(side)) return getCableType().transferRate;
|
||||||
return 0;
|
else return 0;
|
||||||
}
|
|
||||||
return getCableType().transferRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getMaxExtract(@Nullable Direction side) {
|
public long getMaxExtract(Direction side) {
|
||||||
return getCableType().transferRate;
|
if (allowTransfer(side)) return getCableType().transferRate;
|
||||||
|
else return 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private double energy = 0;
|
|
||||||
private TRContent.Cables cableType = null;
|
private TRContent.Cables cableType = null;
|
||||||
private ArrayList<Direction> sendingFace = new ArrayList<>();
|
|
||||||
private BlockState cover = null;
|
private BlockState cover = null;
|
||||||
|
long lastTick = 0;
|
||||||
|
// null means that it needs to be re-queried
|
||||||
|
List<CableTarget> targets = null;
|
||||||
|
/**
|
||||||
|
* Bitmask to prevent input or output into/from the cable when the cable already transferred in the target direction.
|
||||||
|
* This prevents double transfer rates, and back and forth between two cables.
|
||||||
|
*/
|
||||||
|
int blockedSides = 0;
|
||||||
|
/**
|
||||||
|
* This is only used during the cable tick, whereas blockedOperations is used between ticks.
|
||||||
|
*/
|
||||||
|
boolean ioBlocked = false;
|
||||||
|
|
||||||
public CableBlockEntity(BlockPos pos, BlockState state) {
|
public CableBlockEntity(BlockPos pos, BlockState state) {
|
||||||
super(TRBlockEntities.CABLE, pos, state);
|
super(TRBlockEntities.CABLE, pos, state);
|
||||||
|
@ -98,7 +103,7 @@ public class CableBlockEntity extends BlockEntity
|
||||||
this.cableType = type;
|
this.cableType = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
private TRContent.Cables getCableType() {
|
TRContent.Cables getCableType() {
|
||||||
if (cableType != null) {
|
if (cableType != null) {
|
||||||
return cableType;
|
return cableType;
|
||||||
}
|
}
|
||||||
|
@ -113,6 +118,10 @@ public class CableBlockEntity extends BlockEntity
|
||||||
return TRContent.Cables.COPPER;
|
return TRContent.Cables.COPPER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean allowTransfer(Direction side) {
|
||||||
|
return !ioBlocked && (blockedSides & (1 << side.ordinal())) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
public EnergyStorage getSideEnergyStorage(@Nullable Direction side) {
|
public EnergyStorage getSideEnergyStorage(@Nullable Direction side) {
|
||||||
return energyContainer.getSideStorage(side);
|
return energyContainer.getSideStorage(side);
|
||||||
}
|
}
|
||||||
|
@ -128,13 +137,6 @@ public class CableBlockEntity extends BlockEntity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canAcceptEnergy(@Nullable Direction direction) {
|
|
||||||
if (sendingFace.contains(direction)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return energyContainer.getCapacity() != getEnergy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getEnergy() {
|
public long getEnergy() {
|
||||||
return energyContainer.amount;
|
return energyContainer.amount;
|
||||||
}
|
}
|
||||||
|
@ -160,7 +162,7 @@ public class CableBlockEntity extends BlockEntity
|
||||||
public void readNbt(NbtCompound compound) {
|
public void readNbt(NbtCompound compound) {
|
||||||
super.readNbt(compound);
|
super.readNbt(compound);
|
||||||
if (compound.contains("energy")) {
|
if (compound.contains("energy")) {
|
||||||
energy = compound.getDouble("energy");
|
energyContainer.amount = compound.getLong("energy");
|
||||||
}
|
}
|
||||||
if (compound.contains("cover")) {
|
if (compound.contains("cover")) {
|
||||||
cover = NbtHelper.toBlockState(compound.getCompound("cover"));
|
cover = NbtHelper.toBlockState(compound.getCompound("cover"));
|
||||||
|
@ -172,13 +174,17 @@ public class CableBlockEntity extends BlockEntity
|
||||||
@Override
|
@Override
|
||||||
public NbtCompound writeNbt(NbtCompound compound) {
|
public NbtCompound writeNbt(NbtCompound compound) {
|
||||||
super.writeNbt(compound);
|
super.writeNbt(compound);
|
||||||
compound.putDouble("energy", energy);
|
compound.putLong("energy", energyContainer.amount);
|
||||||
if (cover != null) {
|
if (cover != null) {
|
||||||
compound.put("cover", NbtHelper.fromBlockState(cover));
|
compound.put("cover", NbtHelper.fromBlockState(cover));
|
||||||
}
|
}
|
||||||
return compound;
|
return compound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void neighborUpdate() {
|
||||||
|
targets = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Tickable
|
// Tickable
|
||||||
@Override
|
@Override
|
||||||
public void tick(World world, BlockPos pos, BlockState state, CableBlockEntity blockEntity2) {
|
public void tick(World world, BlockPos pos, BlockState state, CableBlockEntity blockEntity2) {
|
||||||
|
@ -186,72 +192,7 @@ public class CableBlockEntity extends BlockEntity
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendingFace.clear();
|
CableTickManager.handleCableTick(this);
|
||||||
|
|
||||||
if (getEnergy() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<EnergyStorage> acceptors = new ArrayList<>();
|
|
||||||
ArrayList<CableBlockEntity> cables = new ArrayList<>();
|
|
||||||
|
|
||||||
for (Direction face : Direction.values()) {
|
|
||||||
BlockPos adjPos = pos.offset(face);
|
|
||||||
BlockEntity blockEntity = world.getBlockEntity(adjPos);
|
|
||||||
EnergyStorage target = EnergyStorage.SIDED.find(world, adjPos, null, blockEntity, face.getOpposite());
|
|
||||||
if (target == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (blockEntity instanceof CableBlockEntity cableBlockEntity) {
|
|
||||||
if (cableBlockEntity.cableType != this.cableType) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Only need ones with energy stores less than ours
|
|
||||||
if (cableBlockEntity.getEnergy() < this.getEnergy()) {
|
|
||||||
cables.add(cableBlockEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
try (Transaction transaction = Transaction.openOuter()) {
|
|
||||||
if (target.insert(Long.MAX_VALUE, transaction) > 0) {
|
|
||||||
acceptors.add(target);
|
|
||||||
if (!sendingFace.contains(face)) {
|
|
||||||
sendingFace.add(face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!acceptors.isEmpty()) {
|
|
||||||
Collections.shuffle(acceptors);
|
|
||||||
|
|
||||||
acceptors.forEach(t -> EnergyStorageUtil.move(
|
|
||||||
energyContainer.getSideStorage(null),
|
|
||||||
t,
|
|
||||||
Long.MAX_VALUE,
|
|
||||||
null
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Distribute energy between cables (TODO DIRTY FIX, until we game network cables)
|
|
||||||
|
|
||||||
if (!cables.isEmpty()) {
|
|
||||||
|
|
||||||
cables.add(this);
|
|
||||||
long energyTotal = cables.stream().mapToLong(CableBlockEntity::getEnergy).sum();
|
|
||||||
long remainingCount = cables.size();
|
|
||||||
|
|
||||||
for (CableBlockEntity cable : cables) {
|
|
||||||
long newEnergy = energyTotal / remainingCount;
|
|
||||||
cable.setEnergy(newEnergy);
|
|
||||||
energyTotal -= newEnergy;
|
|
||||||
remainingCount--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IListInfoProvider
|
// IListInfoProvider
|
||||||
|
@ -286,4 +227,67 @@ public class CableBlockEntity extends BlockEntity
|
||||||
public ItemStack getToolDrop(PlayerEntity playerIn) {
|
public ItemStack getToolDrop(PlayerEntity playerIn) {
|
||||||
return new ItemStack(getCableType().block);
|
return new ItemStack(getCableType().block);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appendTargets(List<OfferedEnergyStorage> targetStorages) {
|
||||||
|
ServerWorld serverWorld = (ServerWorld) world;
|
||||||
|
|
||||||
|
// Update our targets if necessary.
|
||||||
|
if (targets == null) {
|
||||||
|
BlockState newBlockState = getCachedState();
|
||||||
|
|
||||||
|
targets = new ArrayList<>();
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
boolean foundSomething = false;
|
||||||
|
|
||||||
|
BlockPos adjPos = getPos().offset(direction);
|
||||||
|
BlockEntity adjBe = serverWorld.getBlockEntity(adjPos);
|
||||||
|
|
||||||
|
if (adjBe instanceof CableBlockEntity adjCable && adjCable.getCableType() == getCableType()) {
|
||||||
|
// Make sure cables are not used as regular targets.
|
||||||
|
foundSomething = true;
|
||||||
|
} else if (EnergyStorage.SIDED.find(serverWorld, adjPos, null, adjBe, direction.getOpposite()) != null) {
|
||||||
|
foundSomething = true;
|
||||||
|
targets.add(new CableTarget(
|
||||||
|
direction,
|
||||||
|
BlockApiCache.create(EnergyStorage.SIDED, serverWorld, adjPos)
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
newBlockState = newBlockState.with(CableBlock.PROPERTY_MAP.get(direction), foundSomething);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverWorld.setBlockState(getPos(), newBlockState);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fill the list.
|
||||||
|
for (CableTarget target : targets) {
|
||||||
|
EnergyStorage storage = target.find();
|
||||||
|
|
||||||
|
if (storage == null) {
|
||||||
|
// Schedule a rebuild next tick.
|
||||||
|
// This is just a reference change, the iterator remains valid.
|
||||||
|
targets = null;
|
||||||
|
} else {
|
||||||
|
targetStorages.add(new OfferedEnergyStorage(this, target.directionTo, storage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset blocked sides.
|
||||||
|
blockedSides = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class CableTarget {
|
||||||
|
private final Direction directionTo;
|
||||||
|
private final BlockApiCache<EnergyStorage, Direction> cache;
|
||||||
|
|
||||||
|
CableTarget(Direction directionTo, BlockApiCache<EnergyStorage, Direction> cache) {
|
||||||
|
this.directionTo = directionTo;
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
EnergyStorage find() {
|
||||||
|
return cache.find(directionTo.getOpposite());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
164
src/main/java/techreborn/blockentity/cable/CableTickManager.java
Normal file
164
src/main/java/techreborn/blockentity/cable/CableTickManager.java
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
package techreborn.blockentity.cable;
|
||||||
|
|
||||||
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
|
||||||
|
import net.fabricmc.fabric.api.transfer.v1.transaction.Transaction;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import team.reborn.energy.api.EnergyStorage;
|
||||||
|
import techreborn.init.TRContent;
|
||||||
|
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@SuppressWarnings("UnstableApiUsage")
|
||||||
|
class CableTickManager {
|
||||||
|
private static long tickCounter = 0;
|
||||||
|
private static final List<CableBlockEntity> cableList = new ArrayList<>();
|
||||||
|
private static final List<OfferedEnergyStorage> targetStorages = new ArrayList<>();
|
||||||
|
private static final Deque<CableBlockEntity> bfsQueue = new ArrayDeque<>();
|
||||||
|
|
||||||
|
static void handleCableTick(CableBlockEntity startingCable) {
|
||||||
|
if (!(startingCable.getWorld() instanceof ServerWorld)) throw new IllegalStateException();
|
||||||
|
|
||||||
|
try {
|
||||||
|
gatherCables(startingCable);
|
||||||
|
if (cableList.size() == 0) return;
|
||||||
|
|
||||||
|
// Group all energy into the network.
|
||||||
|
long networkCapacity = 0;
|
||||||
|
long networkAmount = 0;
|
||||||
|
|
||||||
|
for (CableBlockEntity cable : cableList) {
|
||||||
|
networkAmount += cable.energyContainer.amount;
|
||||||
|
networkCapacity += cable.energyContainer.getCapacity();
|
||||||
|
|
||||||
|
// Update cable connections.
|
||||||
|
cable.appendTargets(targetStorages);
|
||||||
|
// Block any cable I/O while we access the network amount directly.
|
||||||
|
// Some things might try to access cables, for example a p2p tunnel pointing back at a cable.
|
||||||
|
// If the cables and the network go out of sync, we risk duping or voiding energy.
|
||||||
|
cable.ioBlocked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just in case.
|
||||||
|
if (networkAmount > networkCapacity) {
|
||||||
|
networkAmount = networkCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull energy from storages.
|
||||||
|
networkAmount += dispatchTransfer(startingCable.getCableType(), EnergyStorage::extract, networkCapacity - networkAmount);
|
||||||
|
// Push energy into storages.
|
||||||
|
networkAmount -= dispatchTransfer(startingCable.getCableType(), EnergyStorage::insert, networkAmount);
|
||||||
|
|
||||||
|
// Split energy evenly across cables.
|
||||||
|
int cableCount = cableList.size();
|
||||||
|
for (CableBlockEntity cable : cableList) {
|
||||||
|
cable.energyContainer.amount = networkAmount / cableCount;
|
||||||
|
networkAmount -= cable.energyContainer.amount;
|
||||||
|
cableCount--;
|
||||||
|
cable.markDirty();
|
||||||
|
cable.ioBlocked = false;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
cableList.clear();
|
||||||
|
targetStorages.clear();
|
||||||
|
bfsQueue.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldTickCable(CableBlockEntity current) {
|
||||||
|
// Make sure we only gather and tick each cable once per tick.
|
||||||
|
if (current.lastTick == tickCounter) return false;
|
||||||
|
// Make sure we ignore cables in non-ticking chunks.
|
||||||
|
if (!(current.getWorld() instanceof ServerWorld sw) || !sw.method_37117(current.getPos())) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a BFS to gather all connected ticking cables.
|
||||||
|
*/
|
||||||
|
private static void gatherCables(CableBlockEntity start) {
|
||||||
|
if (!shouldTickCable(start)) return;
|
||||||
|
|
||||||
|
bfsQueue.add(start);
|
||||||
|
start.lastTick = tickCounter;
|
||||||
|
cableList.add(start);
|
||||||
|
|
||||||
|
while (!bfsQueue.isEmpty()) {
|
||||||
|
CableBlockEntity current = bfsQueue.removeFirst();
|
||||||
|
|
||||||
|
for (Direction direction : Direction.values()) {
|
||||||
|
BlockPos adjPos = current.getPos().offset(direction);
|
||||||
|
|
||||||
|
if (current.getWorld().getBlockEntity(adjPos) instanceof CableBlockEntity adjCable && current.getCableType() == adjCable.getCableType()) {
|
||||||
|
if (shouldTickCable(adjCable)) {
|
||||||
|
bfsQueue.add(adjCable);
|
||||||
|
adjCable.lastTick = tickCounter;
|
||||||
|
cableList.add(adjCable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a transfer operation across a list of targets.
|
||||||
|
*/
|
||||||
|
private static long dispatchTransfer(TRContent.Cables cableType, TransferOperation operation, long maxAmount) {
|
||||||
|
// Build target list.
|
||||||
|
List<SortableStorage> sortedTargets = new ArrayList<>();
|
||||||
|
for (var storage : targetStorages) {
|
||||||
|
sortedTargets.add(new SortableStorage(operation, storage));
|
||||||
|
}
|
||||||
|
// Shuffle for better average transfer.
|
||||||
|
Collections.shuffle(sortedTargets);
|
||||||
|
// Sort by lowest simulation target.
|
||||||
|
sortedTargets.sort(Comparator.comparingLong(sortableStorage -> sortableStorage.simulationResult));
|
||||||
|
// Actually perform the transfer.
|
||||||
|
try (Transaction transaction = Transaction.openOuter()) {
|
||||||
|
long transferredAmount = 0;
|
||||||
|
for (int i = 0; i < sortedTargets.size(); ++i) {
|
||||||
|
SortableStorage target = sortedTargets.get(i);
|
||||||
|
int remainingTargets = sortedTargets.size() - i;
|
||||||
|
long remainingAmount = maxAmount - transferredAmount;
|
||||||
|
// Limit max amount to the cable transfer rate.
|
||||||
|
long targetMaxAmount = Math.min(remainingAmount / remainingTargets, cableType.transferRate);
|
||||||
|
|
||||||
|
long localTransferred = operation.transfer(target.storage.storage, targetMaxAmount, transaction);
|
||||||
|
if (localTransferred > 0) {
|
||||||
|
transferredAmount += localTransferred;
|
||||||
|
// Block duplicate operations.
|
||||||
|
target.storage.afterTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transaction.commit();
|
||||||
|
return transferredAmount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface TransferOperation {
|
||||||
|
long transfer(EnergyStorage storage, long maxAmount, Transaction transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SortableStorage {
|
||||||
|
private final OfferedEnergyStorage storage;
|
||||||
|
private final long simulationResult;
|
||||||
|
|
||||||
|
SortableStorage(TransferOperation operation, OfferedEnergyStorage storage) {
|
||||||
|
this.storage = storage;
|
||||||
|
try (Transaction tx = Transaction.openOuter()) {
|
||||||
|
this.simulationResult = operation.transfer(storage.storage, Long.MAX_VALUE, tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static {
|
||||||
|
ServerTickEvents.START_SERVER_TICK.register(server -> tickCounter++);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package techreborn.blockentity.cable;
|
||||||
|
|
||||||
|
import net.minecraft.util.math.Direction;
|
||||||
|
import team.reborn.energy.api.EnergyStorage;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EnergyStorage adjacent to an energy cable, with some additional info.
|
||||||
|
*/
|
||||||
|
class OfferedEnergyStorage {
|
||||||
|
final CableBlockEntity sourceCable;
|
||||||
|
final Direction direction;
|
||||||
|
final EnergyStorage storage;
|
||||||
|
|
||||||
|
OfferedEnergyStorage(CableBlockEntity sourceCable, Direction direction, EnergyStorage storage) {
|
||||||
|
this.sourceCable = sourceCable;
|
||||||
|
this.direction = direction;
|
||||||
|
this.storage = storage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void afterTransfer() {
|
||||||
|
// Block insertions from this side.
|
||||||
|
sourceCable.blockedSides |= 1 << direction.ordinal();
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,42 +105,6 @@ public class CableBlock extends BlockWithEntity implements Waterloggable {
|
||||||
cableShapeUtil = new CableShapeUtil(this);
|
cableShapeUtil = new CableShapeUtil(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BooleanProperty getProperty(Direction facing) {
|
|
||||||
return switch (facing) {
|
|
||||||
case WEST -> WEST;
|
|
||||||
case NORTH -> NORTH;
|
|
||||||
case SOUTH -> SOUTH;
|
|
||||||
case UP -> UP;
|
|
||||||
case DOWN -> DOWN;
|
|
||||||
default -> EAST;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private BlockState makeConnections(World world, BlockPos pos) {
|
|
||||||
Boolean down = canConnectTo(world, pos, Direction.DOWN);
|
|
||||||
Boolean up = canConnectTo(world, pos, Direction.UP);
|
|
||||||
Boolean north = canConnectTo(world, pos, Direction.NORTH);
|
|
||||||
Boolean east = canConnectTo(world, pos, Direction.EAST);
|
|
||||||
Boolean south = canConnectTo(world, pos, Direction.SOUTH);
|
|
||||||
Boolean west = canConnectTo(world, pos, Direction.WEST);
|
|
||||||
|
|
||||||
return this.getDefaultState().with(DOWN, down).with(UP, up).with(NORTH, north).with(EAST, east)
|
|
||||||
.with(SOUTH, south).with(WEST, west);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Boolean canConnectTo(WorldAccess world, BlockPos currentPos, Direction side) {
|
|
||||||
BlockPos adjPos = currentPos.offset(side);
|
|
||||||
BlockEntity adjBe = world.getBlockEntity(adjPos);
|
|
||||||
if (adjBe instanceof CableBlockEntity) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
// TODO: this doesn't work at all, fix this
|
|
||||||
else if (world instanceof ServerWorld sw && EnergyStorage.SIDED.find(sw, adjPos, null, adjBe, side.getOpposite()) != null) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// BlockContainer
|
// BlockContainer
|
||||||
@Override
|
@Override
|
||||||
public BlockRenderType getRenderType(BlockState state) {
|
public BlockRenderType getRenderType(BlockState state) {
|
||||||
|
@ -210,7 +174,7 @@ public class CableBlock extends BlockWithEntity implements Waterloggable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getPlacementState(ItemPlacementContext context) {
|
public BlockState getPlacementState(ItemPlacementContext context) {
|
||||||
return makeConnections(context.getWorld(), context.getBlockPos())
|
return getDefaultState()
|
||||||
.with(WATERLOGGED, context.getWorld().getFluidState(context.getBlockPos()).getFluid() == Fluids.WATER);
|
.with(WATERLOGGED, context.getWorld().getFluidState(context.getBlockPos()).getFluid() == Fluids.WATER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,8 +185,16 @@ public class CableBlock extends BlockWithEntity implements Waterloggable {
|
||||||
if (ourState.get(WATERLOGGED)) {
|
if (ourState.get(WATERLOGGED)) {
|
||||||
worldIn.getFluidTickScheduler().schedule(ourPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
|
worldIn.getFluidTickScheduler().schedule(ourPos, Fluids.WATER, Fluids.WATER.getTickRate(worldIn));
|
||||||
}
|
}
|
||||||
Boolean value = canConnectTo(worldIn, otherPos, direction);
|
return ourState;
|
||||||
return ourState.with(getProperty(direction), value);
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
public void neighborUpdate(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean notify) {
|
||||||
|
if (world.getBlockEntity(pos) instanceof CableBlockEntity cable) {
|
||||||
|
cable.neighborUpdate();
|
||||||
|
}
|
||||||
|
super.neighborUpdate(state, world, pos, block, fromPos, notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
|
|
Loading…
Reference in a new issue