Fluid API rework (#5983)

- Moved forge fluids into FluidAttributes companion object to the vanilla Fluid. By gigaherz
- Redesigned the Fluid API to be closer to the Items API. By King Lemming
Co-authored-by: King Lemming <kinglemming@gmail.com>
This commit is contained in:
David Quintana 2019-07-28 21:35:30 +02:00
parent e784a7f606
commit b7e1cc5f6b
48 changed files with 1077 additions and 2193 deletions

View File

@ -0,0 +1,15 @@
--- a/net/minecraft/client/renderer/FluidBlockRenderer.java
+++ b/net/minecraft/client/renderer/FluidBlockRenderer.java
@@ -58,8 +58,10 @@
public boolean func_217638_a(IEnviromentBlockReader p_217638_1_, BlockPos p_217638_2_, BufferBuilder p_217638_3_, IFluidState p_217638_4_) {
boolean flag = p_217638_4_.func_206884_a(FluidTags.field_206960_b);
- TextureAtlasSprite[] atextureatlassprite = flag ? this.field_178272_a : this.field_178271_b;
- int i = flag ? 16777215 : BiomeColors.func_217612_c(p_217638_1_, p_217638_2_);
+ TextureAtlasSprite[] atextureatlassprite = net.minecraftforge.client.ForgeHooksClient.getFluidSprites(p_217638_1_, p_217638_2_, p_217638_4_);
+ if (atextureatlassprite == null) atextureatlassprite = flag ? this.field_178272_a : this.field_178271_b;
+ int i = p_217638_4_.func_206886_c().getAttributes().getColor(p_217638_1_, p_217638_2_);
+ if (i < 0) i = flag ? 16777215 : BiomeColors.func_217612_c(p_217638_1_, p_217638_2_);
float f = (float)(i >> 16 & 255) / 255.0F;
float f1 = (float)(i >> 8 & 255) / 255.0F;
float f2 = (float)(i & 255) / 255.0F;

View File

@ -9,7 +9,7 @@
public static final ObjectIntIdentityMap<IFluidState> field_207201_d = new ObjectIntIdentityMap<>();
protected final StateContainer<Fluid, IFluidState> field_207202_e;
private IFluidState field_207200_b;
@@ -102,4 +102,10 @@
@@ -102,4 +102,41 @@
}
public abstract VoxelShape func_215664_b(IFluidState p_215664_1_, IBlockReader p_215664_2_, BlockPos p_215664_3_);
@ -18,5 +18,36 @@
+ @Override
+ public java.util.Set<net.minecraft.util.ResourceLocation> getTags() {
+ return reverseTags.getTagNames();
+ }
+
+ /**
+ * Creates the fluid attributes object, which will contain all the extended values for the fluid that aren't part of the vanilla system.
+ * Do not call this from outside. To retrieve the values use {@link Fluid#getAttributes()}
+ */
+ protected net.minecraftforge.fluids.FluidAttributes createAttributes(Fluid fluid)
+ {
+ if (fluid instanceof EmptyFluid)
+ return net.minecraftforge.fluids.FluidAttributes.builder("empty", null, null)
+ .vanillaColor().density(0).temperature(0).luminosity(0).viscosity(0).density(0).build();
+ if (fluid instanceof WaterFluid)
+ return net.minecraftforge.fluids.FluidAttributes.builder("water",
+ new net.minecraft.util.ResourceLocation("block/water_still"),
+ new net.minecraft.util.ResourceLocation("block/water_flow"))
+ .overlay(new net.minecraft.util.ResourceLocation("block/water_overlay"))
+ .vanillaColor().block(() -> net.minecraft.block.Blocks.field_150355_j).build();
+ if (fluid instanceof LavaFluid)
+ return net.minecraftforge.fluids.FluidAttributes.builder("lava",
+ new net.minecraft.util.ResourceLocation("block/lava_still"),
+ new net.minecraft.util.ResourceLocation("block/lava_flow"))
+ .block(() -> net.minecraft.block.Blocks.field_150353_l)
+ .vanillaColor().luminosity(15).density(3000).viscosity(6000).temperature(1300).build();
+ throw new RuntimeException("Mod fluids must override createAttributes.");
+ }
+
+ private net.minecraftforge.fluids.FluidAttributes forgeFluidAttributes;
+ public final net.minecraftforge.fluids.FluidAttributes getAttributes() {
+ if (forgeFluidAttributes == null)
+ forgeFluidAttributes = createAttributes(this);
+ return forgeFluidAttributes;
+ }
}

View File

@ -9,8 +9,25 @@
if (raytraceresult.func_216346_c() == RayTraceResult.Type.MISS) {
return new ActionResult<>(ActionResultType.PASS, itemstack);
} else if (raytraceresult.func_216346_c() != RayTraceResult.Type.BLOCK) {
@@ -150,4 +152,12 @@
SoundEvent soundevent = this.field_77876_a.func_207185_a(FluidTags.field_206960_b) ? SoundEvents.field_187627_L : SoundEvents.field_187624_K;
@@ -52,7 +54,10 @@
Fluid fluid = ((IBucketPickupHandler)blockstate1.func_177230_c()).func_204508_a(p_77659_1_, blockpos, blockstate1);
if (fluid != Fluids.field_204541_a) {
p_77659_2_.func_71029_a(Stats.field_75929_E.func_199076_b(this));
- p_77659_2_.func_184185_a(fluid.func_207185_a(FluidTags.field_206960_b) ? SoundEvents.field_187633_N : SoundEvents.field_187630_M, 1.0F, 1.0F);
+
+ SoundEvent soundevent = field_77876_a.getAttributes().getEmptySound();
+ if(soundevent == null) soundevent = fluid.func_207185_a(FluidTags.field_206960_b) ? SoundEvents.field_187633_N : SoundEvents.field_187630_M;
+ p_77659_2_.func_184185_a(soundevent, 1.0F, 1.0F);
ItemStack itemstack1 = this.func_150910_a(itemstack, p_77659_2_, fluid.func_204524_b());
if (!p_77659_1_.field_72995_K) {
CriteriaTriggers.field_204813_j.func_204817_a((ServerPlayerEntity)p_77659_2_, new ItemStack(fluid.func_204524_b()));
@@ -147,7 +152,18 @@
}
protected void func_203791_b(@Nullable PlayerEntity p_203791_1_, IWorld p_203791_2_, BlockPos p_203791_3_) {
- SoundEvent soundevent = this.field_77876_a.func_207185_a(FluidTags.field_206960_b) ? SoundEvents.field_187627_L : SoundEvents.field_187624_K;
+ SoundEvent soundevent = field_77876_a.getAttributes().getEmptySound();
+ if(soundevent == null) soundevent = this.field_77876_a.func_207185_a(FluidTags.field_206960_b) ? SoundEvents.field_187627_L : SoundEvents.field_187624_K;
p_203791_2_.func_184133_a(p_203791_1_, p_203791_3_, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
+
@ -21,4 +38,6 @@
+ else
+ return super.initCapabilities(stack, nbt);
+ }
+
+ public Fluid getFluid() { return field_77876_a; }
}

View File

@ -32,7 +32,7 @@ public class FluidContainerColorer implements IItemColor
{
if (tintIndex != 1) return 0xFFFFFFFF;
return FluidUtil.getFluidContained(stack)
.map(fstack -> fstack.getFluid().getColor(fstack))
.map(fstack -> fstack.getFluid().getAttributes().getColor(fstack))
.orElse(0xFFFFFFFF);
}
}

View File

@ -1,50 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.client;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fluids.FluidRegistry;
public class ForgeClientHandler
{
@SubscribeEvent
public static void registerModels(ModelRegistryEvent event)
{
// register model for the universal bucket, if it exists
if (FluidRegistry.isUniversalBucketEnabled())
{
// TODO no more mesh definitions, this should be implemented with overrides
// ModelLoader.setBucketModelDefinition(ForgeMod.getInstance().universalBucket);
}
}
@SubscribeEvent
public static void registerItemHandlers(ColorHandlerEvent.Item event)
{
if (FluidRegistry.isUniversalBucketEnabled())
{
event.getItemColors().register(new FluidContainerColorer(), ForgeMod.getInstance().universalBucket);
}
}
}

View File

@ -560,6 +560,15 @@ public class ForgeHooksClient
}
}
public static TextureAtlasSprite[] getFluidSprites(IEnviromentBlockReader world, BlockPos pos, IFluidState fluidStateIn)
{
AtlasTexture atlas = Minecraft.getInstance().getTextureMap();
return new TextureAtlasSprite[] {
atlas.getSprite(fluidStateIn.getFluid().getAttributes().getStill(world, pos)),
atlas.getSprite(fluidStateIn.getFluid().getAttributes().getFlowing(world, pos)),
};
}
private static class LightGatheringTransformer extends QuadGatheringTransformer {
private static final VertexFormat FORMAT = new VertexFormat().addElement(DefaultVertexFormats.TEX_2F).addElement(DefaultVertexFormats.TEX_2S);

View File

@ -37,6 +37,7 @@ import net.minecraft.client.renderer.texture.AtlasTexture;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.resources.data.AnimationMetadataSection;
import net.minecraft.entity.LivingEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.ItemStack;
import net.minecraft.resources.IResource;
import net.minecraft.resources.IResourceManager;
@ -46,7 +47,6 @@ import net.minecraft.world.World;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidUtil;
import java.util.function.Function;
@ -113,7 +113,7 @@ public final class ModelDynBucket implements IUnbakedModel
if (coverLocation != null)
builder.add(coverLocation);
if (fluid != null)
builder.add(fluid.getStill());
builder.add(fluid.getAttributes().getStillTexture());
return builder.build();
}
@ -132,7 +132,7 @@ public final class ModelDynBucket implements IUnbakedModel
ImmutableMap<TransformType, TRSRTransformation> transformMap = PerspectiveMapWrapper.getTransforms(state);
// if the fluid is lighter than air, will manipulate the initial state to be rotated 180° to turn it upside down
if (flipGas && fluid != null && fluid.isLighterThanAir())
if (flipGas && fluid != null && fluid.getAttributes().isLighterThanAir())
{
sprite = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null)));
state = sprite.getState();
@ -144,7 +144,7 @@ public final class ModelDynBucket implements IUnbakedModel
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
if(fluid != null) {
fluidSprite = spriteGetter.apply(fluid.getStill());
fluidSprite = spriteGetter.apply(fluid.getAttributes().getStillTexture());
}
Random random = new Random();
@ -160,8 +160,8 @@ public final class ModelDynBucket implements IUnbakedModel
{
TextureAtlasSprite liquid = spriteGetter.apply(liquidLocation);
// build liquid layer (inside)
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, tint ? fluid.getColor() : 0xFFFFFFFF, 1));
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, tint ? fluid.getColor() : 0xFFFFFFFF, 1));
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, NORTH_Z_FLUID, Direction.NORTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1));
builder.addAll(ItemTextureQuadConverter.convertTexture(format, transform, liquid, fluidSprite, SOUTH_Z_FLUID, Direction.SOUTH, tint ? fluid.getAttributes().getColor() : 0xFFFFFFFF, 1));
particleSprite = fluidSprite;
}
if (coverLocation != null)
@ -441,7 +441,7 @@ public final class ModelDynBucket implements IUnbakedModel
BakedDynBucket model = (BakedDynBucket)originalModel;
Fluid fluid = fluidStack.getFluid();
String name = fluid.getName();
String name = fluid.getAttributes().getName();
if (!model.cache.containsKey(name))
{

View File

@ -37,6 +37,7 @@ import net.minecraft.client.renderer.model.ItemCameraTransforms.TransformType;
import net.minecraft.client.renderer.texture.ISprite;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.fluid.Fluid;
import net.minecraft.resources.IResourceManager;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
@ -45,10 +46,9 @@ import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.pipeline.IVertexConsumer;
import net.minecraftforge.client.model.pipeline.TRSRTransformer;
import net.minecraftforge.client.model.pipeline.UnpackedBakedQuad;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.common.model.IModelState;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.fluids.Fluid;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.LogManager;
@ -79,9 +79,10 @@ public final class ModelFluid implements IUnbakedModel
@Override
public Collection<ResourceLocation> getTextures(Function<ResourceLocation, IUnbakedModel> modelGetter, Set<String> missingTextureErrors)
{
return fluid.getOverlay() != null
? ImmutableSet.of(fluid.getStill(), fluid.getFlowing(), fluid.getOverlay())
: ImmutableSet.of(fluid.getStill(), fluid.getFlowing());
FluidAttributes attrs = fluid.getAttributes();
return attrs.getOverlayTexture() != null
? ImmutableSet.of(attrs.getStillTexture(), attrs.getFlowingTexture(), attrs.getOverlayTexture())
: ImmutableSet.of(attrs.getStillTexture(), attrs.getFlowingTexture());
}
@Override
@ -93,15 +94,16 @@ public final class ModelFluid implements IUnbakedModel
@Override
public IBakedModel bake(ModelBakery bakery, Function<ResourceLocation, TextureAtlasSprite> spriteGetter, ISprite sprite, VertexFormat format)
{
FluidAttributes attrs = fluid.getAttributes();
return new CachingBakedFluid(
sprite.getState().apply(Optional.empty()),
PerspectiveMapWrapper.getTransforms(sprite.getState()),
format,
fluid.getColor(),
spriteGetter.apply(fluid.getStill()),
spriteGetter.apply(fluid.getFlowing()),
Optional.ofNullable(fluid.getOverlay()).map(spriteGetter),
fluid.isLighterThanAir(),
attrs.getColor(),
spriteGetter.apply(attrs.getStillTexture()),
spriteGetter.apply(attrs.getFlowingTexture()),
Optional.ofNullable(attrs.getOverlayTexture()).map(spriteGetter),
attrs.isLighterThanAir(),
null
);
}

View File

@ -85,7 +85,6 @@ import net.minecraftforge.common.model.Models;
import net.minecraftforge.common.model.TRSRTransformation;
import net.minecraftforge.common.model.animation.IClip;
import net.minecraftforge.common.property.Properties;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.client.ClientModLoader;
import net.minecraftforge.logging.ModelLoaderErrorMessage;
import net.minecraftforge.registries.IRegistryDelegate;

View File

@ -71,7 +71,6 @@ import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.event.lifecycle.GatherDataEvent;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.fluids.UniversalBucket;
import net.minecraftforge.fml.common.Mod;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
@ -98,8 +97,6 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
return INSTANCE;
}
public UniversalBucket universalBucket;
public ForgeMod()
{
LOGGER.info(FORGEMOD,"Forge mod loading, version {}, for MC {} with MCP {}", ForgeVersion.getVersion(), MCPVersion.getMCVersion(), MCPVersion.getMCPVersion());
@ -158,7 +155,6 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
DimensionManager.writeRegistry(dims);
if (!dims.isEmpty())
forgeData.put("dims", dims);
// TODO fluids FluidRegistry.writeDefaultFluidList(forgeData);
return forgeData;
}
@ -167,7 +163,6 @@ public class ForgeMod implements WorldPersistenceHooks.WorldPersistenceHook
{
if (tag.contains("dims", 10))
DimensionManager.readRegistry(tag.getCompound("dims"));
// TODO fluids FluidRegistry.loadFluidDefaults(tag);
}
public void mappingChanged(FMLModIdMappingEvent evt)

View File

@ -27,6 +27,7 @@ import net.minecraft.block.material.Material;
import net.minecraft.client.renderer.model.IBakedModel;
import net.minecraft.entity.Entity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.tags.Tag;
import net.minecraft.util.BlockRenderLayer;
@ -35,6 +36,7 @@ import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.Explosion;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.fluids.FluidAttributes;
public interface IForgeFluid
{
@ -117,4 +119,9 @@ public interface IForgeFluid
* This should be used in favor of TagCollection.getOwningTags, as this caches the result and automatically updates when the TagCollection changes.
*/
Set<ResourceLocation> getTags();
/**
* Retrieves the non-vanilla fluid attributes, including localized name.
*/
FluidAttributes getAttributes();
}

View File

@ -19,8 +19,6 @@
package net.minecraftforge.common.network;
import net.minecraftforge.fluids.FluidRegistry;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

View File

@ -19,8 +19,6 @@
package net.minecraftforge.energy;
import java.util.concurrent.Callable;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.IntNBT;
import net.minecraft.util.Direction;

View File

@ -30,6 +30,7 @@ import net.minecraft.util.Direction;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
/**
@ -108,7 +109,7 @@ public class DispenseFluidContainer extends DefaultDispenseItemBehavior
return super.dispenseStack(source, stack);
}
FluidStack fluidStack = fluidHandler.drain(Fluid.BUCKET_VOLUME, false);
FluidStack fluidStack = fluidHandler.drain(FluidAttributes.BUCKET_VOLUME, IFluidHandler.FluidAction.EXECUTE);
Direction dispenserFacing = source.getBlockState().get(DispenserBlock.FACING);
BlockPos blockpos = source.getBlockPos().offset(dispenserFacing);
FluidActionResult result = fluidStack != null ? FluidUtil.tryPlaceFluid(null, source.getWorld(), Hand.MAIN_HAND, blockpos, stack, fluidStack) : FluidActionResult.FAILURE;

View File

@ -21,11 +21,17 @@ package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.IFluidState;
import net.minecraft.particles.ParticleTypes;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IEnviromentBlockReader;
import java.util.Locale;
import java.util.function.Supplier;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.PlayerEntity;
@ -54,33 +60,31 @@ import net.minecraft.item.Rarity;
* water.
*
*/
public class Fluid
public class FluidAttributes
{
private static final Logger LOGGER = LogManager.getLogger();
public static final int BUCKET_VOLUME = 1000;
/** The unique identification name for this fluid. */
protected final String fluidName;
private final String fluidName;
/** The unlocalized name of this fluid. */
protected String unlocalizedName;
/** The translation key of this fluid. */
private String translationKey;
protected final ResourceLocation still;
protected final ResourceLocation flowing;
private final ResourceLocation stillTexture;
private final ResourceLocation flowingTexture;
@Nullable
protected final ResourceLocation overlay;
private final ResourceLocation overlayTexture;
private SoundEvent fillSound;
private SoundEvent emptySound;
private final SoundEvent fillSound;
private final SoundEvent emptySound;
/**
* The light level emitted by this fluid.
*
* Default value is 0, as most fluids do not actively emit light.
*/
protected int luminosity = 0;
private final int luminosity;
/**
* Density of the fluid - completely arbitrary; negative density indicates that the fluid is
@ -88,7 +92,7 @@ public class Fluid
*
* Default value is approximately the real-life density of water in kg/m^3.
*/
protected int density = 1000;
private final int density;
/**
* Temperature of the fluid - completely arbitrary; higher temperature indicates that the fluid is
@ -96,7 +100,7 @@ public class Fluid
*
* Default value is approximately the real-life room temperature of water in degrees Kelvin.
*/
protected int temperature = 300;
private final int temperature;
/**
* Viscosity ("thickness") of the fluid - completely arbitrary; negative values are not
@ -108,28 +112,23 @@ public class Fluid
* Lower viscosity means that a fluid flows more quickly, like helium.
*
*/
protected int viscosity = 1000;
private final int viscosity;
/**
* This indicates if the fluid is gaseous.
*
* Generally this is associated with negative density fluids.
*/
protected boolean isGaseous;
private final boolean isGaseous;
/**
* The rarity of the fluid.
*
* Used primarily in tool tips.
*/
protected Rarity rarity = Rarity.COMMON;
private final Rarity rarity;
/**
* If there is a Block implementation of the Fluid, the Block is linked here.
*
* The default value of null should remain for any Fluid without a Block implementation.
*/
protected Block block = null;
private final Supplier<Block> blockSupplier;
/**
* Color used by universal bucket and the ModelFluid baked model.
@ -139,105 +138,25 @@ public class Fluid
* float b = ((color >> 0) & 0xFF) / 255f; // blue
* float a = ((color >> 24) & 0xFF) / 255f; // alpha
*/
protected int color = 0xFFFFFFFF;
private final int color;
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, int color)
protected FluidAttributes(Builder builder)
{
this(fluidName, still, flowing, null, color);
}
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, @Nullable ResourceLocation overlay, int color)
{
this(fluidName, still, flowing, overlay);
this.setColor(color);
}
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing)
{
this(fluidName, still, flowing, (ResourceLocation) null);
}
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, @Nullable ResourceLocation overlay)
{
this.fluidName = fluidName.toLowerCase(Locale.ENGLISH);
this.unlocalizedName = fluidName;
this.still = still;
this.flowing = flowing;
this.overlay = overlay;
}
public Fluid setUnlocalizedName(String unlocalizedName)
{
this.unlocalizedName = unlocalizedName;
return this;
}
public Fluid setBlock(Block block)
{
if (this.block == null || this.block == block)
{
this.block = block;
}
else
{
LOGGER.warn("A mod has attempted to assign Block {} to the Fluid '{}' but this Fluid has already been linked to the Block {}. "
+ "You may have duplicate Fluid Blocks as a result. It *may* be possible to configure your mods to avoid this.", block, fluidName, this.block);
}
return this;
}
public Fluid setLuminosity(int luminosity)
{
this.luminosity = luminosity;
return this;
}
public Fluid setDensity(int density)
{
this.density = density;
return this;
}
public Fluid setTemperature(int temperature)
{
this.temperature = temperature;
return this;
}
public Fluid setViscosity(int viscosity)
{
this.viscosity = viscosity;
return this;
}
public Fluid setGaseous(boolean isGaseous)
{
this.isGaseous = isGaseous;
return this;
}
public Fluid setRarity(Rarity rarity)
{
this.rarity = rarity;
return this;
}
public Fluid setFillSound(SoundEvent fillSound)
{
this.fillSound = fillSound;
return this;
}
public Fluid setEmptySound(SoundEvent emptySound)
{
this.emptySound = emptySound;
return this;
}
public Fluid setColor(int color)
{
this.color = color;
return this;
this.fluidName = builder.name;
this.translationKey = builder.translationKey;
this.stillTexture = builder.stillTexture;
this.flowingTexture = builder.flowingTexture;
this.overlayTexture = builder.overlayTexture;
this.blockSupplier = builder.blockSupplier;
this.color = builder.color;
this.fillSound = builder.fillSound;
this.emptySound = builder.emptySound;
this.luminosity = builder.luminosity;
this.temperature = builder.temperature;
this.viscosity = builder.viscosity;
this.density = builder.density;
this.isGaseous = builder.isGaseous;
this.rarity = builder.rarity;
}
public final String getName()
@ -245,14 +164,24 @@ public class Fluid
return this.fluidName;
}
public final Block getBlock()
public BlockState getBlock(IEnviromentBlockReader reader, BlockPos pos, IFluidState state)
{
return block;
return (blockSupplier != null ? blockSupplier.get() : Blocks.AIR).getDefaultState();
}
public final boolean canBePlacedInWorld()
public IFluidState getStateForPlacement(IEnviromentBlockReader reader, BlockPos pos, FluidStack state)
{
return block != null;
return state.getFluid().getDefaultState();
}
public final boolean canBePlacedInWorld(IEnviromentBlockReader reader, BlockPos pos, IFluidState state)
{
return getBlock(reader, pos, state) != null;
}
public final boolean canBePlacedInWorld(IEnviromentBlockReader reader, BlockPos pos, FluidStack state)
{
return getBlock(reader, pos, getStateForPlacement(reader, pos, state)) != null;
}
public final boolean isLighterThanAir()
@ -269,11 +198,12 @@ public class Fluid
* @param fluidStack The fluidStack is trying to be placed.
* @return true if this fluid should vaporize in dimensions where water vaporizes when placed.
*/
public boolean doesVaporize(FluidStack fluidStack)
public boolean doesVaporize(IEnviromentBlockReader reader, BlockPos pos, FluidStack fluidStack)
{
if (block == null)
BlockState blockstate = getBlock(reader, pos, getStateForPlacement(reader, pos, fluidStack));
if (blockstate == null)
return false;
return block.getDefaultState().getMaterial() == Material.WATER;
return blockstate.getMaterial() == Material.WATER;
}
/**
@ -299,26 +229,25 @@ public class Fluid
/**
* Returns the localized name of this fluid.
*/
public String getLocalizedName(FluidStack stack)
public ITextComponent getDisplayName(FluidStack stack)
{
String s = this.getUnlocalizedName();
return s == null ? "" : LanguageMap.getInstance().translateKey(s); // TODO Server translation
return new TranslationTextComponent(getTranslationKey());
}
/**
* A FluidStack sensitive version of getUnlocalizedName
*/
public String getUnlocalizedName(FluidStack stack)
public String getTranslationKey(FluidStack stack)
{
return this.getUnlocalizedName();
return this.getTranslationKey();
}
/**
* Returns the unlocalized name of this fluid.
*/
public String getUnlocalizedName()
public String getTranslationKey()
{
return "fluid." + this.unlocalizedName;
return "fluid." + this.translationKey;
}
/* Default Accessors */
@ -357,53 +286,29 @@ public class Fluid
return color;
}
public ResourceLocation getStill()
public ResourceLocation getStillTexture()
{
return still;
return stillTexture;
}
public ResourceLocation getFlowing()
public ResourceLocation getFlowingTexture()
{
return flowing;
return flowingTexture;
}
@Nullable
public ResourceLocation getOverlay()
public ResourceLocation getOverlayTexture()
{
return overlay;
return overlayTexture;
}
public SoundEvent getFillSound()
{
if(fillSound == null)
{
if(getBlock() != null && getBlock().getDefaultState().getMaterial() == Material.LAVA)
{
fillSound = SoundEvents.ITEM_BUCKET_FILL_LAVA;
}
else
{
fillSound = SoundEvents.ITEM_BUCKET_FILL;
}
}
return fillSound;
}
public SoundEvent getEmptySound()
{
if(emptySound == null)
{
if(getBlock() != null && getBlock().getDefaultState().getMaterial() == Material.LAVA)
{
emptySound = SoundEvents.ITEM_BUCKET_EMPTY_LAVA;
}
else
{
emptySound = SoundEvents.ITEM_BUCKET_EMPTY;
}
}
return emptySound;
}
@ -415,22 +320,135 @@ public class Fluid
public boolean isGaseous(FluidStack stack){ return isGaseous(); }
public Rarity getRarity(FluidStack stack){ return getRarity(); }
public int getColor(FluidStack stack){ return getColor(); }
public ResourceLocation getStill(FluidStack stack) { return getStill(); }
public ResourceLocation getFlowing(FluidStack stack) { return getFlowing(); }
public ResourceLocation getStill(FluidStack stack) { return getStillTexture(); }
public ResourceLocation getFlowing(FluidStack stack) { return getFlowingTexture(); }
public SoundEvent getFillSound(FluidStack stack) { return getFillSound(); }
public SoundEvent getEmptySound(FluidStack stack) { return getEmptySound(); }
/* World-based Accessors */
public int getLuminosity(World world, BlockPos pos){ return getLuminosity(); }
public int getDensity(World world, BlockPos pos){ return getDensity(); }
public int getTemperature(World world, BlockPos pos){ return getTemperature(); }
public int getViscosity(World world, BlockPos pos){ return getViscosity(); }
public boolean isGaseous(World world, BlockPos pos){ return isGaseous(); }
public Rarity getRarity(World world, BlockPos pos){ return getRarity(); }
public int getColor(World world, BlockPos pos){ return getColor(); }
public ResourceLocation getStill(World world, BlockPos pos) { return getStill(); }
public ResourceLocation getFlowing(World world, BlockPos pos) { return getFlowing(); }
public SoundEvent getFillSound(World world, BlockPos pos) { return getFillSound(); }
public SoundEvent getEmptySound(World world, BlockPos pos) { return getEmptySound(); }
public int getLuminosity(IEnviromentBlockReader world, BlockPos pos){ return getLuminosity(); }
public int getDensity(IEnviromentBlockReader world, BlockPos pos){ return getDensity(); }
public int getTemperature(IEnviromentBlockReader world, BlockPos pos){ return getTemperature(); }
public int getViscosity(IEnviromentBlockReader world, BlockPos pos){ return getViscosity(); }
public boolean isGaseous(IEnviromentBlockReader world, BlockPos pos){ return isGaseous(); }
public Rarity getRarity(IEnviromentBlockReader world, BlockPos pos){ return getRarity(); }
public int getColor(IEnviromentBlockReader world, BlockPos pos){ return getColor(); }
public ResourceLocation getStill(IEnviromentBlockReader world, BlockPos pos) { return getStillTexture(); }
public ResourceLocation getFlowing(IEnviromentBlockReader world, BlockPos pos) { return getFlowingTexture(); }
public SoundEvent getFillSound(IEnviromentBlockReader world, BlockPos pos) { return getFillSound(); }
public SoundEvent getEmptySound(IEnviromentBlockReader world, BlockPos pos) { return getEmptySound(); }
public static Builder builder(String name, ResourceLocation stillTexture, ResourceLocation flowingTexture) {
return new Builder(name, stillTexture, flowingTexture);
}
public static class Builder
{
private final String name;
private final ResourceLocation stillTexture;
private final ResourceLocation flowingTexture;
private ResourceLocation overlayTexture;
private int color = 0xFFFFFF;
private String translationKey;
private SoundEvent fillSound;
private SoundEvent emptySound;
private Supplier<Block> blockSupplier;
private int luminosity = 0;
private int density = 1000;
private int temperature = 300;
private int viscosity = 1000;
private boolean isGaseous;
private Rarity rarity = Rarity.COMMON;
protected Builder(String name, ResourceLocation stillTexture, ResourceLocation flowingTexture) {
this.name = name.toLowerCase(Locale.ENGLISH);
this.stillTexture = stillTexture;
this.flowingTexture = flowingTexture;
this.translationKey = "fluid." + this.name + ".name";
}
public final Builder translationKey(String translationKey)
{
this.translationKey = translationKey;
return this;
}
public final Builder color(int color)
{
this.color = color;
return this;
}
public final Builder vanillaColor()
{
this.color = -1;
return this;
}
public final Builder overlay(ResourceLocation texture)
{
overlayTexture = texture;
return this;
}
public final Builder block(Supplier<Block> supplier)
{
blockSupplier = supplier;
return this;
}
public final Builder luminosity(int luminosity)
{
this.luminosity = luminosity;
return this;
}
public final Builder density(int density)
{
this.density = density;
return this;
}
public final Builder temperature(int temperature)
{
this.temperature = temperature;
return this;
}
public final Builder viscosity(int viscosity)
{
this.viscosity = viscosity;
return this;
}
public final Builder gaseous()
{
isGaseous = true;
return this;
}
public final Builder rarity(Rarity rarity)
{
this.rarity = rarity;
return this;
}
public final Builder sound(SoundEvent sound)
{
this.fillSound = this.emptySound = sound;
return this;
}
public final Builder sound(SoundEvent fillSound, SoundEvent emptySound)
{
this.fillSound = fillSound;
this.emptySound = emptySound;
return this;
}
public FluidAttributes build()
{
return new FluidAttributes(this);
}
}
}

View File

@ -1,145 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.Event;
public class FluidEvent extends net.minecraftforge.eventbus.api.Event
{
private final FluidStack fluid;
private final World world;
private final BlockPos pos;
public FluidEvent(FluidStack fluid, World world, BlockPos pos)
{
this.fluid = fluid;
this.world = world;
this.pos = pos;
}
public FluidStack getFluid()
{
return fluid;
}
public World getWorld()
{
return world;
}
public BlockPos getPos()
{
return pos;
}
/**
* Mods should fire this event when they move fluids around.
*
*/
public static class FluidMotionEvent extends FluidEvent
{
public FluidMotionEvent(FluidStack fluid, World world, BlockPos pos)
{
super(fluid, world, pos);
}
}
/**
* Mods should fire this event when a fluid is {@link IFluidTank#fill(FluidStack, boolean)}
* their tank implementation. {@link FluidTank} does.
*
*/
public static class FluidFillingEvent extends FluidEvent
{
private final IFluidTank tank;
private final int amount;
public FluidFillingEvent(FluidStack fluid, World world, BlockPos pos, IFluidTank tank, int amount)
{
super(fluid, world, pos);
this.tank = tank;
this.amount = amount;
}
public IFluidTank getTank()
{
return tank;
}
public int getAmount()
{
return amount;
}
}
/**
* Mods should fire this event when a fluid is {@link IFluidTank#drain(int, boolean)} from their
* tank.
*
*/
public static class FluidDrainingEvent extends FluidEvent
{
private final IFluidTank tank;
private final int amount;
public FluidDrainingEvent(FluidStack fluid, World world, BlockPos pos, IFluidTank tank, int amount)
{
super(fluid, world, pos);
this.amount = amount;
this.tank = tank;
}
public IFluidTank getTank()
{
return tank;
}
public int getAmount()
{
return amount;
}
}
/**
* Mods should fire this event when a fluid "spills", for example, if a block containing fluid
* is broken.
*
*/
public static class FluidSpilledEvent extends FluidEvent
{
public FluidSpilledEvent(FluidStack fluid, World world, BlockPos pos)
{
super(fluid, world, pos);
}
}
/**
* A handy shortcut for firing the various fluid events.
*
* @param event
*/
public static final void fireEvent(FluidEvent event)
{
MinecraftForge.EVENT_BUS.post(event);
}
}

View File

@ -1,51 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.Marker;
import org.apache.logging.log4j.MarkerManager;
/**
* Handles Fluid registrations. Fluids MUST be registered in order to function.
*/
public abstract class FluidRegistry
{
private static final Logger LOGGER = LogManager.getLogger();
private static final Marker FLUIDS = MarkerManager.getMarker("FLUIDS");
static boolean universalBucketEnabled = false;
/**
* Enables the universal bucket in forge.
* Has to be called before pre-initialization.
* Actually just call it statically in your mod class.
*/
public static void enableUniversalBucket()
{
universalBucketEnabled = true;
}
public static boolean isUniversalBucketEnabled()
{
return universalBucketEnabled;
}
}

View File

@ -19,8 +19,10 @@
package net.minecraftforge.fluids;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.registries.IRegistryDelegate;
@ -123,14 +125,14 @@ public class FluidStack
return fluidDelegate.get();
}
public String getLocalizedName()
public ITextComponent getDisplayName()
{
return this.getFluid().getLocalizedName(this);
return this.getFluid().getAttributes().getDisplayName(this);
}
public String getUnlocalizedName()
public String getTranslationKey()
{
return this.getFluid().getUnlocalizedName(this);
return this.getFluid().getAttributes().getTranslationKey(this);
}
/**
@ -155,7 +157,7 @@ public class FluidStack
private boolean isFluidStackTagEqual(FluidStack other)
{
return tag == null ? other.tag == null : other.tag == null ? false : tag.equals(other.tag);
return tag == null ? other.tag == null : other.tag != null && tag.equals(other.tag);
}
/**
@ -163,7 +165,7 @@ public class FluidStack
*/
public static boolean areFluidStackTagsEqual(@Nullable FluidStack stack1, @Nullable FluidStack stack2)
{
return stack1 == null && stack2 == null ? true : stack1 == null || stack2 == null ? false : stack1.isFluidStackTagEqual(stack2);
return stack1 == null && stack2 == null || (stack1 != null && stack2 != null && stack1.isFluidStackTagEqual(stack2));
}
/**
@ -230,7 +232,6 @@ public class FluidStack
{
return false;
}
return isFluidEqual((FluidStack) o);
}
}

View File

@ -1,357 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fluids.capability.FluidTankPropertiesWrapper;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
/**
* Reference implementation of {@link IFluidTank}. Use/extend this or implement your own.
*/
public class FluidTank implements IFluidTank, IFluidHandler
{
@Nullable
protected FluidStack fluid;
protected int capacity;
protected TileEntity tile;
protected boolean canFill = true;
protected boolean canDrain = true;
protected IFluidTankProperties[] tankProperties;
public FluidTank(int capacity)
{
this(null, capacity);
}
public FluidTank(@Nullable FluidStack fluidStack, int capacity)
{
this.fluid = fluidStack;
this.capacity = capacity;
}
public FluidTank(Fluid fluid, int amount, int capacity)
{
this(new FluidStack(fluid, amount), capacity);
}
public FluidTank readFromNBT(CompoundNBT nbt)
{
if (!nbt.contains("Empty"))
{
FluidStack fluid = FluidStack.loadFluidStackFromNBT(nbt);
setFluid(fluid);
}
else
{
setFluid(null);
}
return this;
}
public CompoundNBT writeToNBT(CompoundNBT nbt)
{
if (fluid != null)
{
fluid.writeToNBT(nbt);
}
else
{
nbt.putString("Empty", "");
}
return nbt;
}
/* IFluidTank */
@Override
@Nullable
public FluidStack getFluid()
{
return fluid;
}
public void setFluid(@Nullable FluidStack fluid)
{
this.fluid = fluid;
}
@Override
public int getFluidAmount()
{
if (fluid == null)
{
return 0;
}
return fluid.amount;
}
@Override
public int getCapacity()
{
return capacity;
}
public void setCapacity(int capacity)
{
this.capacity = capacity;
}
public void setTileEntity(TileEntity tile)
{
this.tile = tile;
}
@Override
public FluidTankInfo getInfo()
{
return new FluidTankInfo(this);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
if (this.tankProperties == null)
{
this.tankProperties = new IFluidTankProperties[] { new FluidTankPropertiesWrapper(this) };
}
return this.tankProperties;
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (!canFillFluidType(resource))
{
return 0;
}
return fillInternal(resource, doFill);
}
/**
* Use this method to bypass the restrictions from {@link #canFillFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canFill() set to false}.
*/
public int fillInternal(FluidStack resource, boolean doFill)
{
if (resource == null || resource.amount <= 0)
{
return 0;
}
if (!doFill)
{
if (fluid == null)
{
return Math.min(capacity, resource.amount);
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
return Math.min(capacity - fluid.amount, resource.amount);
}
if (fluid == null)
{
fluid = new FluidStack(resource, Math.min(capacity, resource.amount));
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.getWorld(), tile.getPos(), this, fluid.amount));
}
return fluid.amount;
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
int filled = capacity - fluid.amount;
if (resource.amount < filled)
{
fluid.amount += resource.amount;
filled = resource.amount;
}
else
{
fluid.amount = capacity;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.getWorld(), tile.getPos(), this, filled));
}
return filled;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (!canDrainFluidType(getFluid()))
{
return null;
}
return drainInternal(resource, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (!canDrainFluidType(fluid))
{
return null;
}
return drainInternal(maxDrain, doDrain);
}
/**
* Use this method to bypass the restrictions from {@link #canDrainFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canDrain()} set to false}.
*/
@Nullable
public FluidStack drainInternal(FluidStack resource, boolean doDrain)
{
if (resource == null || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drainInternal(resource.amount, doDrain);
}
/**
* Use this method to bypass the restrictions from {@link #canDrainFluidType(FluidStack)}
* Meant for use by the owner of the tank when they have {@link #canDrain()} set to false}.
*/
@Nullable
public FluidStack drainInternal(int maxDrain, boolean doDrain)
{
if (fluid == null || maxDrain <= 0)
{
return null;
}
int drained = maxDrain;
if (fluid.amount < drained)
{
drained = fluid.amount;
}
FluidStack stack = new FluidStack(fluid, drained);
if (doDrain)
{
fluid.amount -= drained;
if (fluid.amount <= 0)
{
fluid = null;
}
onContentsChanged();
if (tile != null)
{
FluidEvent.fireEvent(new FluidEvent.FluidDrainingEvent(fluid, tile.getWorld(), tile.getPos(), this, drained));
}
}
return stack;
}
/**
* Whether this tank can be filled with {@link IFluidHandler}
*
* @see IFluidTankProperties#canFill()
*/
public boolean canFill()
{
return canFill;
}
/**
* Whether this tank can be drained with {@link IFluidHandler}
*
* @see IFluidTankProperties#canDrain()
*/
public boolean canDrain()
{
return canDrain;
}
/**
* Set whether this tank can be filled with {@link IFluidHandler}
*
* @see IFluidTankProperties#canFill()
*/
public void setCanFill(boolean canFill)
{
this.canFill = canFill;
}
/**
* Set whether this tank can be drained with {@link IFluidHandler}
*
* @see IFluidTankProperties#canDrain()
*/
public void setCanDrain(boolean canDrain)
{
this.canDrain = canDrain;
}
/**
* Returns true if the tank can be filled with this type of fluid.
* Used as a filter for fluid types.
* Does not consider the current contents or capacity of the tank,
* only whether it could ever fill with this type of fluid.
*
* @see IFluidTankProperties#canFillFluidType(FluidStack)
*/
public boolean canFillFluidType(FluidStack fluid)
{
return canFill();
}
/**
* Returns true if the tank can drain out this type of fluid.
* Used as a filter for fluid types.
* Does not consider the current contents or capacity of the tank,
* only whether it could ever drain out this type of fluid.
*
* @see IFluidTankProperties#canDrainFluidType(FluidStack)
*/
public boolean canDrainFluidType(@Nullable FluidStack fluid)
{
return fluid != null && canDrain();
}
protected void onContentsChanged()
{
}
}

View File

@ -1,44 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
import javax.annotation.Nullable;
/**
* Wrapper class used to encapsulate information about an IFluidTank.
*/
public final class FluidTankInfo
{
@Nullable
public final FluidStack fluid;
public final int capacity;
public FluidTankInfo(@Nullable FluidStack fluid, int capacity)
{
this.fluid = fluid;
this.capacity = capacity;
}
public FluidTankInfo(IFluidTank tank)
{
this.fluid = tank.getFluid();
this.capacity = tank.getCapacity();
}
}

View File

@ -27,6 +27,7 @@ import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluid;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ItemUseContext;
@ -121,7 +122,7 @@ public class FluidUtil
*
* @param container The container to be filled. Will not be modified.
* Separate handling must be done to reduce the stack size, stow containers, etc, on success.
* See {@link #tryFillContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer, boolean)}.
* See {@link #tryFillContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, PlayerEntity, boolean)}.
* @param fluidSource The fluid handler to be drained.
* @param maxAmount The largest amount of fluid that should be transferred.
* @param player The player to make the filling noise. Pass null for no noise.
@ -142,13 +143,13 @@ public class FluidUtil
tryFluidTransfer(containerFluidHandler, fluidSource, maxAmount, true);
if (player != null)
{
SoundEvent soundevent = simulatedTransfer.getFluid().getFillSound(simulatedTransfer);
SoundEvent soundevent = simulatedTransfer.getFluid().getAttributes().getFillSound(simulatedTransfer);
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
}
else
{
containerFluidHandler.fill(simulatedTransfer, true);
containerFluidHandler.fill(simulatedTransfer, IFluidHandler.FluidAction.SIMULATE);
}
ItemStack resultContainer = containerFluidHandler.getContainer();
@ -164,7 +165,7 @@ public class FluidUtil
*
* @param container The filled container. Will not be modified.
* Separate handling must be done to reduce the stack size, stow containers, etc, on success.
* See {@link #tryEmptyContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, EntityPlayer, boolean)}.
* See {@link #tryEmptyContainerAndStow(ItemStack, IFluidHandler, IItemHandler, int, PlayerEntity, boolean)}.
* @param fluidDestination The fluid handler to be filled by the container.
* @param maxAmount The largest amount of fluid that should be transferred.
* @param player Player for making the bucket drained sound. Pass null for no noise.
@ -185,7 +186,7 @@ public class FluidUtil
{
if (player != null)
{
SoundEvent soundevent = transfer.getFluid().getEmptySound(transfer);
SoundEvent soundevent = transfer.getFluid().getAttributes().getEmptySound(transfer);
player.world.playSound(null, player.posX, player.posY + 0.5, player.posZ, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
}
ItemStack resultContainer = containerFluidHandler.getContainer();
@ -197,7 +198,7 @@ public class FluidUtil
FluidStack simulatedTransfer = tryFluidTransfer(fluidDestination, containerFluidHandler, maxAmount, false);
if (simulatedTransfer != null)
{
containerFluidHandler.drain(simulatedTransfer, true);
containerFluidHandler.drain(simulatedTransfer, IFluidHandler.FluidAction.SIMULATE);
ItemStack resultContainer = containerFluidHandler.getContainer();
return new FluidActionResult(resultContainer);
}
@ -358,7 +359,7 @@ public class FluidUtil
@Nullable
public static FluidStack tryFluidTransfer(IFluidHandler fluidDestination, IFluidHandler fluidSource, int maxAmount, boolean doTransfer)
{
FluidStack drainable = fluidSource.drain(maxAmount, false);
FluidStack drainable = fluidSource.drain(maxAmount, IFluidHandler.FluidAction.SIMULATE);
if (drainable != null && drainable.amount > 0)
{
return tryFluidTransfer_Internal(fluidDestination, fluidSource, drainable, doTransfer);
@ -380,7 +381,7 @@ public class FluidUtil
@Nullable
public static FluidStack tryFluidTransfer(IFluidHandler fluidDestination, IFluidHandler fluidSource, FluidStack resource, boolean doTransfer)
{
FluidStack drainable = fluidSource.drain(resource, false);
FluidStack drainable = fluidSource.drain(resource, IFluidHandler.FluidAction.SIMULATE);
if (drainable != null && drainable.amount > 0 && resource.isFluidEqual(drainable))
{
return tryFluidTransfer_Internal(fluidDestination, fluidSource, drainable, doTransfer);
@ -398,15 +399,15 @@ public class FluidUtil
@Nullable
private static FluidStack tryFluidTransfer_Internal(IFluidHandler fluidDestination, IFluidHandler fluidSource, FluidStack drainable, boolean doTransfer)
{
int fillableAmount = fluidDestination.fill(drainable, false);
int fillableAmount = fluidDestination.fill(drainable, IFluidHandler.FluidAction.SIMULATE);
if (fillableAmount > 0)
{
if (doTransfer)
{
FluidStack drained = fluidSource.drain(fillableAmount, true);
FluidStack drained = fluidSource.drain(fillableAmount, IFluidHandler.FluidAction.EXECUTE);
if (drained != null)
{
drained.amount = fluidDestination.fill(drained, true);
drained.amount = fluidDestination.fill(drained, IFluidHandler.FluidAction.EXECUTE);
return drained;
}
}
@ -445,7 +446,7 @@ public class FluidUtil
{
container = ItemHandlerHelper.copyStackWithSize(container, 1);
return getFluidHandler(container)
.map(handler -> handler.drain(Integer.MAX_VALUE, false));
.map(handler -> handler.drain(Integer.MAX_VALUE, IFluidHandler.FluidAction.SIMULATE));
}
return LazyOptional.empty();
}
@ -513,7 +514,7 @@ public class FluidUtil
}
/**
* ItemStack version of {@link #tryPlaceFluid(EntityPlayer, World, BlockPos, IFluidHandler, FluidStack)}.
* ItemStack version of {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, IFluidHandler, FluidStack)}.
* Use the returned {@link FluidActionResult} to update the container ItemStack.
*
* @param player Player who places the fluid. May be null for blocks like dispensers.
@ -541,7 +542,7 @@ public class FluidUtil
* Honors the amount of fluid contained by the used container.
* Checks if water-like fluids should vaporize like in the nether.
*
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(EntityPlayer, World, BlockPos)}
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
*
* @param player Player who places the fluid. May be null for blocks like dispensers.
* @param world World to place the fluid in
@ -559,12 +560,12 @@ public class FluidUtil
}
Fluid fluid = resource.getFluid();
if (fluid == null || !fluid.canBePlacedInWorld())
if (fluid == null || !fluid.getAttributes().canBePlacedInWorld(world, pos, resource))
{
return false;
}
if (fluidSource.drain(resource, false) == null)
if (fluidSource.drain(resource, IFluidHandler.FluidAction.SIMULATE) == null)
{
return false;
}
@ -581,12 +582,12 @@ public class FluidUtil
return false; // Non-air, solid, unreplacable block. We can't put fluid here.
}
if (world.dimension.doesWaterVaporize() && fluid.doesVaporize(resource))
if (world.dimension.doesWaterVaporize() && fluid.getAttributes().doesVaporize(world, pos, resource))
{
FluidStack result = fluidSource.drain(resource, true);
FluidStack result = fluidSource.drain(resource, IFluidHandler.FluidAction.EXECUTE);
if (result != null)
{
result.getFluid().vaporize(player, world, pos, result);
result.getFluid().getAttributes().vaporize(player, world, pos, result);
return true;
}
}
@ -597,7 +598,7 @@ public class FluidUtil
FluidStack result = tryFluidTransfer(handler, fluidSource, resource, true);
if (result != null)
{
SoundEvent soundevent = resource.getFluid().getEmptySound(resource);
SoundEvent soundevent = resource.getFluid().getAttributes().getEmptySound(resource);
world.playSound(player, pos, soundevent, SoundCategory.BLOCKS, 1.0F, 1.0F);
return true;
}
@ -608,12 +609,12 @@ public class FluidUtil
/**
* Internal method for getting a fluid block handler for placing a fluid.
*
* Modders: Instead of this method, use {@link #tryPlaceFluid(EntityPlayer, World, BlockPos, ItemStack, FluidStack)}
* or {@link #tryPlaceFluid(EntityPlayer, World, BlockPos, IFluidHandler, FluidStack)}
* Modders: Instead of this method, use {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, ItemStack, FluidStack)}
* or {@link #tryPlaceFluid(PlayerEntity, World, BlockPos, IFluidHandler, FluidStack)}
*/
private static IFluidHandler getFluidBlockHandler(Fluid fluid, World world, BlockPos pos)
{
Block block = fluid.getBlock();/* TODO fluid blocks?
BlockState state = fluid.getAttributes().getBlock(world, pos, fluid.getDefaultState());/* TODO fluid blocks?
if (block instanceof IFluidBlock)
{
return new FluidBlockWrapper((IFluidBlock) block, world, pos);
@ -624,13 +625,13 @@ public class FluidUtil
}
else*/
{
return new BlockWrapper(block, world, pos);
return new BlockWrapper(state, world, pos);
}
}
/**
* Destroys a block when a fluid is placed in the same position.
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(EntityPlayer, World, BlockPos)}
* Modeled after {@link ItemBucket#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
*
* This is a helper method for implementing {@link IFluidBlock#place(World, BlockPos, FluidStack, boolean)}.
*

View File

@ -19,8 +19,10 @@
package net.minecraftforge.fluids;
import net.minecraft.fluid.Fluid;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -47,22 +49,22 @@ public interface IFluidBlock
* @param world the world to place the block in
* @param pos the position to place the block at
* @param fluidStack the fluid stack to get the required data from
* @param doPlace if false, the placement will only be simulated
* @param action If SIMULATE, the placement will only be simulated
* @return the amount of fluid extracted from the provided stack to achieve some fluid level
*/
int place(World world, BlockPos pos, @Nonnull FluidStack fluidStack, boolean doPlace);
int place(World world, BlockPos pos, @Nonnull FluidStack fluidStack, IFluidHandler.FluidAction action);
/**
* Attempt to drain the block. This method should be called by devices such as pumps.
*
* NOTE: The block is intended to handle its own state changes.
*
* @param doDrain
* If false, the drain will only be simulated.
* @param action
* If SIMULATE, the drain will only be simulated.
* @return
*/
@Nullable
FluidStack drain(World world, BlockPos pos, boolean doDrain);
FluidStack drain(World world, BlockPos pos, IFluidHandler.FluidAction action);
/**
* Check to see if a block can be drained. This method should be called by devices such as

View File

@ -19,15 +19,17 @@
package net.minecraftforge.fluids;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nullable;
/**
* A tank is the unit of interaction with Fluid inventories.
*
* A reference implementation can be found at {@link FluidTank}.
* This interface represents a Fluid Tank. IT IS NOT REQUIRED but is provided for convenience.
* You are free to handle Fluids in any way that you wish - this is simply an easy default way.
* DO NOT ASSUME that these objects are used internally in all cases.
*/
public interface IFluidTank
{
public interface IFluidTank {
/**
* @return FluidStack representing the fluid in the tank, null if the tank is empty.
*/
@ -45,33 +47,32 @@ public interface IFluidTank
int getCapacity();
/**
* Returns a wrapper object {@link FluidTankInfo } containing the capacity of the tank and the
* FluidStack it holds.
*
* Should prevent manipulation of the IFluidTank. See {@link FluidTank}.
*
* @return State information for the IFluidTank.
* @param stack Fluidstack holding the Fluid to be queried.
* @return If the tank can hold the fluid (EVER, not at the time of query).
*/
FluidTankInfo getInfo();
boolean isFluidValid(FluidStack stack);
/**
*
* @param resource
* FluidStack attempting to fill the tank.
* @param doFill
* If false, the fill will only be simulated.
* @return Amount of fluid that was accepted by the tank.
* @param resource FluidStack attempting to fill the tank.
* @param action If SIMULATE, the fill will only be simulated.
* @return Amount of fluid that was accepted (or would be, if simulated) by the tank.
*/
int fill(FluidStack resource, boolean doFill);
int fill(FluidStack resource, FluidAction action);
/**
*
* @param maxDrain
* Maximum amount of fluid to be removed from the container.
* @param doDrain
* If false, the drain will only be simulated.
* @return Amount of fluid that was removed from the tank.
* @param maxDrain Maximum amount of fluid to be removed from the container.
* @param action If SIMULATE, the drain will only be simulated.
* @return Amount of fluid that was removed (or would be, if simulated) from the tank.
*/
@Nullable
FluidStack drain(int maxDrain, boolean doDrain);
FluidStack drain(int maxDrain, FluidAction action);
/**
* @param resource Maximum amount of fluid to be removed from the container.
* @param action If SIMULATE, the drain will only be simulated.
* @return FluidStack representing fluid that was removed (or would be, if simulated) from the tank.
*/
@Nullable
FluidStack drain(FluidStack resource, FluidAction action);
}

View File

@ -1,302 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids;
import net.minecraft.block.DispenserBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.stats.Stats;
import net.minecraft.util.ActionResult;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Hand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.RayTraceContext;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.RayTraceContext.FluidMode;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.translation.LanguageMap;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.event.entity.player.FillBucketEvent;
import net.minecraftforge.event.ForgeEventFactory;
import net.minecraftforge.fluids.capability.wrappers.FluidBucketWrapper;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.items.ItemHandlerHelper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.item.Item.Properties;
/**
* A universal bucket that can hold any liquid
*/
public class UniversalBucket extends Item
{
private final int capacity; // how much the bucket holds
@Nonnull
private final ItemStack empty; // empty item to return and recognize when filling
private final boolean nbtSensitive;
public UniversalBucket(Properties properties)
{
this(properties, Fluid.BUCKET_VOLUME, new ItemStack(Items.BUCKET), false);
}
/**
* @param capacity Capacity of the container
* @param empty Item used for filling with the bucket event and returned when emptied
* @param nbtSensitive Whether the empty item is NBT sensitive (usually true if empty and full are the same items)
*/
public UniversalBucket(Properties properties, int capacity, @Nonnull ItemStack empty, boolean nbtSensitive)
{
super(properties);
this.capacity = capacity;
this.empty = empty;
this.nbtSensitive = nbtSensitive;
/* TODO move to builder construction
this.setMaxStackSize(1);
this.setCreativeTab(CreativeTabs.MISC);
*/
DispenserBlock.registerDispenseBehavior(this, DispenseFluidContainer.getInstance());
}
@Override
public boolean hasContainerItem(@Nonnull ItemStack stack)
{
return !getEmpty().isEmpty();
}
@Nonnull
@Override
public ItemStack getContainerItem(@Nonnull ItemStack itemStack)
{
if (!getEmpty().isEmpty())
{
// Create a copy such that the game can't mess with it
return getEmpty().copy();
}
return super.getContainerItem(itemStack);
}
@Override
public void fillItemGroup(@Nullable ItemGroup tab, @Nonnull NonNullList<ItemStack> subItems)
{
if (!this.isInGroup(tab))
return;/* TODO fluids
for (Fluid fluid : FluidRegistry.getRegisteredFluids().values())
{
if (fluid != FluidRegistry.WATER && fluid != FluidRegistry.LAVA && !fluid.getName().equals("milk"))
{
// add all fluids that the bucket can be filled with
FluidStack fs = new FluidStack(fluid, getCapacity());
ItemStack stack = new ItemStack(this);
IFluidHandlerItem fluidHandler = new FluidBucketWrapper(stack);
if (fluidHandler.fill(fs, true) == fs.amount)
{
ItemStack filled = fluidHandler.getContainer();
subItems.add(filled);
}
}
}*/
}
@Override
@Nonnull
public ITextComponent getDisplayName(@Nonnull ItemStack stack)
{
FluidStack fluidStack = getFluid(stack);
if (fluidStack == null)
{
if(!getEmpty().isEmpty())
{
return getEmpty().getDisplayName();
}
return super.getDisplayName(stack);
}
String unloc = this.getTranslationKey();
// TODO this is not reliable on the server
if (LanguageMap.getInstance().exists(unloc + "." + fluidStack.getFluid().getName()))
{
return new TranslationTextComponent(unloc + "." + fluidStack.getFluid().getName());
}
return new TranslationTextComponent(unloc + ".name", fluidStack.getLocalizedName());
}
@Override
@Nonnull
public ActionResult<ItemStack> onItemRightClick(@Nonnull World world, @Nonnull PlayerEntity player, @Nonnull Hand hand)
{
ItemStack itemstack = player.getHeldItem(hand);
FluidStack fluidStack = getFluid(itemstack);
// empty bucket shouldn't exist, do nothing since it should be handled by the bucket event
if (fluidStack == null)
{
return new ActionResult<ItemStack>(ActionResultType.PASS, itemstack);
}
// clicked on a block?
RayTraceResult rt = rayTrace(world, player, FluidMode.NONE);
ActionResult<ItemStack> ret = ForgeEventFactory.onBucketUse(player, world, itemstack, rt);
if (ret != null) return ret;
if(rt == null || rt.getType() != RayTraceResult.Type.BLOCK)
{
return new ActionResult<ItemStack>(ActionResultType.PASS, itemstack);
}
BlockRayTraceResult brt = (BlockRayTraceResult) rt;
BlockPos clickPos = brt.getPos();
// can we place liquid there?
if (world.isBlockModifiable(player, clickPos))
{
// the block adjacent to the side we clicked on
BlockPos targetPos = clickPos.offset(brt.getFace());
// can the player place there?
if (player.canPlayerEdit(targetPos, brt.getFace(), itemstack))
{
// try placing liquid
FluidActionResult result = FluidUtil.tryPlaceFluid(player, world, hand, targetPos, itemstack, fluidStack);
if (result.isSuccess() && !player.abilities.isCreativeMode)
{
// success!
player.addStat(Stats.ITEM_USED.get(this));
itemstack.shrink(1);
ItemStack drained = result.getResult();
ItemStack emptyStack = !drained.isEmpty() ? drained.copy() : new ItemStack(this);
// check whether we replace the item or add the empty one to the inventory
if (itemstack.isEmpty())
{
return new ActionResult<ItemStack>(ActionResultType.SUCCESS, emptyStack);
}
else
{
// add empty bucket to player inventory
ItemHandlerHelper.giveItemToPlayer(player, emptyStack);
return new ActionResult<ItemStack>(ActionResultType.SUCCESS, itemstack);
}
}
}
}
// couldn't place liquid there2
return new ActionResult<ItemStack>(ActionResultType.FAIL, itemstack);
}
@SubscribeEvent(priority = EventPriority.LOW) // low priority so other mods can handle their stuff first
public void onFillBucket(FillBucketEvent event)
{
if (event.getResult() != net.minecraftforge.eventbus.api.Event.Result.DEFAULT)
{
// event was already handled
return;
}
// not for us to handle
ItemStack emptyBucket = event.getEmptyBucket();
if (emptyBucket.isEmpty() ||
!emptyBucket.isItemEqual(getEmpty()) ||
(isNbtSensitive() && ItemStack.areItemStackTagsEqual(emptyBucket, getEmpty())))
{
return;
}
// needs to target a block
RayTraceResult target = event.getTarget();
if (target == null || target.getType() != RayTraceResult.Type.BLOCK)
{
return;
}
World world = event.getWorld();
BlockPos pos = ((BlockRayTraceResult) target).getPos();
ItemStack singleBucket = emptyBucket.copy();
singleBucket.setCount(1);
FluidActionResult filledResult = FluidUtil.tryPickUpFluid(singleBucket, event.getEntityPlayer(), world, pos, ((BlockRayTraceResult) target).getFace());
if (filledResult.isSuccess())
{
event.setResult(net.minecraftforge.eventbus.api.Event.Result.ALLOW);
event.setFilledBucket(filledResult.getResult());
}
else
{
// cancel event, otherwise the vanilla minecraft ItemBucket would
// convert it into a water/lava bucket depending on the blocks material
event.setCanceled(true);
}
}
@Nullable
public FluidStack getFluid(@Nonnull ItemStack container)
{
return FluidStack.loadFluidStackFromNBT(container.getTag());
}
public int getCapacity()
{
return capacity;
}
@Nonnull
public ItemStack getEmpty()
{
return empty;
}
public boolean isNbtSensitive()
{
return nbtSensitive;
}
@Nullable
@Override
public String getCreatorModId(@Nonnull ItemStack itemStack)
{
FluidStack fluidStack = getFluid(itemStack);
String modId = null; // TODO fluids FluidRegistry.getModId(fluidStack);
return modId != null ? modId : super.getCreatorModId(itemStack);
}
@Override
public ICapabilityProvider initCapabilities(@Nonnull ItemStack stack, CompoundNBT nbt)
{
return new FluidBucketWrapper(stack);
}
}

View File

@ -27,11 +27,10 @@ import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.templates.FluidHandlerItemStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
public class CapabilityFluidHandler
{
@ -40,21 +39,21 @@ public class CapabilityFluidHandler
@CapabilityInject(IFluidHandlerItem.class)
public static Capability<IFluidHandlerItem> FLUID_HANDLER_ITEM_CAPABILITY = null;
public static void register()
public static void register()
{
CapabilityManager.INSTANCE.register(IFluidHandler.class, new DefaultFluidHandlerStorage<>(), () -> new FluidTank(Fluid.BUCKET_VOLUME));
CapabilityManager.INSTANCE.register(IFluidHandler.class, new DefaultFluidHandlerStorage<>(), () -> new FluidTank(FluidAttributes.BUCKET_VOLUME));
CapabilityManager.INSTANCE.register(IFluidHandlerItem.class, new DefaultFluidHandlerStorage<>(), () -> new FluidHandlerItemStack(new ItemStack(Items.BUCKET), Fluid.BUCKET_VOLUME));
CapabilityManager.INSTANCE.register(IFluidHandlerItem.class, new DefaultFluidHandlerStorage<>(), () -> new FluidHandlerItemStack(new ItemStack(Items.BUCKET), FluidAttributes.BUCKET_VOLUME));
}
private static class DefaultFluidHandlerStorage<T extends IFluidHandler> implements Capability.IStorage<T> {
@Override
public INBT writeNBT(Capability<T> capability, T instance, Direction side)
{
if (!(instance instanceof IFluidTank))
throw new RuntimeException("IFluidHandler instance does not implement IFluidTank");
if (!(instance instanceof FluidTank))
throw new RuntimeException("Cannot serialize to an instance that isn't the default implementation");
CompoundNBT nbt = new CompoundNBT();
IFluidTank tank = (IFluidTank) instance;
FluidTank tank = (FluidTank) instance;
FluidStack fluid = tank.getFluid();
if (fluid != null)
{
@ -72,7 +71,7 @@ public class CapabilityFluidHandler
public void readNBT(Capability<T> capability, T instance, Direction side, INBT nbt)
{
if (!(instance instanceof FluidTank))
throw new RuntimeException("IFluidHandler instance is not instance of FluidTank");
throw new RuntimeException("Cannot deserialize to an instance that isn't the default implementation");
CompoundNBT tags = (CompoundNBT) nbt;
FluidTank tank = (FluidTank) instance;
tank.setCapacity(tags.getInt("Capacity"));

View File

@ -1,98 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
/**
* Basic implementation of {@link IFluidTankProperties}.
*/
public class FluidTankProperties implements IFluidTankProperties
{
public static FluidTankProperties[] convert(FluidTankInfo[] fluidTankInfos)
{
FluidTankProperties[] properties = new FluidTankProperties[fluidTankInfos.length];
for (int i = 0; i < fluidTankInfos.length; i++)
{
FluidTankInfo info = fluidTankInfos[i];
properties[i] = new FluidTankProperties(info.fluid, info.capacity);
}
return properties;
}
@Nullable
private final FluidStack contents;
private final int capacity;
private final boolean canFill;
private final boolean canDrain;
public FluidTankProperties(@Nullable FluidStack contents, int capacity)
{
this(contents, capacity, true, true);
}
public FluidTankProperties(@Nullable FluidStack contents, int capacity, boolean canFill, boolean canDrain)
{
this.contents = contents;
this.capacity = capacity;
this.canFill = canFill;
this.canDrain = canDrain;
}
@Nullable
@Override
public FluidStack getContents()
{
return contents == null ? null : contents.copy();
}
@Override
public int getCapacity()
{
return capacity;
}
@Override
public boolean canFill()
{
return canFill;
}
@Override
public boolean canDrain()
{
return canDrain;
}
@Override
public boolean canFillFluidType(FluidStack fluidStack)
{
return canFill;
}
@Override
public boolean canDrainFluidType(FluidStack fluidStack)
{
return canDrain;
}
}

View File

@ -1,76 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
/**
* Basic {@link IFluidTankProperties} wrapper for {@link FluidTank}.
*/
public class FluidTankPropertiesWrapper implements IFluidTankProperties
{
protected final FluidTank tank;
public FluidTankPropertiesWrapper(FluidTank tank)
{
this.tank = tank;
}
@Nullable
@Override
public FluidStack getContents()
{
FluidStack contents = tank.getFluid();
return contents == null ? null : contents.copy();
}
@Override
public int getCapacity()
{
return tank.getCapacity();
}
@Override
public boolean canFill()
{
return tank.canFill();
}
@Override
public boolean canDrain()
{
return tank.canDrain();
}
@Override
public boolean canFillFluidType(FluidStack fluidStack)
{
return tank.canFillFluidType(fluidStack);
}
@Override
public boolean canDrainFluidType(FluidStack fluidStack)
{
return tank.canDrainFluidType(fluidStack);
}
}

View File

@ -19,6 +19,7 @@
package net.minecraftforge.fluids.capability;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.*;
@ -31,33 +32,82 @@ import net.minecraftforge.fluids.*;
*/
public interface IFluidHandler
{
enum FluidAction {
EXECUTE, SIMULATE;
public boolean execute() {
return this == EXECUTE;
}
public boolean simulate() {
return this == SIMULATE;
}
}
/**
* Returns an array of objects which represent the internal tanks.
* These objects cannot be used to manipulate the internal tanks.
* Returns the number of fluid storage units ("tanks") available
*
* @return Properties for the relevant internal tanks.
* @return The number of tanks available
*/
IFluidTankProperties[] getTankProperties();
int getTanks();
/**
* Returns the FluidStack in a given tank.
*
* <p>
* <strong>IMPORTANT:</strong> This FluidStack <em>MUST NOT</em> be modified. This method is not for
* altering internal contents. Any implementers who are able to detect modification via this method
* should throw an exception. It is ENTIRELY reasonable and likely that the stack returned here will be a copy.
* </p>
*
* <p>
* <strong><em>SERIOUSLY: DO NOT MODIFY THE RETURNED FLUIDSTACK</em></strong>
* </p>
*
* @param tank Tank to query.
* @return FluidStack in a given tank. NULL if the tank is empty.
*/
@Nullable
FluidStack getFluidInTank(int tank);
/**
* Retrieves the maximum fluid amount for a given tank.
*
* @param tank Tank to query.
* @return The maximum fluid amount held by the tank.
*/
int getTankCapacity(int tank);
/**
* This function is a way to determine which fluids can exist inside a given handler. General purpose tanks will
* basically always return TRUE for this.
*
* @param tank Tank to query for validity
* @param stack Stack to test with for validity
* @return TRUE if the tank can hold the FluidStack, not considering current state.
* (Basically, is a given fluid EVER allowed in this tank?) Return FALSE if the answer to that question is 'no.'
*/
boolean isFluidValid(int tank, @Nonnull FluidStack stack);
/**
* Fills fluid into internal tanks, distribution is left entirely to the IFluidHandler.
*
* @param resource FluidStack representing the Fluid and maximum amount of fluid to be filled.
* @param doFill If false, fill will only be simulated.
* @param action If SIMULATE, fill will only be simulated.
* @return Amount of resource that was (or would have been, if simulated) filled.
*/
int fill(FluidStack resource, boolean doFill);
int fill(FluidStack resource, FluidAction action);
/**
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
*
* @param resource FluidStack representing the Fluid and maximum amount of fluid to be drained.
* @param doDrain If false, drain will only be simulated.
* @param action If SIMULATE, drain will only be simulated.
* @return FluidStack representing the Fluid and amount that was (or would have been, if
* simulated) drained.
*/
@Nullable
FluidStack drain(FluidStack resource, boolean doDrain);
FluidStack drain(FluidStack resource, FluidAction action);
/**
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
@ -65,10 +115,11 @@ public interface IFluidHandler
* This method is not Fluid-sensitive.
*
* @param maxDrain Maximum amount of fluid to drain.
* @param doDrain If false, drain will only be simulated.
* @param action If SIMULATE, drain will only be simulated.
* @return FluidStack representing the Fluid and amount that was (or would have been, if
* simulated) drained.
*/
@Nullable
FluidStack drain(int maxDrain, boolean doDrain);
FluidStack drain(int maxDrain, FluidAction action);
}

View File

@ -1,84 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
/**
* Simplified Read-only Information about the internals of an {@link IFluidHandler}.
* This is useful for displaying information, and as hints for interacting with it.
* These properties are constant and do not depend on the fluid contents (except the contents themselves, of course).
*
* The information here may not tell the full story of how the tank actually works,
* for real fluid transactions you must use {@link IFluidHandler} to simulate, check, and then interact.
* None of the information in these properties is required to successfully interact using a {@link IFluidHandler}.
*/
public interface IFluidTankProperties
{
/**
* @return A copy of the fluid contents of this tank. May be null.
* To modify the contents, use {@link IFluidHandler}.
*/
@Nullable
FluidStack getContents();
/**
* @return The maximum amount of fluid this tank can hold, in millibuckets.
*/
int getCapacity();
/**
* Returns true if the tank can be filled at any time (even if it is currently full).
* It does not consider the contents or capacity of the tank.
*
* This value is constant. If the tank behavior is more complicated, returns true.
*/
boolean canFill();
/**
* Returns true if the tank can be drained at any time (even if it is currently empty).
* It does not consider the contents or capacity of the tank.
*
* This value is constant. If the tank behavior is more complicated, returns true.
*/
boolean canDrain();
/**
* Returns true if the tank can be filled with a specific type of fluid.
* Used as a filter for fluid types.
*
* Does not consider the current contents or capacity of the tank,
* only whether it could ever fill with this type of fluid.
* {@link FluidStack} is used here because fluid properties can depend on NBT, the amount is ignored.
*/
boolean canFillFluidType(FluidStack fluidStack);
/**
* Returns true if the tank can drain out this a specific of fluid.
* Used as a filter for fluid types.
*
* Does not consider the current contents or capacity of the tank,
* only whether it could ever drain out this type of fluid.
* {@link FluidStack} is used here because fluid properties can depend on NBT, the amount is ignored.
*/
boolean canDrainFluidType(FluidStack fluidStack);
}

View File

@ -25,15 +25,15 @@ import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.capability.templates.FluidTank;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public class TileFluidHandler extends TileEntity
{
protected FluidTank tank = new FluidTank(Fluid.BUCKET_VOLUME);
protected FluidTank tank = new FluidTank(FluidAttributes.BUCKET_VOLUME);
private final LazyOptional<IFluidHandler> holder = LazyOptional.of(() -> tank);

View File

@ -19,69 +19,47 @@
package net.minecraftforge.fluids.capability.templates;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class EmptyFluidHandler implements IFluidHandler, IFluidTank
public class EmptyFluidHandler implements IFluidHandler
{
public static final EmptyFluidHandler INSTANCE = new EmptyFluidHandler();
public static final FluidTankInfo EMPTY_TANK_INFO = new FluidTankInfo(null, 0);
public static final IFluidTankProperties EMPTY_TANK_PROPERTIES = new FluidTankProperties(null, 0, false, false);
public static final IFluidTankProperties[] EMPTY_TANK_PROPERTIES_ARRAY = new IFluidTankProperties[] { EMPTY_TANK_PROPERTIES };
protected EmptyFluidHandler() {}
@Override
public IFluidTankProperties[] getTankProperties()
{
return EMPTY_TANK_PROPERTIES_ARRAY;
}
public int getTanks() { return 1; }
@Override
@Nullable
public FluidStack getFluid()
@Override
public FluidStack getFluidInTank(int tank) { return null; }
@Override
public int getTankCapacity(int tank) { return 0; }
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override
public int fill(FluidStack resource, FluidAction action)
{
return resource.amount;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{
return null;
}
@Nullable
@Override
public int getFluidAmount()
{
return 0;
}
@Override
public int getCapacity()
{
return 0;
}
@Override
public FluidTankInfo getInfo()
{
return EMPTY_TANK_INFO;
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
return 0;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
return null;
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
public FluidStack drain(int maxDrain, FluidAction action)
{
return null;
}

View File

@ -1,140 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability.templates;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* FluidHandlerConcatenate is a template class for concatenating multiple handlers into one.
* If each tank is restricted to exactly one type of fluid, then use {@link FluidHandlerFluidMap} as it is more efficient.
*/
public class FluidHandlerConcatenate implements IFluidHandler
{
protected final IFluidHandler[] subHandlers;
public FluidHandlerConcatenate(IFluidHandler... subHandlers)
{
this.subHandlers = subHandlers;
}
public FluidHandlerConcatenate(Collection<IFluidHandler> subHandlers)
{
this.subHandlers = subHandlers.toArray(new IFluidHandler[subHandlers.size()]);
}
@Override
public IFluidTankProperties[] getTankProperties()
{
List<IFluidTankProperties> tanks = Lists.newArrayList();
for (IFluidHandler handler : subHandlers)
{
Collections.addAll(tanks, handler.getTankProperties());
}
return tanks.toArray(new IFluidTankProperties[tanks.size()]);
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null || resource.amount <= 0)
return 0;
resource = resource.copy();
int totalFillAmount = 0;
for (IFluidHandler handler : subHandlers)
{
int fillAmount = handler.fill(resource, doFill);
totalFillAmount += fillAmount;
resource.amount -= fillAmount;
if (resource.amount <= 0)
break;
}
return totalFillAmount;
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || resource.amount <= 0)
return null;
resource = resource.copy();
FluidStack totalDrained = null;
for (IFluidHandler handler : subHandlers)
{
FluidStack drain = handler.drain(resource, doDrain);
if (drain != null)
{
if (totalDrained == null)
totalDrained = drain;
else
totalDrained.amount += drain.amount;
resource.amount -= drain.amount;
if (resource.amount <= 0)
break;
}
}
return totalDrained;
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain == 0)
return null;
FluidStack totalDrained = null;
for (IFluidHandler handler : subHandlers)
{
if (totalDrained == null)
{
totalDrained = handler.drain(maxDrain, doDrain);
if (totalDrained != null)
{
maxDrain -= totalDrained.amount;
}
}
else
{
FluidStack copy = totalDrained.copy();
copy.amount = maxDrain;
FluidStack drain = handler.drain(copy, doDrain);
if (drain != null)
{
totalDrained.amount += drain.amount;
maxDrain -= drain.amount;
}
}
if (maxDrain <= 0)
break;
}
return totalDrained;
}
}

View File

@ -1,99 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability.templates;
import com.google.common.collect.Lists;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
import java.util.*;
/**
* FluidHandlerFluidMap is a template class for concatenating multiple handlers into one,
* where each handler is associated with a different fluid.
*/
public class FluidHandlerFluidMap implements IFluidHandler
{
protected final Map<Fluid, IFluidHandler> handlers;
public FluidHandlerFluidMap()
{
// LinkedHashMap to ensure iteration order is consistent.
this(new LinkedHashMap<Fluid, IFluidHandler>());
}
public FluidHandlerFluidMap(Map<Fluid, IFluidHandler> handlers)
{
this.handlers = handlers;
}
public FluidHandlerFluidMap addHandler(Fluid fluid, IFluidHandler handler)
{
handlers.put(fluid, handler);
return this;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
List<IFluidTankProperties> tanks = Lists.newArrayList();
for (IFluidHandler iFluidHandler : handlers.values())
{
Collections.addAll(tanks, iFluidHandler.getTankProperties());
}
return tanks.toArray(new IFluidTankProperties[tanks.size()]);
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (resource == null)
return 0;
IFluidHandler handler = handlers.get(resource.getFluid());
if (handler == null)
return 0;
return handler.fill(resource, doFill);
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null)
return null;
IFluidHandler handler = handlers.get(resource.getFluid());
if (handler == null)
return null;
return handler.drain(resource, doDrain);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
for (IFluidHandler handler : handlers.values())
{
FluidStack drain = handler.drain(maxDrain, doDrain);
if (drain != null)
return drain;
}
return null;
}
}

View File

@ -30,15 +30,13 @@ import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.*;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
/**
* FluidHandlerItemStack is a template capability provider for ItemStacks.
* Data is stored directly in the vanilla NBT, in the same way as the old ItemFluidContainer.
*
* This class allows an itemStack to contain any partial level of fluid up to its capacity, unlike {@link FluidHandlerItemStackSimple}
* This class allows an ItemStack to contain any partial level of fluid up to its capacity, unlike {@link FluidHandlerItemStackSimple}
*
* Additional examples are provided to enable consumable fluid containers (see {@link Consumable}),
* fluid containers with different empty and full items (see {@link SwapEmpty},
@ -94,13 +92,32 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new FluidTankProperties[] { new FluidTankProperties(getFluid(), capacity) };
public int getTanks() {
return 1;
}
@Nullable
@Override
public FluidStack getFluidInTank(int tank) {
return getFluid();
}
@Override
public int fill(FluidStack resource, boolean doFill)
public int getTankCapacity(int tank) {
return capacity;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
@Override
public int fill(FluidStack resource, FluidAction doFill)
{
if (container.getCount() != 1 || resource == null || resource.amount <= 0 || !canFillFluidType(resource))
{
@ -112,7 +129,7 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
{
int fillAmount = Math.min(capacity, resource.amount);
if (doFill)
if (doFill.execute())
{
FluidStack filled = resource.copy();
filled.amount = fillAmount;
@ -127,7 +144,7 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
{
int fillAmount = Math.min(capacity - contained.amount, resource.amount);
if (doFill && fillAmount > 0) {
if (doFill.execute() && fillAmount > 0) {
contained.amount += fillAmount;
setFluid(contained);
}
@ -140,17 +157,17 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
public FluidStack drain(FluidStack resource, FluidAction action)
{
if (container.getCount() != 1 || resource == null || resource.amount <= 0 || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drain(resource.amount, doDrain);
return drain(resource.amount, action);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
public FluidStack drain(int maxDrain, FluidAction action)
{
if (container.getCount() != 1 || maxDrain <= 0)
{
@ -168,7 +185,7 @@ public class FluidHandlerItemStack implements IFluidHandlerItem, ICapabilityProv
FluidStack drained = contained.copy();
drained.amount = drainAmount;
if (doDrain)
if (action.execute())
{
contained.amount -= drainAmount;
if (contained.amount == 0)

View File

@ -29,9 +29,7 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
/**
@ -91,13 +89,32 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new IFluidTankProperties[] { new FluidTankProperties(getFluid(), capacity) };
public int getTanks() {
return 1;
}
@Nullable
@Override
public FluidStack getFluidInTank(int tank) {
return getFluid();
}
@Override
public int fill(FluidStack resource, boolean doFill)
public int getTankCapacity(int tank) {
return capacity;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
@Override
public int fill(FluidStack resource, FluidAction action)
{
if (container.getCount() != 1 || resource == null || resource.amount <= 0 || !canFillFluidType(resource))
{
@ -109,7 +126,7 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
{
int fillAmount = Math.min(capacity, resource.amount);
if (fillAmount == capacity) {
if (doFill) {
if (action.execute()) {
FluidStack filled = resource.copy();
filled.amount = fillAmount;
setFluid(filled);
@ -123,17 +140,17 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
}
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
public FluidStack drain(FluidStack resource, FluidAction action)
{
if (container.getCount() != 1 || resource == null || resource.amount <= 0 || !resource.isFluidEqual(getFluid()))
{
return null;
}
return drain(resource.amount, doDrain);
return drain(resource.amount, action);
}
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
public FluidStack drain(int maxDrain, FluidAction action)
{
if (container.getCount() != 1 || maxDrain <= 0)
{
@ -150,7 +167,7 @@ public class FluidHandlerItemStackSimple implements IFluidHandlerItem, ICapabili
if (drainAmount == capacity) {
FluidStack drained = contained.copy();
if (doDrain) {
if (action.execute()) {
setContainerToEmpty();
}

View File

@ -0,0 +1,244 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability.templates;
import net.minecraft.nbt.CompoundNBT;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.function.Predicate;
/**
* Flexible implementation of a Fluid Storage object. NOT REQUIRED.
*
* @author King Lemming
*/
public class FluidTank implements IFluidHandler, IFluidTank {
protected Predicate<FluidStack> validator;
@Nullable
protected FluidStack fluid = null;
protected int capacity;
public FluidTank(int capacity)
{
this(capacity, e -> true);
}
public FluidTank(int capacity, Predicate<FluidStack> validator)
{
this.capacity = capacity;
this.validator = validator;
}
public FluidTank setCapacity(int capacity)
{
this.capacity = capacity;
return this;
}
public FluidTank setValidator(Predicate<FluidStack> validator)
{
if (validator != null) {
this.validator = validator;
}
return this;
}
public boolean isFluidValid(FluidStack stack)
{
return validator.test(stack);
}
public int getCapacity()
{
return capacity;
}
public FluidStack getFluid()
{
return fluid;
}
public int getFluidAmount()
{
if (fluid == null)
{
return 0;
}
return fluid.amount;
}
public FluidTank readFromNBT(CompoundNBT nbt) {
FluidStack fluid = null;
if (!nbt.contains("Empty"))
{
fluid = FluidStack.loadFluidStackFromNBT(nbt);
}
setFluid(fluid);
return this;
}
public CompoundNBT writeToNBT(CompoundNBT nbt) {
if (fluid != null)
{
fluid.writeToNBT(nbt);
}
else
{
nbt.putString("Empty", "");
}
return nbt;
}
@Override
public int getTanks() {
return 1;
}
@Nullable
@Override
public FluidStack getFluidInTank(int tank) {
return getFluid();
}
@Override
public int getTankCapacity(int tank) {
return getCapacity();
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return isFluidValid(stack);
}
@Override
public int fill(FluidStack resource, FluidAction action)
{
if (resource == null || !isFluidValid(resource))
{
return 0;
}
if (action.simulate())
{
if (fluid == null)
{
return Math.min(capacity, resource.amount);
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
return Math.min(capacity - fluid.amount, resource.amount);
}
if (fluid == null)
{
onContentsChanged();
fluid = new FluidStack(resource, Math.min(capacity, resource.amount));
return fluid.amount;
}
if (!fluid.isFluidEqual(resource))
{
return 0;
}
int filled = capacity - fluid.amount;
if (resource.amount < filled)
{
fluid.amount += resource.amount;
filled = resource.amount;
}
else
{
fluid.amount = capacity;
}
return filled;
}
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{
if (resource == null || !resource.isFluidEqual(fluid))
{
return null;
}
return drain(resource.amount, action);
}
@Override
public FluidStack drain(int maxDrain, FluidAction action)
{
if (fluid == null)
{
return null;
}
int drained = maxDrain;
if (fluid.amount < drained)
{
drained = fluid.amount;
}
FluidStack stack = new FluidStack(fluid, drained);
if (action.execute())
{
fluid.amount -= drained;
if (fluid.amount <= 0)
{
fluid = null;
}
}
return stack;
}
protected void onContentsChanged()
{
}
public void setFluid(FluidStack stack)
{
this.fluid = stack;
}
public boolean isEmpty()
{
return fluid == null || fluid.amount <= 0;
}
public int getSpace()
{
if (fluid == null)
{
return capacity;
}
return fluid.amount >= capacity ? 0 : capacity - fluid.amount;
}
}

View File

@ -20,73 +20,50 @@
package net.minecraftforge.fluids.capability.templates;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.Nullable;
import static net.minecraftforge.fluids.capability.templates.EmptyFluidHandler.EMPTY_TANK_INFO;
import static net.minecraftforge.fluids.capability.templates.EmptyFluidHandler.EMPTY_TANK_PROPERTIES_ARRAY;
/**
* VoidFluidHandler is a template fluid handler that can be filled indefinitely without ever getting full.
* It does not store fluid that gets filled into it, but "destroys" it upon receiving it.
*/
public class VoidFluidHandler implements IFluidHandler, IFluidTank
public class VoidFluidHandler implements IFluidHandler
{
public static final VoidFluidHandler INSTANCE = new VoidFluidHandler();
public VoidFluidHandler() {}
@Override
public IFluidTankProperties[] getTankProperties()
{
return EMPTY_TANK_PROPERTIES_ARRAY;
}
public int getTanks() { return 1; }
@Override
@Nullable
public FluidStack getFluid()
{
return null;
}
@Override
public FluidStack getFluidInTank(int tank) { return null; }
@Override
public int getFluidAmount()
{
return 0;
}
public int getTankCapacity(int tank) { return Integer.MAX_VALUE; }
@Override
public int getCapacity()
{
return Integer.MAX_VALUE;
}
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) { return true; }
@Override
public FluidTankInfo getInfo()
{
return EMPTY_TANK_INFO;
}
@Override
public int fill(FluidStack resource, boolean doFill)
public int fill(FluidStack resource, FluidAction action)
{
return resource.amount;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
public FluidStack drain(FluidStack resource, FluidAction action)
{
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
public FluidStack drain(int maxDrain, FluidAction action)
{
return null;
}

View File

@ -1,159 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability.wrappers;
/*
import javax.annotation.Nullable;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBucket;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wrapper to handle vanilla Water or Lava as an IFluidHandler.
* Methods are modeled after {@link ItemBucket#onItemRightClick(World, EntityPlayer, EnumHand)}
* /
public class BlockLiquidWrapper implements IFluidHandler
{
protected final BlockLiquid blockLiquid;
protected final World world;
protected final BlockPos blockPos;
public BlockLiquidWrapper(BlockLiquid blockLiquid, World world, BlockPos blockPos)
{
this.blockLiquid = blockLiquid;
this.world = world;
this.blockPos = blockPos;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
FluidStack containedStack = null;
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid)
{
containedStack = getStack(blockState);
}
return new FluidTankProperties[]{new FluidTankProperties(containedStack, Fluid.BUCKET_VOLUME, false, true)};
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
// NOTE: "Filling" means placement in this context!
if (resource.amount < Fluid.BUCKET_VOLUME)
{
return 0;
}
if (doFill)
{
Material material = blockLiquid.getDefaultState().getMaterial();
BlockLiquid block = BlockLiquid.getFlowingBlock(material);
world.setBlockState(blockPos, block.getDefaultState().withProperty(BlockLiquid.LEVEL, 0), 11);
}
return Fluid.BUCKET_VOLUME;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || resource.amount < Fluid.BUCKET_VOLUME)
{
return null;
}
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
FluidStack containedStack = getStack(blockState);
if (containedStack != null && resource.containsFluid(containedStack))
{
if (doDrain)
{
world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), Constants.BlockFlags.DEFAULT_AND_RERENDER);
}
return containedStack;
}
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain < Fluid.BUCKET_VOLUME)
{
return null;
}
IBlockState blockState = world.getBlockState(blockPos);
if (blockState.getBlock() == blockLiquid)
{
FluidStack containedStack = getStack(blockState);
if (containedStack != null && containedStack.amount <= maxDrain)
{
if (doDrain)
{
world.setBlockState(blockPos, Blocks.AIR.getDefaultState(), Constants.BlockFlags.DEFAULT_AND_RERENDER);
}
return containedStack;
}
}
return null;
}
@Nullable
private FluidStack getStack(IBlockState blockState)
{
Material material = blockState.getMaterial();
if (material == Material.WATER && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
return new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME);
}
else if (material == Material.LAVA && blockState.getValue(BlockLiquid.LEVEL) == 0)
{
return new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME);
}
else
{
return null;
}
}
}
*/

View File

@ -20,10 +20,11 @@
package net.minecraftforge.fluids.capability.wrappers;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.templates.VoidFluidHandler;
@ -35,30 +36,30 @@ import net.minecraftforge.fluids.capability.templates.VoidFluidHandler;
*/
public class BlockWrapper extends VoidFluidHandler
{
protected final Block block;
protected final BlockState state;
protected final World world;
protected final BlockPos blockPos;
public BlockWrapper(Block block, World world, BlockPos blockPos)
public BlockWrapper(BlockState state, World world, BlockPos blockPos)
{
this.block = block;
this.state = state;
this.world = world;
this.blockPos = blockPos;
}
@Override
public int fill(FluidStack resource, boolean doFill)
public int fill(FluidStack resource, FluidAction action)
{
// NOTE: "Filling" means placement in this context!
if (resource.amount < Fluid.BUCKET_VOLUME)
if (resource.amount < FluidAttributes.BUCKET_VOLUME)
{
return 0;
}
if (doFill)
if (action.execute())
{
FluidUtil.destroyBlockOnFluidPlacement(world, blockPos);
world.setBlockState(blockPos, block.getDefaultState(), Constants.BlockFlags.DEFAULT_AND_RERENDER);
world.setBlockState(blockPos, state, Constants.BlockFlags.DEFAULT_AND_RERENDER);
}
return Fluid.BUCKET_VOLUME;
return FluidAttributes.BUCKET_VOLUME;
}
}

View File

@ -1,122 +0,0 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nullable;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandler;
/**
* Wrapper to handle {@link IFluidBlock} as an IFluidHandler
*/
public class FluidBlockWrapper implements IFluidHandler
{
protected final IFluidBlock fluidBlock;
protected final World world;
protected final BlockPos blockPos;
public FluidBlockWrapper(IFluidBlock fluidBlock, World world, BlockPos blockPos)
{
this.fluidBlock = fluidBlock;
this.world = world;
this.blockPos = blockPos;
}
@Override
public IFluidTankProperties[] getTankProperties()
{
float percentFilled = fluidBlock.getFilledPercentage(world, blockPos);
if (percentFilled < 0)
{
percentFilled *= -1;
}
int amountFilled = Math.round(Fluid.BUCKET_VOLUME * percentFilled);
FluidStack fluid = amountFilled > 0 ? new FluidStack(fluidBlock.getFluid(), amountFilled) : null;
return new FluidTankProperties[]{ new FluidTankProperties(fluid, Fluid.BUCKET_VOLUME, false, true)};
}
@Override
public int fill(FluidStack resource, boolean doFill)
{
// NOTE: "Filling" means placement in this context!
if (resource == null)
{
return 0;
}
return fluidBlock.place(world, blockPos, resource, doFill);
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
{
if (resource == null || !fluidBlock.canDrain(world, blockPos))
{
return null;
}
FluidStack simulatedDrain = fluidBlock.drain(world, blockPos, false);
if (resource.containsFluid(simulatedDrain))
{
if (doDrain)
{
return fluidBlock.drain(world, blockPos, true);
}
else
{
return simulatedDrain;
}
}
return null;
}
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
{
if (maxDrain <= 0 || !fluidBlock.canDrain(world, blockPos))
{
return null;
}
FluidStack simulatedDrain = fluidBlock.drain(world, blockPos, false);
if (simulatedDrain != null && simulatedDrain.amount <= maxDrain)
{
if (doDrain)
{
return fluidBlock.drain(world, blockPos, true);
}
else
{
return simulatedDrain;
}
}
return null;
}
}

View File

@ -22,22 +22,15 @@ package net.minecraftforge.fluids.capability.wrappers;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.item.Items;
import net.minecraft.item.Item;
import net.minecraft.item.MilkBucketItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.*;
import net.minecraft.util.Direction;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilityProvider;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.capability.FluidTankProperties;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
/**
@ -76,24 +69,17 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
@Nullable
public FluidStack getFluid()
{
Item item = container.getItem();/* TODO fluids
if (item == Items.WATER_BUCKET)
Item item = container.getItem();
if (item instanceof BucketItem)
{
return new FluidStack(FluidRegistry.WATER, Fluid.BUCKET_VOLUME);
}
else if (item == Items.LAVA_BUCKET)
{
return new FluidStack(FluidRegistry.LAVA, Fluid.BUCKET_VOLUME);
return new FluidStack(((BucketItem)item).getFluid(), FluidAttributes.BUCKET_VOLUME);
}
/* TODO fluids
else if (item == Items.MILK_BUCKET)
{
return FluidRegistry.getFluidStack("milk", Fluid.BUCKET_VOLUME);
}
else*/ if (item == ForgeMod.getInstance().universalBucket)
{
return ForgeMod.getInstance().universalBucket.getFluid(container);
}
else
else*/
{
return null;
}
@ -108,32 +94,51 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
}
@Override
public IFluidTankProperties[] getTankProperties()
{
return new FluidTankProperties[] { new FluidTankProperties(getFluid(), Fluid.BUCKET_VOLUME) };
}
public int getTanks() {
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.getCount() != 1 || resource == null || resource.amount < Fluid.BUCKET_VOLUME || container.getItem() instanceof MilkBucketItem || getFluid() != null || !canFillFluidType(resource))
{
return 0;
}
if (doFill)
{
setFluid(resource);
}
return Fluid.BUCKET_VOLUME;
return 1;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, boolean doDrain)
public FluidStack getFluidInTank(int tank) {
return getFluid();
}
@Override
public int getTankCapacity(int tank) {
return FluidAttributes.BUCKET_VOLUME;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return true;
}
@Override
public int fill(FluidStack resource, FluidAction action)
{
if (container.getCount() != 1 || resource == null || resource.amount < Fluid.BUCKET_VOLUME)
if (container.getCount() != 1 || resource == null || resource.amount < FluidAttributes.BUCKET_VOLUME || container.getItem() instanceof MilkBucketItem || getFluid() != null || !canFillFluidType(resource))
{
return 0;
}
if (action.execute())
{
setFluid(resource);
}
return FluidAttributes.BUCKET_VOLUME;
}
@Nullable
@Override
public FluidStack drain(FluidStack resource, FluidAction action)
{
if (container.getCount() != 1 || resource == null || resource.amount < FluidAttributes.BUCKET_VOLUME)
{
return null;
}
@ -141,9 +146,9 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
FluidStack fluidStack = getFluid();
if (fluidStack != null && fluidStack.isFluidEqual(resource))
{
if (doDrain)
if (action.execute())
{
setFluid((FluidStack) null);
setFluid(null);
}
return fluidStack;
}
@ -153,9 +158,9 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
@Nullable
@Override
public FluidStack drain(int maxDrain, boolean doDrain)
public FluidStack drain(int maxDrain, FluidAction action)
{
if (container.getCount() != 1 || maxDrain < Fluid.BUCKET_VOLUME)
if (container.getCount() != 1 || maxDrain < FluidAttributes.BUCKET_VOLUME)
{
return null;
}
@ -163,9 +168,9 @@ public class FluidBucketWrapper implements IFluidHandlerItem, ICapabilityProvide
FluidStack fluidStack = getFluid();
if (fluidStack != null)
{
if (doDrain)
if (action.execute())
{
setFluid((FluidStack) null);
setFluid(null);
}
return fluidStack;
}

View File

@ -214,7 +214,7 @@ public class ModLoader
if (containers.size() != modInfoMap.size()) {
LOGGER.fatal(LOADING,"File {} constructed {} mods: {}, but had {} mods specified: {}",
modFile.getFilePath(),
containers.size(), containers.stream().map(ModContainer::getModId).collect(Collectors.toList()),
containers.size(), containers.stream().map(c -> c != null ? c.getModId() : "(null)").collect(Collectors.toList()),
modInfoMap.size(), modInfoMap.values().stream().map(IModInfo::getModId).collect(Collectors.toList()));
loadingExceptions.add(new ModLoadingException(null, ModLoadingStage.CONSTRUCT, "fml.modloading.missingclasses", null, modFile.getFilePath()));
}

View File

@ -1,3 +1,22 @@
/*
* Minecraft Forge
* Copyright (c) 2016-2019.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package net.minecraftforge.fml.mclanguageprovider;
import net.minecraftforge.fml.ModContainer;

View File

@ -32,8 +32,6 @@ import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;

View File

@ -63,7 +63,7 @@ import net.minecraftforge.event.entity.player.FillBucketEvent;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTank;
import net.minecraftforge.fluids.FluidTankOld;
import net.minecraftforge.fluids.FluidUtil;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fluids.UniversalBucket;
@ -136,7 +136,7 @@ public class DynBucketTest
@net.minecraftforge.eventbus.api.SubscribeEvent
public void registerRecipes(RegistryEvent.Register<IRecipe> event)
{
ItemStack filledBucket = FluidUtil.getFilledBucket(new FluidStack(ModelFluidTest.FLUID, Fluid.BUCKET_VOLUME));
ItemStack filledBucket = FluidUtil.getFilledBucket(new FluidStack(ModelFluidTest.FLUID, FluidAttributes.BUCKET_VOLUME));
GameRegistry.addShapelessRecipe(new ResourceLocation(MODID, "diamond_to_fluid"), null, filledBucket, Ingredient.fromItem(Items.DIAMOND));
}
@ -162,7 +162,7 @@ public class DynBucketTest
if (state.getBlock() instanceof IFluidBlock)
{
Fluid fluid = ((IFluidBlock) state.getBlock()).getFluid();
FluidStack fs = new FluidStack(fluid, Fluid.BUCKET_VOLUME);
FluidStack fs = new FluidStack(fluid, FluidAttributes.BUCKET_VOLUME);
ItemStack bucket = event.getEmptyBucket();
IFluidHandlerItem fluidHandler = FluidUtil.getFluidHandler(bucket);
@ -331,7 +331,7 @@ public class DynBucketTest
public static class TileSimpleTank extends TileEntity
{
FluidTank tank = new FluidTank(4000);
FluidTankOld tank = new FluidTankOld(4000);
@Override
public void readFromNBT(NBTTagCompound tags)

View File

@ -213,7 +213,7 @@ public class FluidPlacementTest
@Override
public int fill(FluidStack resource, boolean doFill)
{
if (container.getCount() != 1 || resource == null || resource.amount > Fluid.BUCKET_VOLUME || container
if (container.getCount() != 1 || resource == null || resource.amount > FluidAttributes.BUCKET_VOLUME || container
.getItem() instanceof ItemBucketMilk || getFluid() != null || !canFillFluidType(resource))
{
return 0;

View File

@ -0,0 +1,206 @@
package net.minecraftforge.debug.fluid;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.block.material.Material;
import net.minecraft.fluid.FlowingFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.BucketItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.item.Items;
import net.minecraft.state.StateContainer;
import net.minecraft.tags.FluidTags;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.BlockRenderLayer;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IEnviromentBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ObjectHolder;
@Mod("new_fluid_test")
public class NewFluidTest
{
public static final ResourceLocation FLUID_STILL = new ResourceLocation("minecraft:block/brown_mushroom_block");
public static final ResourceLocation FLUID_FLOWING = new ResourceLocation("minecraft:block/mushroom_stem");
@ObjectHolder("forge:test_fluid")
public static FlowingFluid test_fluid;
@ObjectHolder("forge:test_fluid_flowing")
public static Fluid test_fluid_flowing;
@ObjectHolder("forge:test_fluid_bucket")
public static Item test_fluid_bucket;
@ObjectHolder("forge:test_fluid_block")
public static Block test_fluid_block;
public NewFluidTest()
{
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();
modEventBus.addGenericListener(Block.class, this::registerBlocks);
modEventBus.addGenericListener(Item.class, this::registerItems);
modEventBus.addGenericListener(Fluid.class, this::registerFluids);
}
public void registerBlocks(RegistryEvent.Register<Block> event)
{
(test_fluid = new MyFlowingFluid.Source()).setRegistryName("forge:test_fluid");
test_fluid_flowing = new MyFlowingFluid.Flowing().setRegistryName("forge:test_fluid_flowing");
event.getRegistry().registerAll(
new FlowingFluidBlock(test_fluid, Block.Properties.create(Material.WATER).doesNotBlockMovement().hardnessAndResistance(100.0F).noDrops())
{}
.setRegistryName("forge:test_fluid_block")
);
}
public void registerItems(RegistryEvent.Register<Item> event)
{
event.getRegistry().registerAll(
new BucketItem(test_fluid, new Item.Properties().containerItem(Items.BUCKET).maxStackSize(1).group(ItemGroup.MISC)).setRegistryName("forge:test_fluid_bucket")
);
}
public void registerFluids(RegistryEvent.Register<Fluid> event)
{
event.getRegistry().registerAll(test_fluid, test_fluid_flowing);
}
private static final FluidAttributes ATTRIBUTES = FluidAttributes.builder("test_fluid", FLUID_STILL, FLUID_FLOWING).build();
private static abstract class MyFlowingFluid extends FlowingFluid
{
@Override
public Fluid getFlowingFluid()
{
return test_fluid_flowing;
}
@Override
public Fluid getStillFluid()
{
return test_fluid;
}
@Override
protected boolean canSourcesMultiply()
{
return false;
}
@Override
protected void beforeReplacingBlock(IWorld worldIn, BlockPos pos, BlockState state)
{
// copied from the WaterFluid implementation
TileEntity tileentity = state.getBlock().hasTileEntity() ? worldIn.getTileEntity(pos) : null;
Block.spawnDrops(state, worldIn.getWorld(), pos, tileentity);
}
@Override
protected int getSlopeFindDistance(IWorldReader worldIn)
{
return 4;
}
@Override
protected int getLevelDecreasePerBlock(IWorldReader worldIn)
{
return 1;
}
@Override
public BlockRenderLayer getRenderLayer()
{
return BlockRenderLayer.TRANSLUCENT;
}
@Override
public Item getFilledBucket()
{
return test_fluid_bucket;
}
@Override
protected boolean func_215665_a(IFluidState p_215665_1_, IBlockReader p_215665_2_, BlockPos p_215665_3_, Fluid p_215665_4_, Direction p_215665_5_)
{
return p_215665_5_ == Direction.DOWN && !p_215665_4_.isIn(FluidTags.WATER);
}
@Override
public int getTickRate(IWorldReader p_205569_1_)
{
return 5;
}
@Override
protected float getExplosionResistance()
{
return 1;
}
@Override
protected BlockState getBlockState(IFluidState state)
{
return test_fluid_block.getDefaultState().with(FlowingFluidBlock.LEVEL, getLevelFromState(state));
}
@Override
public boolean isEquivalentTo(Fluid fluidIn) {
return fluidIn == test_fluid || fluidIn == test_fluid_flowing;
}
@Override
public FluidAttributes createAttributes(Fluid fluid)
{
return ATTRIBUTES;
}
public static class Flowing extends MyFlowingFluid
{
{
setDefaultState(getStateContainer().getBaseState().with(LEVEL_1_8, 7));
}
protected void fillStateContainer(StateContainer.Builder<Fluid, IFluidState> builder) {
super.fillStateContainer(builder);
builder.add(LEVEL_1_8);
}
public int getLevel(IFluidState p_207192_1_) {
return p_207192_1_.get(LEVEL_1_8);
}
public boolean isSource(IFluidState state) {
return false;
}
}
public static class Source extends MyFlowingFluid {
public int getLevel(IFluidState p_207192_1_) {
return 8;
}
public boolean isSource(IFluidState state) {
return true;
}
}
}
}

View File

@ -43,6 +43,8 @@ loaderVersion="[28,)"
modId="command_event_test"
[[mods]]
modId="entity_selector_test"
[[mods]]
modId="new_fluid_test"
[[mods]]
modId="data_gen_test"
[[mods]]