Skip to content

Commit

Permalink
Multi-Fluid Hatches (#141)
Browse files Browse the repository at this point in the history
  • Loading branch information
Dane Strandboge authored Sep 16, 2021
1 parent eb4eb2f commit ca2f2a3
Show file tree
Hide file tree
Showing 14 changed files with 274 additions and 7 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG-GTCEU.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@
- Can be applied to Pickaxes, and will automatically crush ores when mined
- Will output their "normal" amount by default (1 crushed ore for most, but more for some, like Redstone)
- When combined with Fortune, can output up to their Macerated amount
- Quadruple and Nonuple Input/Output Hatches added, holding either 4 or 9 fluids each, and 16B per fluid
- Fluids in them are forced to be "unique," for example Water cannot occupy 2 slots of either an Input or Output version
- Can be used in any multiblock, EXCEPT the Output hatches cannot be used in the Distillation Tower
- TODO Maintenance/Muffler

### Major Recipe Changes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gregtech.api.capability;


import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;

Expand All @@ -13,4 +14,8 @@ public interface IMultipleTankHandler extends IFluidHandler, Iterable<IFluidTank
int getTanks();

IFluidTank getTankAt(int index);

int getIndexOfFluid(FluidStack other);

boolean allowSameFluidFill();
}
26 changes: 23 additions & 3 deletions src/main/java/gregtech/api/capability/impl/FluidTankList.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@
import javax.annotation.Nullable;
import java.util.*;

/**
* Recommended to use this with {@link NotifiableFluidTankFromList} to ensure
* proper behavior of the "allowSameFluidFill" setting, but not required.
*/
public class FluidTankList implements IFluidHandler, IMultipleTankHandler, INBTSerializable<NBTTagCompound> {

protected final List<IFluidTank> fluidTanks;
protected IFluidTankProperties[] properties;
protected final boolean allowSameFluidFill;
private final boolean allowSameFluidFill;
private IFluidTankProperties[] fluidTankProperties;

public FluidTankList(boolean allowSameFluidFill, IFluidTank... fluidTanks) {
Expand Down Expand Up @@ -95,7 +99,7 @@ private int fillTanksImpl(FluidStack resource, boolean doFill) {
totalFilled += filledAmount;
resource.amount -= filledAmount;
//if filling multiple tanks is not allowed, or resource is empty, return now
if (!allowSameFluidFill || resource.amount == 0)
if (!allowSameFluidFill() || resource.amount == 0)
return totalFilled;
}
}
Expand All @@ -105,7 +109,7 @@ private int fillTanksImpl(FluidStack resource, boolean doFill) {
int filledAmount = handler.fill(resource, doFill);
totalFilled += filledAmount;
resource.amount -= filledAmount;
if (!allowSameFluidFill || resource.amount == 0)
if (!allowSameFluidFill() || resource.amount == 0)
return totalFilled;
}
}
Expand Down Expand Up @@ -204,4 +208,20 @@ protected void validateTankIndex(int tank) {
if (tank < 0 || tank >= fluidTanks.size())
throw new RuntimeException("Tank " + tank + " not in valid range - (0," + fluidTanks.size() + "]");
}

@Override
public int getIndexOfFluid(FluidStack fluidStack) {
for (int i = 0; i < fluidTanks.size(); i++) {
FluidStack tankStack = fluidTanks.get(i).getFluid();
if (tankStack != null && tankStack.isFluidEqual(fluidStack)) {
return i;
}
}
return -1;
}

@Override
public boolean allowSameFluidFill() {
return allowSameFluidFill;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package gregtech.api.capability.impl;

import gregtech.api.capability.IMultipleTankHandler;
import gregtech.api.metatileentity.MetaTileEntity;
import net.minecraftforge.fluids.FluidStack;

import java.util.function.Supplier;

public abstract class NotifiableFluidTankFromList extends NotifiableFluidTank {

private final int index;

public NotifiableFluidTankFromList(int capacity, MetaTileEntity entityToNotify, boolean isExport, int index) {
super(capacity, entityToNotify, isExport);
this.index = index;
}

public abstract Supplier<IMultipleTankHandler> getFluidTankList();

public int getIndex() {
return index;
}

@Override
public int fill(FluidStack resource, boolean doFill) {
IMultipleTankHandler tanks = getFluidTankList().get();
if (!tanks.allowSameFluidFill()) {
int fillIndex = tanks.getIndexOfFluid(resource);
if (fillIndex != getIndex() && fillIndex != -1) return 0;
}
return super.fill(resource, doFill);
}
}
2 changes: 2 additions & 0 deletions src/main/java/gregtech/api/render/Textures.java
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ public class Textures {
public static final SimpleOverlayRenderer INFINITE_WATER = new SimpleOverlayRenderer("cover/overlay_infinite_water", true);
public static final SimpleOverlayRenderer PIPE_OUT_OVERLAY = new SimpleOverlayRenderer("overlay/machine/overlay_pipe_out");
public static final SimpleOverlayRenderer PIPE_IN_OVERLAY = new SimpleOverlayRenderer("overlay/machine/overlay_pipe_in");
public static final SimpleOverlayRenderer PIPE_4X_OVERLAY = new SimpleOverlayRenderer("overlay/machine/overlay_pipe_4x");
public static final SimpleOverlayRenderer PIPE_9X_OVERLAY = new SimpleOverlayRenderer("overlay/machine/overlay_pipe_9x");

// todo should we do emissive for these auto-output overlays?
public static final SimpleOverlayRenderer FLUID_OUTPUT_OVERLAY = new SimpleOverlayRenderer("overlay/machine/overlay_fluid_output");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ public class MetaTileEntities {
public static final MetaTileEntityItemBus[] ITEM_EXPORT_BUS = new MetaTileEntityItemBus[GTValues.UHV + 1];
public static final MetaTileEntityFluidHatch[] FLUID_IMPORT_HATCH = new MetaTileEntityFluidHatch[GTValues.UHV + 1];
public static final MetaTileEntityFluidHatch[] FLUID_EXPORT_HATCH = new MetaTileEntityFluidHatch[GTValues.UHV + 1];
public static final MetaTileEntityMultiFluidHatch[] MULTI_FLUID_IMPORT_HATCH = new MetaTileEntityMultiFluidHatch[2];
public static final MetaTileEntityMultiFluidHatch[] MULTI_FLUID_EXPORT_HATCH = new MetaTileEntityMultiFluidHatch[2];
public static final MetaTileEntityEnergyHatch[] ENERGY_INPUT_HATCH = new MetaTileEntityEnergyHatch[GTValues.V.length];
public static final MetaTileEntityAdjustableEnergyHatch[] ENERGY_INPUT_HATCH_ADJUSTABLE = new MetaTileEntityAdjustableEnergyHatch[GTValues.V.length];
public static final MetaTileEntityEnergyHatch[] ENERGY_OUTPUT_HATCH = new MetaTileEntityEnergyHatch[GTValues.V.length];
Expand Down Expand Up @@ -491,6 +493,12 @@ public static void init() {
GregTechAPI.registerMetaTileEntity(1180 + 9, FLUID_IMPORT_HATCH[9]);
GregTechAPI.registerMetaTileEntity(1195 + 9, FLUID_EXPORT_HATCH[9]);

// Multi-Fluid Hatches
MULTI_FLUID_IMPORT_HATCH[0] = GregTechAPI.registerMetaTileEntity(1190, new MetaTileEntityMultiFluidHatch(gregtechId("fluid_hatch.import_4x"), 2, false));
MULTI_FLUID_IMPORT_HATCH[1] = GregTechAPI.registerMetaTileEntity(1191, new MetaTileEntityMultiFluidHatch(gregtechId("fluid_hatch.import_9x"), 3, false));
MULTI_FLUID_EXPORT_HATCH[0] = GregTechAPI.registerMetaTileEntity(1205, new MetaTileEntityMultiFluidHatch(gregtechId("fluid_hatch.export_4x"), 2, true));
MULTI_FLUID_EXPORT_HATCH[1] = GregTechAPI.registerMetaTileEntity(1206, new MetaTileEntityMultiFluidHatch(gregtechId("fluid_hatch.export_9x"), 3, true));

// Energy Input/Output Hatches, IDs 1210-1269
endPos = GTValues.HT ? ENERGY_INPUT_HATCH.length - 1 : Math.min(ENERGY_INPUT_HATCH.length - 1, GTValues.UV + 1);
for (int i = 0; i < endPos; i++) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package gregtech.common.metatileentities.electric.multiblockpart;

import codechicken.lib.render.CCRenderState;
import codechicken.lib.render.pipeline.IVertexOperation;
import codechicken.lib.vec.Matrix4;
import gregtech.api.capability.IMultipleTankHandler;
import gregtech.api.capability.impl.FluidTankList;
import gregtech.api.capability.impl.NotifiableFluidTank;
import gregtech.api.capability.impl.NotifiableFluidTankFromList;
import gregtech.api.gui.GuiTextures;
import gregtech.api.gui.ModularUI;
import gregtech.api.gui.widgets.TankWidget;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.MetaTileEntityHolder;
import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart;
import gregtech.api.metatileentity.multiblock.MultiblockAbility;
import gregtech.api.metatileentity.multiblock.MultiblockControllerBase;
import gregtech.api.render.ICubeRenderer;
import gregtech.api.render.SimpleOverlayRenderer;
import gregtech.api.render.Textures;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.IFluidTank;

import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Supplier;

public class MetaTileEntityMultiFluidHatch extends MetaTileEntityMultiblockPart implements IMultiblockAbilityPart<IFluidTank> {

private static final int TANK_SIZE = 16000;

protected FluidTankList fluidTanks;
private final boolean isExportHatch;

public MetaTileEntityMultiFluidHatch(ResourceLocation metaTileEntityId, int tier, boolean isExportHatch) {
super(metaTileEntityId, tier);
this.isExportHatch = isExportHatch;
initializeInventory();
}

@Override
public MetaTileEntity createMetaTileEntity(MetaTileEntityHolder metaTileEntityHolder) {
return new MetaTileEntityMultiFluidHatch(metaTileEntityId, this.getTier(), this.isExportHatch);
}

@Override
protected void initializeInventory() {
FluidTank[] fluidsHandlers = new FluidTank[(int) Math.pow(this.getTier(), 2)];
for (int i = 0; i <fluidsHandlers.length; i++) {
fluidsHandlers[i] = new NotifiableFluidTankFromList(TANK_SIZE, this, isExportHatch, i) {
@Override
public Supplier<IMultipleTankHandler> getFluidTankList() {
return () -> MetaTileEntityMultiFluidHatch.this.fluidTanks;
}
};
}
this.fluidTanks = new FluidTankList(false, fluidsHandlers);
this.fluidInventory = fluidTanks;
super.initializeInventory();
}

@Override
public void update() {
super.update();
if (!getWorld().isRemote) {
if (isExportHatch) {
pushFluidsIntoNearbyHandlers(getFrontFacing());
} else {
pullFluidsFromNearbyHandlers(getFrontFacing());
}
}
}

@Override
public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, IVertexOperation[] pipeline) {
super.renderMetaTileEntity(renderState, translation, pipeline);
if (shouldRenderOverlay()) {
SimpleOverlayRenderer renderer = getTier() == 2 ? Textures.PIPE_4X_OVERLAY : Textures.PIPE_9X_OVERLAY;
renderer.renderSided(getFrontFacing(), renderState, translation, pipeline);
}
}

@Override
public ICubeRenderer getBaseTexture() {
MultiblockControllerBase controller = getController();
if (controller != null) {
this.hatchTexture = controller.getBaseTexture(this);
}
if (controller == null && this.hatchTexture != null) {
return this.hatchTexture;
}
if (controller == null) {
this.setPaintingColor(DEFAULT_PAINTING_COLOR);
return Textures.VOLTAGE_CASINGS[getTier() == 2 ? 3 : 5];
}
this.setPaintingColor(0xFFFFFF);
return controller.getBaseTexture(this);
}

@Override
public void addInformation(ItemStack stack, @Nullable World player, List<String> tooltip, boolean advanced) {
super.addInformation(stack, player, tooltip, advanced);
tooltip.add(I18n.format("gregtech.machine.multi_fluid_hatch_universal.tooltip.1"));
tooltip.add(I18n.format("gregtech.machine.multi_fluid_hatch_universal.tooltip.2", (int) Math.pow(this.getTier(), 2)));
}

@Override
protected FluidTankList createImportFluidHandler() {
return isExportHatch ? new FluidTankList(false) : new FluidTankList(false, fluidTanks);
}

@Override
protected FluidTankList createExportFluidHandler() {
return new FluidTankList(false, fluidTanks);
}

@Override
public MultiblockAbility<IFluidTank> getAbility() {
return isExportHatch ? MultiblockAbility.EXPORT_FLUIDS : MultiblockAbility.IMPORT_FLUIDS;
}

@Override
public void registerAbilities(List<IFluidTank> abilityList) {
abilityList.addAll(isExportHatch ? this.exportFluids.getFluidTanks() : this.importFluids.getFluidTanks());
}

@Override
public void setupNotifiableMetaTileEntity(MetaTileEntity metaTileEntity) {
FluidTankList handlers;
if (isExportHatch) {
handlers = getExportFluids();
} else {
handlers = getImportFluids();
}
if (handlers != null) {
for (IFluidTank fluidTank : handlers) {
if (fluidTank instanceof NotifiableFluidTank) {
NotifiableFluidTank handler = (NotifiableFluidTank) fluidTank;
handler.setNotifiableMetaTileEntity(metaTileEntity);
handler.addToNotifiedList(this, handler, isExportHatch);
}
}
}
}

@Override
protected ModularUI createUI(EntityPlayer entityPlayer) {
int rowSize = getTier();
ModularUI.Builder builder = ModularUI.builder(GuiTextures.BACKGROUND, 176,
18 + 18 * rowSize + 94)
.label(10, 5, getMetaFullName());

for (int y = 0; y < rowSize; y++) {
for (int x = 0; x < rowSize; x++) {
int index = y * rowSize + x;
builder.widget(new TankWidget(isExportHatch ? exportFluids.getTankAt(index) : importFluids.getTankAt(index), 89 - rowSize * 9 + x * 18, 18 + y * 18, 18, 18)
.setBackgroundTexture(GuiTextures.FLUID_SLOT)
.setContainerClicking(true, !isExportHatch)
.setAlwaysShowFull(true));
}
}
builder.bindPlayerInventory(entityPlayer.inventory, GuiTextures.SLOT, 7, 18 + 18 * rowSize + 12);
return builder.build(getHolder(), entityPlayer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public abstract class MetaTileEntityMultiblockPart extends MetaTileEntity implem
private final int tier;
private BlockPos controllerPos;
private MultiblockControllerBase controllerTile;
private ICubeRenderer hatchTexture = null;
protected ICubeRenderer hatchTexture = null;

public MetaTileEntityMultiblockPart(ResourceLocation metaTileEntityId, int tier) {
super(metaTileEntityId);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.api.metatileentity.MetaTileEntityHolder;
import gregtech.api.metatileentity.multiblock.IMultiblockAbilityPart;
import gregtech.api.metatileentity.multiblock.IMultiblockPart;
import gregtech.api.metatileentity.multiblock.MultiblockAbility;
import gregtech.api.metatileentity.multiblock.RecipeMapMultiblockController;
Expand All @@ -15,6 +16,7 @@
import gregtech.api.render.Textures;
import gregtech.common.blocks.BlockMetalCasing.MetalCasingType;
import gregtech.common.blocks.MetaBlocks;
import gregtech.common.metatileentities.electric.multiblockpart.MetaTileEntityMultiFluidHatch;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
Expand Down Expand Up @@ -64,21 +66,30 @@ protected void addDisplayText(List<ITextComponent> textList) {

@Override
protected BlockPattern createStructurePattern() {
Predicate<BlockWorldState> fluidExportPredicate = countMatch("HatchesAmount", abilityPartPredicate(MultiblockAbility.EXPORT_FLUIDS));
Predicate<PatternMatchContext> exactlyOneHatch = context -> context.getInt("HatchesAmount") == 1;
return FactoryBlockPattern.start(RIGHT, FRONT, UP)
.aisle("YSY", "YYY", "YYY")
.aisle("XXX", "X#X", "XXX").setRepeatable(0, 11)
.aisle("XXX", "XXX", "XXX")
.where('S', selfPredicate())
.where('Y', statePredicate(getCasingState()).or(abilityPartPredicate(ALLOWED_ABILITIES)))
.where('X', fluidExportPredicate.or(maintenancePredicate(getCasingState())))
.where('X', dtAbilityPartPredicate().or(maintenancePredicate(getCasingState())))
.where('#', isAirPredicate())
.validateLayer(1, exactlyOneHatch)
.validateLayer(2, exactlyOneHatch)
.build();
}

private Predicate<BlockWorldState> dtAbilityPartPredicate() {
return countMatch("HatchesAmount", abilityPartPredicate(MultiblockAbility.EXPORT_FLUIDS)).and(tilePredicate((state, tile) -> {
if (tile instanceof IMultiblockAbilityPart<?>) {
MultiblockAbility<?> ability = ((IMultiblockAbilityPart<?>) tile).getAbility();
return ability == MultiblockAbility.EXPORT_FLUIDS && !(tile instanceof MetaTileEntityMultiFluidHatch);
}
return false;
}));
}

@Override
protected boolean allowSameFluidFillForOutputs() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ public float getDefaultZoom() {
protected void generateBlockTooltips() {
super.generateBlockTooltips();
ITextComponent tooltip = new TextComponentTranslation("gregtech.multiblock.preview.limit_per_layer", 1).setStyle(new Style().setColor(TextFormatting.DARK_RED));
ITextComponent inputTooltip = new TextComponentTranslation("gregtech.multiblock.preview.only_location", I18n.format("gregtech.multiblock.preview.location.b_c")).setStyle(new Style().setColor(TextFormatting.DARK_RED));
ITextComponent inputTooltip = new TextComponentTranslation("gregtech.multiblock.preview.only_location", I18n.format("gregtech.multiblock.preview.location.b_l")).setStyle(new Style().setColor(TextFormatting.DARK_RED));
ITextComponent outputTooltip = new TextComponentTranslation("gregtech.multiblock.preview.distillation_multi_fluid").setStyle(new Style().setColor(TextFormatting.RED));

for (int i = 0; i < GTValues.UHV + 1; i++) {
addBlockTooltip(MetaTileEntities.FLUID_EXPORT_HATCH[i].getStackForm(), tooltip);
addBlockTooltip(MetaTileEntities.FLUID_EXPORT_HATCH[i].getStackForm(), outputTooltip);
addBlockTooltip(MetaTileEntities.FLUID_IMPORT_HATCH[i].getStackForm(), inputTooltip);
}
}
Expand Down
Loading

0 comments on commit ca2f2a3

Please sign in to comment.