mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
world of fluidtanks
This commit is contained in:
parent
43af152641
commit
71af841046
8 changed files with 540 additions and 22 deletions
|
@ -0,0 +1,372 @@
|
||||||
|
package com.simibubi.create.api.connectivity;
|
||||||
|
|
||||||
|
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity;
|
||||||
|
import com.simibubi.create.foundation.tileEntity.IMultiTileContainer;
|
||||||
|
|
||||||
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||||
|
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.IFluidTank;
|
||||||
|
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
|
||||||
|
|
||||||
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
||||||
|
|
||||||
|
import net.minecraftforge.items.CapabilityItemHandler;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.PriorityQueue;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class ConnectivityHandler {
|
||||||
|
|
||||||
|
public static <T extends BlockEntity & IMultiTileContainer> void formMulti (T be) {
|
||||||
|
SearchCache<T> cache = new SearchCache<>();
|
||||||
|
List<T> frontier = new ArrayList<>();
|
||||||
|
frontier.add(be);
|
||||||
|
formMulti(be.getType(), be.getLevel(), cache, frontier);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> void formMulti (BlockEntityType<?> type, BlockGetter level, SearchCache<T> cache, List<T> frontier) {
|
||||||
|
PriorityQueue<Pair<Integer, T>> creationQueue = makeCreationQueue();
|
||||||
|
Set<BlockPos> visited = new HashSet<>();
|
||||||
|
Direction.Axis mainAxis = frontier.get(0).getMainConnectionAxis();
|
||||||
|
|
||||||
|
// essentially, if it's a vertical multi then the search won't be restricted by Y
|
||||||
|
// alternately, a horizontal multi search shouldn't be restricted by X or Z
|
||||||
|
int minX = (mainAxis == Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
|
||||||
|
int minY = (mainAxis != Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
|
||||||
|
int minZ = (mainAxis == Direction.Axis.Y ? Integer.MAX_VALUE : Integer.MIN_VALUE);
|
||||||
|
|
||||||
|
for (T be : frontier) {
|
||||||
|
BlockPos pos = be.getBlockPos();
|
||||||
|
minX = Math.min(pos.getX(), minX);
|
||||||
|
minY = Math.min(pos.getY(), minY);
|
||||||
|
minZ = Math.min(pos.getZ(), minZ);
|
||||||
|
}
|
||||||
|
if (mainAxis == Direction.Axis.Y) minX -= frontier.get(0).getMaxWidth();
|
||||||
|
if (mainAxis != Direction.Axis.Y) minY -= frontier.get(0).getMaxWidth();
|
||||||
|
if (mainAxis == Direction.Axis.Y) minZ -= frontier.get(0).getMaxWidth();
|
||||||
|
|
||||||
|
while (!frontier.isEmpty()) {
|
||||||
|
T part = frontier.remove(0);
|
||||||
|
BlockPos partPos = part.getBlockPos();
|
||||||
|
if (visited.contains(partPos)) continue;
|
||||||
|
|
||||||
|
visited.add(partPos);
|
||||||
|
|
||||||
|
int amount = tryToFormNewMulti(part, cache, true);
|
||||||
|
if (amount > 1) {
|
||||||
|
creationQueue.add(Pair.of(amount, part));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Direction.Axis axis : Iterate.axes) {
|
||||||
|
Direction dir = Direction.get(Direction.AxisDirection.NEGATIVE, axis);
|
||||||
|
BlockPos next = partPos.relative(dir);
|
||||||
|
|
||||||
|
if (next.getX() <= minX || next.getY() <= minY || next.getZ() <= minZ) continue;
|
||||||
|
if (visited.contains(next)) continue;
|
||||||
|
T nextBe = partAt(type, level, next);
|
||||||
|
if (nextBe == null) continue;
|
||||||
|
if (nextBe.isRemoved()) continue;
|
||||||
|
frontier.add(nextBe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited.clear();
|
||||||
|
|
||||||
|
while (!creationQueue.isEmpty()) {
|
||||||
|
Pair<Integer, T> next = creationQueue.poll();
|
||||||
|
T toCreate = next.getValue();
|
||||||
|
if (visited.contains(toCreate.getBlockPos())) continue;
|
||||||
|
|
||||||
|
visited.add(toCreate.getBlockPos());
|
||||||
|
tryToFormNewMulti(toCreate, cache, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> int tryToFormNewMulti (T be, SearchCache<T> cache, boolean simulate) {
|
||||||
|
int bestWidth = 1;
|
||||||
|
int bestAmount = -1;
|
||||||
|
if (!be.isController()) return 0;
|
||||||
|
|
||||||
|
int radius = be.getMaxWidth();
|
||||||
|
for (int w = 1; w <= radius; w++) {
|
||||||
|
int amount = tryToFormNewMultiOfWidth(be, w, cache, true);
|
||||||
|
if (amount < bestAmount) continue;
|
||||||
|
bestWidth = w;
|
||||||
|
bestAmount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!simulate) {
|
||||||
|
int beWidth = be.getWidth();
|
||||||
|
if (beWidth == bestWidth && beWidth*beWidth * be.getHeight() == bestAmount) return bestAmount;
|
||||||
|
|
||||||
|
splitMultiAndInvalidate(be, cache, false);
|
||||||
|
if (be.hasFluid()) be.setTankSize(0, bestAmount);
|
||||||
|
|
||||||
|
tryToFormNewMultiOfWidth(be, bestWidth, cache, false);
|
||||||
|
|
||||||
|
be.preventConnectivityUpdate();
|
||||||
|
be.setWidth(bestWidth);
|
||||||
|
be.setHeight(bestAmount / bestWidth / bestWidth);
|
||||||
|
be.notifyMultiUpdated();
|
||||||
|
}
|
||||||
|
return bestAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> int tryToFormNewMultiOfWidth (T be, int width, SearchCache<T> cache, boolean simulate) {
|
||||||
|
int amount = 0;
|
||||||
|
int height = 0;
|
||||||
|
BlockEntityType<?> type = be.getType();
|
||||||
|
Level level = be.getLevel();
|
||||||
|
if (level == null) return 0;
|
||||||
|
BlockPos origin = be.getBlockPos();
|
||||||
|
|
||||||
|
// optional fluid handling
|
||||||
|
IFluidTank beTank = null;
|
||||||
|
FluidStack fluid = FluidStack.EMPTY;
|
||||||
|
if (be.hasFluid()) {
|
||||||
|
beTank = be.getTank(0);
|
||||||
|
fluid = beTank.getFluid();
|
||||||
|
}
|
||||||
|
Direction.Axis axis = be.getMainConnectionAxis();
|
||||||
|
|
||||||
|
Search:
|
||||||
|
for (int yOffset = 0; yOffset < be.getMaxLength(axis, width); yOffset++) {
|
||||||
|
for (int xOffset = 0; xOffset < width; xOffset++) {
|
||||||
|
for (int zOffset = 0; zOffset < width; zOffset++) {
|
||||||
|
BlockPos pos = switch (axis) {
|
||||||
|
case X -> origin.offset(yOffset, xOffset, zOffset);
|
||||||
|
case Y -> origin.offset(xOffset, yOffset, zOffset);
|
||||||
|
case Z -> origin.offset(xOffset, zOffset, yOffset);
|
||||||
|
};
|
||||||
|
Optional<T> part = cache.getOrCache(type, level, pos);
|
||||||
|
if (part.isEmpty()) break Search;
|
||||||
|
|
||||||
|
T controller = part.get();
|
||||||
|
int otherWidth = controller.getWidth();
|
||||||
|
if (otherWidth > width) break Search;
|
||||||
|
if (otherWidth == width && controller.getHeight() == be.getMaxLength(axis, width)) break Search;
|
||||||
|
|
||||||
|
Direction.Axis conAxis = controller.getMainConnectionAxis();
|
||||||
|
if (axis != conAxis) break Search;
|
||||||
|
|
||||||
|
BlockPos conPos = controller.getBlockPos();
|
||||||
|
if (!conPos.equals(origin)) {
|
||||||
|
if (axis == Direction.Axis.Y) { // vertical multi, like a FluidTank
|
||||||
|
if (conPos.getX() < origin.getX()) break Search;
|
||||||
|
if (conPos.getZ() < origin.getZ()) break Search;
|
||||||
|
if (conPos.getX() + otherWidth > origin.getX() + width) break Search;
|
||||||
|
if (conPos.getZ() + otherWidth > origin.getZ() + width) break Search;
|
||||||
|
} else { // horizontal multi, like an ItemVault
|
||||||
|
if (axis == Direction.Axis.Z && conPos.getX() < origin.getX()) break Search;
|
||||||
|
if (conPos.getY() < origin.getY()) break Search;
|
||||||
|
if (axis == Direction.Axis.X && conPos.getZ() < origin.getZ()) break Search;
|
||||||
|
if (axis == Direction.Axis.Z && conPos.getX() + otherWidth > origin.getX() + width) break Search;
|
||||||
|
if (conPos.getY() + otherWidth > origin.getY() + width) break Search;
|
||||||
|
if (axis == Direction.Axis.X && conPos.getZ() + otherWidth > origin.getZ() + width) break Search;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FluidStack otherFluid = controller.getFluid(0);
|
||||||
|
if (!fluid.isEmpty() && !otherFluid.isEmpty() && !fluid.isFluidEqual(otherFluid)) break Search;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
amount += width * width;
|
||||||
|
height++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (simulate) return amount;
|
||||||
|
|
||||||
|
Object extraData = be.getExtraData();
|
||||||
|
|
||||||
|
for (int yOffset = 0; yOffset < height; yOffset++) {
|
||||||
|
for (int xOffset = 0; xOffset < width; xOffset++) {
|
||||||
|
for (int zOffset = 0; zOffset < width; zOffset++) {
|
||||||
|
BlockPos pos = switch (axis) {
|
||||||
|
case X -> origin.offset(yOffset, xOffset, zOffset);
|
||||||
|
case Y -> origin.offset(xOffset, yOffset, zOffset);
|
||||||
|
case Z -> origin.offset(xOffset, zOffset, yOffset);
|
||||||
|
};
|
||||||
|
T part = partAt(type, level, pos);
|
||||||
|
if (part == null) continue;
|
||||||
|
if (part == be) continue;
|
||||||
|
|
||||||
|
extraData = be.modifyExtraData(extraData);
|
||||||
|
|
||||||
|
if (part.hasFluid()) {
|
||||||
|
IFluidTank tankAt = part.getTank(0);
|
||||||
|
FluidStack fluidAt = tankAt.getFluid();
|
||||||
|
if (!fluidAt.isEmpty()) {
|
||||||
|
// making this generic would be a rather large mess, unfortunately
|
||||||
|
if (beTank != null && fluid.isEmpty() && beTank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank) {
|
||||||
|
((CreativeFluidTankTileEntity.CreativeSmartFluidTank)beTank).setContainedFluid(fluidAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tankAt.drain(tankAt.getCapacity(), IFluidHandler.FluidAction.EXECUTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
splitMultiAndInvalidate(part, cache, false);
|
||||||
|
part.setController(origin);
|
||||||
|
part.preventConnectivityUpdate();
|
||||||
|
cache.put(pos, be);
|
||||||
|
part.setHeight(height);
|
||||||
|
part.notifyMultiUpdated();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
be.setExtraData(extraData);
|
||||||
|
be.notifyMultiUpdated();
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends BlockEntity & IMultiTileContainer> void splitMulti (T be) {
|
||||||
|
splitMultiAndInvalidate(be, null, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// tryReconnect helps whenever only a few tanks have been removed
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> void splitMultiAndInvalidate (T be, @Nullable SearchCache<T> cache, boolean tryReconnect) {
|
||||||
|
Level level = be.getLevel();
|
||||||
|
if (level == null) return;
|
||||||
|
|
||||||
|
be = be.getControllerTE();
|
||||||
|
if (be == null) return;
|
||||||
|
|
||||||
|
int height = be.getHeight();
|
||||||
|
int width = be.getWidth();
|
||||||
|
if (width == 1 && height == 1) return;
|
||||||
|
|
||||||
|
BlockPos origin = be.getBlockPos();
|
||||||
|
List<T> frontier = new ArrayList<>();
|
||||||
|
Direction.Axis axis = be.getMainConnectionAxis();
|
||||||
|
|
||||||
|
// fluid handling, if present
|
||||||
|
FluidStack toDistribute = FluidStack.EMPTY;
|
||||||
|
int maxCapacity = 0;
|
||||||
|
if (be.hasFluid()) {
|
||||||
|
toDistribute = be.getFluid(0);
|
||||||
|
maxCapacity = be.getTankSize(0);
|
||||||
|
if (!toDistribute.isEmpty() && !be.isRemoved()) toDistribute.shrink(maxCapacity);
|
||||||
|
be.setTankSize(0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int yOffset = 0; yOffset < height; yOffset++) {
|
||||||
|
for (int xOffset = 0; xOffset < width; xOffset++) {
|
||||||
|
for (int zOffset = 0; zOffset < width; zOffset++) {
|
||||||
|
BlockPos pos = switch (axis) {
|
||||||
|
case X -> origin.offset(yOffset, xOffset, zOffset);
|
||||||
|
case Y -> origin.offset(xOffset, yOffset, zOffset);
|
||||||
|
case Z -> origin.offset(xOffset, zOffset, yOffset);
|
||||||
|
};
|
||||||
|
T partAt = partAt(be.getType(), level, pos);
|
||||||
|
if (partAt == null) continue;
|
||||||
|
if (!partAt.getController().equals(origin)) continue;
|
||||||
|
|
||||||
|
T controllerBE = partAt.getControllerTE();
|
||||||
|
partAt.setExtraData ( (controllerBE == null ? null : controllerBE.getExtraData()));
|
||||||
|
partAt.removeController(true);
|
||||||
|
|
||||||
|
if (!toDistribute.isEmpty() && partAt != be) {
|
||||||
|
FluidStack copy = toDistribute.copy();
|
||||||
|
IFluidTank tank = partAt.getTank(0);
|
||||||
|
// making this generic would be a rather large mess, unfortunately
|
||||||
|
if (tank instanceof CreativeFluidTankTileEntity.CreativeSmartFluidTank creativeTank) {
|
||||||
|
if (creativeTank.isEmpty()) creativeTank.setContainedFluid(toDistribute);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int split = Math.min(maxCapacity, toDistribute.getAmount());
|
||||||
|
copy.setAmount(split);
|
||||||
|
toDistribute.shrink(split);
|
||||||
|
tank.fill(copy, IFluidHandler.FluidAction.EXECUTE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tryReconnect) {
|
||||||
|
frontier.add(partAt);
|
||||||
|
partAt.preventConnectivityUpdate();
|
||||||
|
}
|
||||||
|
if (cache != null) {
|
||||||
|
cache.put(pos, partAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (be.hasItems()) {
|
||||||
|
be.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).invalidate();
|
||||||
|
}
|
||||||
|
if (be.hasFluid()) {
|
||||||
|
be.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY).invalidate();
|
||||||
|
}
|
||||||
|
if (tryReconnect) {
|
||||||
|
formMulti(be.getType(), level, cache == null ? new SearchCache<>() : cache, frontier);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> PriorityQueue<Pair<Integer, T>> makeCreationQueue () {
|
||||||
|
return new PriorityQueue<>((one, two) -> two.getKey() - one.getKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static <T extends BlockEntity & IMultiTileContainer> T partAt (BlockEntityType<?> type, BlockGetter level, BlockPos pos) {
|
||||||
|
BlockEntity be = level.getBlockEntity(pos);
|
||||||
|
if (be != null && be.getType() == type) return checked(be);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends BlockEntity & IMultiTileContainer> boolean isConnected (BlockGetter level, BlockPos pos, BlockPos other) {
|
||||||
|
T one = checked(level.getBlockEntity(pos));
|
||||||
|
T two = checked(level.getBlockEntity(other));
|
||||||
|
if (one == null || two == null) return false;
|
||||||
|
return one.getController().equals(two.getController());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static <T extends BlockEntity & IMultiTileContainer> T checked (BlockEntity be) {
|
||||||
|
if (be instanceof IMultiTileContainer) return (T)be;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class SearchCache<T extends BlockEntity & IMultiTileContainer> {
|
||||||
|
Map<BlockPos, Optional<T>> controllerMap;
|
||||||
|
|
||||||
|
public SearchCache () { controllerMap = new HashMap<>(); }
|
||||||
|
|
||||||
|
void put (BlockPos pos, T target) { controllerMap.put(pos, Optional.of(target)); }
|
||||||
|
|
||||||
|
void putEmpty (BlockPos pos) { controllerMap.put(pos, Optional.empty()); }
|
||||||
|
|
||||||
|
boolean hasVisited (BlockPos pos) { return controllerMap.containsKey(pos); }
|
||||||
|
|
||||||
|
Optional<T> getOrCache (BlockEntityType<?> type, BlockGetter level, BlockPos pos) {
|
||||||
|
if (hasVisited(pos)) return controllerMap.get(pos);
|
||||||
|
|
||||||
|
T partAt = partAt(type, level, pos);
|
||||||
|
if (partAt == null) {
|
||||||
|
putEmpty(pos);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
T controller = checked(level.getBlockEntity(partAt.getController()));
|
||||||
|
if (controller == null) {
|
||||||
|
putEmpty(pos);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
put(pos, controller);
|
||||||
|
return Optional.of(controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import java.util.List;
|
||||||
|
|
||||||
import com.simibubi.create.AllBlocks;
|
import com.simibubi.create.AllBlocks;
|
||||||
import com.simibubi.create.AllTags.AllBlockTags;
|
import com.simibubi.create.AllTags.AllBlockTags;
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock;
|
import com.simibubi.create.content.contraptions.components.actors.AttachedActorBlock;
|
||||||
import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock;
|
import com.simibubi.create.content.contraptions.components.actors.HarvesterBlock;
|
||||||
import com.simibubi.create.content.contraptions.components.actors.PloughBlock;
|
import com.simibubi.create.content.contraptions.components.actors.PloughBlock;
|
||||||
|
@ -330,7 +331,7 @@ public class BlockMovementChecks {
|
||||||
return direction.getAxis() != state.getValue(SailBlock.FACING)
|
return direction.getAxis() != state.getValue(SailBlock.FACING)
|
||||||
.getAxis();
|
.getAxis();
|
||||||
if (state.getBlock() instanceof FluidTankBlock)
|
if (state.getBlock() instanceof FluidTankBlock)
|
||||||
return FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(direction));
|
return ConnectivityHandler.isConnected(world, pos, pos.relative(direction)); //FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(direction));
|
||||||
if (state.getBlock() instanceof ItemVaultBlock)
|
if (state.getBlock() instanceof ItemVaultBlock)
|
||||||
return ItemVaultConnectivityHandler.isConnected(world, pos, pos.relative(direction));
|
return ItemVaultConnectivityHandler.isConnected(world, pos, pos.relative(direction));
|
||||||
if (AllBlocks.STICKER.has(state) && state.getValue(StickerBlock.EXTENDED)) {
|
if (AllBlocks.STICKER.has(state) && state.getValue(StickerBlock.EXTENDED)) {
|
||||||
|
@ -349,7 +350,7 @@ public class BlockMovementChecks {
|
||||||
return state.getValue(HarvesterBlock.FACING) == facing;
|
return state.getValue(HarvesterBlock.FACING) == facing;
|
||||||
if (AllBlocks.MECHANICAL_PLOUGH.has(state))
|
if (AllBlocks.MECHANICAL_PLOUGH.has(state))
|
||||||
return state.getValue(PloughBlock.FACING) == facing;
|
return state.getValue(PloughBlock.FACING) == facing;
|
||||||
|
|
||||||
if (AllBlocks.CART_ASSEMBLER.has(state))
|
if (AllBlocks.CART_ASSEMBLER.has(state))
|
||||||
return Direction.DOWN == facing;
|
return Direction.DOWN == facing;
|
||||||
if (AllBlocks.MECHANICAL_SAW.has(state))
|
if (AllBlocks.MECHANICAL_SAW.has(state))
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids.tank;
|
package com.simibubi.create.content.contraptions.fluids.tank;
|
||||||
|
|
||||||
import com.simibubi.create.AllTileEntities;
|
import com.simibubi.create.AllTileEntities;
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling;
|
import com.simibubi.create.content.contraptions.fluids.actors.GenericItemFilling;
|
||||||
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank;
|
import com.simibubi.create.content.contraptions.fluids.tank.CreativeFluidTankTileEntity.CreativeSmartFluidTank;
|
||||||
import com.simibubi.create.content.contraptions.processing.EmptyingByBasin;
|
import com.simibubi.create.content.contraptions.processing.EmptyingByBasin;
|
||||||
|
@ -90,10 +91,10 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
|
||||||
protected void createBlockStateDefinition(Builder<Block, BlockState> p_206840_1_) {
|
protected void createBlockStateDefinition(Builder<Block, BlockState> p_206840_1_) {
|
||||||
p_206840_1_.add(TOP, BOTTOM, SHAPE);
|
p_206840_1_.add(TOP, BOTTOM, SHAPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) {
|
public int getLightEmission(BlockState state, BlockGetter world, BlockPos pos) {
|
||||||
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(world, pos);
|
FluidTankTileEntity tankAt = ConnectivityHandler.partAt(getTileEntityType(), world, pos); //FluidTankConnectivityHandler.anyTankAt(world, pos);
|
||||||
if (tankAt == null)
|
if (tankAt == null)
|
||||||
return 0;
|
return 0;
|
||||||
FluidTankTileEntity controllerTE = tankAt.getControllerTE();
|
FluidTankTileEntity controllerTE = tankAt.getControllerTE();
|
||||||
|
@ -120,7 +121,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
|
||||||
return InteractionResult.PASS;
|
return InteractionResult.PASS;
|
||||||
|
|
||||||
FluidExchange exchange = null;
|
FluidExchange exchange = null;
|
||||||
FluidTankTileEntity te = FluidTankConnectivityHandler.anyTankAt(world, pos);
|
FluidTankTileEntity te = ConnectivityHandler.partAt(getTileEntityType(), world, pos); //FluidTankConnectivityHandler.anyTankAt(world, pos);
|
||||||
if (te == null)
|
if (te == null)
|
||||||
return InteractionResult.FAIL;
|
return InteractionResult.FAIL;
|
||||||
|
|
||||||
|
@ -231,7 +232,8 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
|
||||||
return;
|
return;
|
||||||
FluidTankTileEntity tankTE = (FluidTankTileEntity) te;
|
FluidTankTileEntity tankTE = (FluidTankTileEntity) te;
|
||||||
world.removeBlockEntity(pos);
|
world.removeBlockEntity(pos);
|
||||||
FluidTankConnectivityHandler.splitTank(tankTE);
|
//FluidTankConnectivityHandler.splitTank(tankTE);
|
||||||
|
ConnectivityHandler.splitMulti(tankTE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +241,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
|
||||||
public Class<FluidTankTileEntity> getTileEntityClass() {
|
public Class<FluidTankTileEntity> getTileEntityClass() {
|
||||||
return FluidTankTileEntity.class;
|
return FluidTankTileEntity.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockEntityType<? extends FluidTankTileEntity> getTileEntityType() {
|
public BlockEntityType<? extends FluidTankTileEntity> getTileEntityType() {
|
||||||
return creative ? AllTileEntities.CREATIVE_FLUID_TANK.get() : AllTileEntities.FLUID_TANK.get();
|
return creative ? AllTileEntities.CREATIVE_FLUID_TANK.get() : AllTileEntities.FLUID_TANK.get();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids.tank;
|
package com.simibubi.create.content.contraptions.fluids.tank;
|
||||||
|
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
|
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
|
||||||
import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour;
|
import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour;
|
||||||
|
|
||||||
|
@ -21,6 +22,6 @@ public class FluidTankCTBehaviour extends HorizontalCTBehaviour {
|
||||||
@Override
|
@Override
|
||||||
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos,
|
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos,
|
||||||
Direction face) {
|
Direction face) {
|
||||||
return state.getBlock() == other.getBlock() && FluidTankConnectivityHandler.isConnected(reader, pos, otherPos);
|
return state.getBlock() == other.getBlock() && ConnectivityHandler.isConnected(reader, pos, otherPos); //FluidTankConnectivityHandler.isConnected(reader, pos, otherPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package com.simibubi.create.content.contraptions.fluids.tank;
|
package com.simibubi.create.content.contraptions.fluids.tank;
|
||||||
|
|
||||||
|
import com.simibubi.create.AllTileEntities;
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
@ -71,7 +74,7 @@ public class FluidTankItem extends BlockItem {
|
||||||
|
|
||||||
if (!FluidTankBlock.isTank(placedOnState))
|
if (!FluidTankBlock.isTank(placedOnState))
|
||||||
return;
|
return;
|
||||||
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(world, placedOnPos);
|
FluidTankTileEntity tankAt = ConnectivityHandler.partAt(AllTileEntities.FLUID_TANK.get(), world, placedOnPos); //FluidTankConnectivityHandler.anyTankAt(world, placedOnPos);
|
||||||
if (tankAt == null)
|
if (tankAt == null)
|
||||||
return;
|
return;
|
||||||
FluidTankTileEntity controllerTE = tankAt.getControllerTE();
|
FluidTankTileEntity controllerTE = tankAt.getControllerTE();
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import com.simibubi.create.AllSpriteShifts;
|
import com.simibubi.create.AllSpriteShifts;
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
import com.simibubi.create.foundation.block.connected.CTModel;
|
import com.simibubi.create.foundation.block.connected.CTModel;
|
||||||
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
|
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
@ -28,20 +29,20 @@ public class FluidTankModel extends CTModel {
|
||||||
public static FluidTankModel standard(BakedModel originalModel) {
|
public static FluidTankModel standard(BakedModel originalModel) {
|
||||||
return new FluidTankModel(originalModel, AllSpriteShifts.FLUID_TANK, AllSpriteShifts.COPPER_CASING);
|
return new FluidTankModel(originalModel, AllSpriteShifts.FLUID_TANK, AllSpriteShifts.COPPER_CASING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FluidTankModel creative(BakedModel originalModel) {
|
public static FluidTankModel creative(BakedModel originalModel) {
|
||||||
return new FluidTankModel(originalModel, AllSpriteShifts.CREATIVE_FLUID_TANK, AllSpriteShifts.CREATIVE_CASING);
|
return new FluidTankModel(originalModel, AllSpriteShifts.CREATIVE_FLUID_TANK, AllSpriteShifts.CREATIVE_CASING);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FluidTankModel(BakedModel originalModel, CTSpriteShiftEntry side, CTSpriteShiftEntry top) {
|
private FluidTankModel(BakedModel originalModel, CTSpriteShiftEntry side, CTSpriteShiftEntry top) {
|
||||||
super(originalModel, new FluidTankCTBehaviour(side, top));
|
super(originalModel, new FluidTankCTBehaviour(side, top));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
|
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
|
||||||
CullData cullData = new CullData();
|
CullData cullData = new CullData();
|
||||||
for (Direction d : Iterate.horizontalDirections)
|
for (Direction d : Iterate.horizontalDirections)
|
||||||
cullData.setCulled(d, FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(d)));
|
cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d))); //FluidTankConnectivityHandler.isConnected(world, pos, pos.relative(d)));
|
||||||
return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData);
|
return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ import java.util.List;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.simibubi.create.Create;
|
||||||
|
import com.simibubi.create.api.connectivity.ConnectivityHandler;
|
||||||
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape;
|
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape;
|
||||||
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
|
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
|
@ -79,7 +81,8 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
|
||||||
return;
|
return;
|
||||||
if (!isController())
|
if (!isController())
|
||||||
return;
|
return;
|
||||||
FluidTankConnectivityHandler.formTanks(this);
|
//FluidTankConnectivityHandler.formTanks(this);
|
||||||
|
ConnectivityHandler.formMulti(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -103,7 +106,7 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
|
||||||
if (fluidLevel != null)
|
if (fluidLevel != null)
|
||||||
fluidLevel.tick();
|
fluidLevel.tick();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockPos getLastKnownPos() {
|
public BlockPos getLastKnownPos() {
|
||||||
return lastKnownPos;
|
return lastKnownPos;
|
||||||
|
@ -145,7 +148,7 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
|
||||||
for (int xOffset = 0; xOffset < width; xOffset++) {
|
for (int xOffset = 0; xOffset < width; xOffset++) {
|
||||||
for (int zOffset = 0; zOffset < width; zOffset++) {
|
for (int zOffset = 0; zOffset < width; zOffset++) {
|
||||||
BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset);
|
BlockPos pos = this.worldPosition.offset(xOffset, yOffset, zOffset);
|
||||||
FluidTankTileEntity tankAt = FluidTankConnectivityHandler.anyTankAt(level, pos);
|
FluidTankTileEntity tankAt = ConnectivityHandler.partAt(getType(), level, pos); //FluidTankConnectivityHandler.anyTankAt(level, pos);
|
||||||
if (tankAt == null)
|
if (tankAt == null)
|
||||||
continue;
|
continue;
|
||||||
level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState()
|
level.updateNeighbourForOutputSignal(pos, tankAt.getBlockState()
|
||||||
|
@ -161,7 +164,7 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
|
||||||
setChanged();
|
setChanged();
|
||||||
sendData();
|
sendData();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isVirtual()) {
|
if (isVirtual()) {
|
||||||
if (fluidLevel == null)
|
if (fluidLevel == null)
|
||||||
fluidLevel = new InterpolatedChasingValue().start(getFillState());
|
fluidLevel = new InterpolatedChasingValue().start(getFillState());
|
||||||
|
@ -462,4 +465,82 @@ public class FluidTankTileEntity extends SmartTileEntity implements IHaveGoggleI
|
||||||
this.fluidLevel = fluidLevel;
|
this.fluidLevel = fluidLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void preventConnectivityUpdate() { updateConnectivity = false; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void notifyMultiUpdated () {
|
||||||
|
BlockState state = this.getBlockState();
|
||||||
|
if (FluidTankBlock.isTank(state)) { // safety
|
||||||
|
state = state.setValue(FluidTankBlock.BOTTOM, getController().getY() == getBlockPos().getY());
|
||||||
|
state = state.setValue(FluidTankBlock.TOP, getController().getY() + height - 1 == getBlockPos().getY());
|
||||||
|
level.setBlock(getBlockPos(), state, 22);
|
||||||
|
}
|
||||||
|
setWindows(window);
|
||||||
|
onFluidStackChanged(tankInventory.getFluid());
|
||||||
|
setChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setExtraData (@Nullable Object data) {
|
||||||
|
if (data instanceof Boolean) window = (boolean)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Nullable
|
||||||
|
public Object getExtraData () { return window; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object modifyExtraData (Object data) {
|
||||||
|
if (data instanceof Boolean windows) {
|
||||||
|
windows |= window;
|
||||||
|
return windows;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Direction.Axis getMainConnectionAxis() { return Direction.Axis.Y; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxLength (Direction.Axis longAxis, int width) {
|
||||||
|
if (longAxis == Direction.Axis.Y) return getMaxHeight();
|
||||||
|
return getMaxWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxWidth () { return MAX_SIZE; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight () { return height; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHeight (int height) { this.height = height; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getWidth () { return width; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setWidth (int width) { this.width = width; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasFluid () { return true; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTankSize (int tank) { return getCapacityMultiplier(); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTankSize (int tank, int blocks) {
|
||||||
|
applyFluidTankSize(blocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IFluidTank getTank (int tank) {
|
||||||
|
return tankInventory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack getFluid (int tank) {
|
||||||
|
return tankInventory.getFluid().copy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,69 @@
|
||||||
package com.simibubi.create.foundation.tileEntity;
|
package com.simibubi.create.foundation.tileEntity;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Direction;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
||||||
|
import net.minecraftforge.fluids.FluidStack;
|
||||||
|
import net.minecraftforge.fluids.IFluidTank;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public interface IMultiTileContainer {
|
public interface IMultiTileContainer {
|
||||||
|
|
||||||
public BlockPos getController();
|
|
||||||
public boolean isController();
|
|
||||||
public void setController(BlockPos pos);
|
|
||||||
public BlockPos getLastKnownPos();
|
|
||||||
|
|
||||||
|
BlockPos getController();
|
||||||
|
<T extends BlockEntity & IMultiTileContainer> T getControllerTE ();
|
||||||
|
boolean isController();
|
||||||
|
void setController(BlockPos pos);
|
||||||
|
void removeController (boolean keepContents);
|
||||||
|
BlockPos getLastKnownPos();
|
||||||
|
|
||||||
|
void preventConnectivityUpdate ();
|
||||||
|
void notifyMultiUpdated ();
|
||||||
|
|
||||||
|
// only used for FluidTank windows at present. Might be useful for similar properties on other things?
|
||||||
|
default void setExtraData (@Nullable Object data) {}
|
||||||
|
@Nullable
|
||||||
|
default Object getExtraData () { return null; }
|
||||||
|
default Object modifyExtraData (Object data) { return data; }
|
||||||
|
|
||||||
|
// multiblock structural information
|
||||||
|
Direction.Axis getMainConnectionAxis();
|
||||||
|
default Direction.Axis getMainAxisOf (BlockEntity be) { // this feels redundant, but it gives us a default to use when defining ::getMainConnectionAxis
|
||||||
|
BlockState state = be.getBlockState();
|
||||||
|
|
||||||
|
Direction.Axis axis;
|
||||||
|
if (state.hasProperty(BlockStateProperties.HORIZONTAL_AXIS)) {
|
||||||
|
axis = state.getValue(BlockStateProperties.HORIZONTAL_AXIS);
|
||||||
|
}
|
||||||
|
else if (state.hasProperty(BlockStateProperties.FACING)) {
|
||||||
|
axis = state.getValue(BlockStateProperties.FACING).getAxis();
|
||||||
|
}
|
||||||
|
else if (state.hasProperty(BlockStateProperties.HORIZONTAL_FACING)) {
|
||||||
|
axis = state.getValue(BlockStateProperties.HORIZONTAL_FACING).getAxis();
|
||||||
|
}
|
||||||
|
else axis = Direction.Axis.Y;
|
||||||
|
|
||||||
|
return axis;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getMaxLength (Direction.Axis longAxis, int width);
|
||||||
|
int getMaxWidth ();
|
||||||
|
|
||||||
|
int getHeight ();
|
||||||
|
void setHeight (int height);
|
||||||
|
int getWidth ();
|
||||||
|
void setWidth (int width);
|
||||||
|
|
||||||
|
// optional item handling
|
||||||
|
default boolean hasItems () { return false; }
|
||||||
|
|
||||||
|
// optional fluid handling
|
||||||
|
// done here rather than through the Capability to allow greater flexibility
|
||||||
|
default boolean hasFluid () { return false; }
|
||||||
|
default int getTankSize (int tank) { return 0; }
|
||||||
|
default void setTankSize (int tank, int blocks) {}
|
||||||
|
default IFluidTank getTank (int tank) { return null; }
|
||||||
|
default FluidStack getFluid (int tank) { return FluidStack.EMPTY; }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue