Some (sadly breaking) improvements to the Fluid API (#6110)

* Some (sadly breaking) improvements to the API, after feedback and concerns provided by users:
  - Moved calculation of the translation key to the FluidAttributes constructor, so that builders can be shared between still & flowing sub-fluids.
  - Moved biome-based coloring to a dedicated FluidAttributes.Water variant, which is not used by default.
  - Added logic to automatically gather fluid textures into the list of textures to bake.
  - Patched BucketItem and FlowingFluidBlock to avoid eager access to the fluid objects.
  - Added a ForgeFlowingFluid class, as a more user-friendly way to construct a new FlowingFluid.
This commit is contained in:
David Quintana 2019-09-11 16:00:32 +02:00 committed by GitHub
parent 281ef5a152
commit b0c9d7cce9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 537 additions and 277 deletions

View file

@ -1,6 +1,49 @@
--- a/net/minecraft/block/FlowingFluidBlock.java
+++ b/net/minecraft/block/FlowingFluidBlock.java
@@ -121,13 +121,13 @@
@@ -30,9 +30,11 @@
public class FlowingFluidBlock extends Block implements IBucketPickupHandler {
public static final IntegerProperty field_176367_b = BlockStateProperties.field_208132_ag;
- protected final FlowingFluid field_204517_c;
+ private final FlowingFluid field_204517_c;
private final List<IFluidState> field_212565_c;
+ // Forge: Use the constructor that takes a supplier
+ @Deprecated
protected FlowingFluidBlock(FlowingFluid p_i49014_1_, Block.Properties p_i49014_2_) {
super(p_i49014_2_);
this.field_204517_c = p_i49014_1_;
@@ -45,8 +47,21 @@
this.field_212565_c.add(p_i49014_1_.func_207207_a(8, true));
this.func_180632_j(this.field_176227_L.func_177621_b().func_206870_a(field_176367_b, Integer.valueOf(0)));
+ fluidStateCacheInitialized = true;
+ supplier = p_i49014_1_.delegate;
}
+ /**
+ * @param supplier A fluid supplier such as {@link net.minecraftforge.fml.RegistryObject<Fluid>}
+ */
+ public FlowingFluidBlock(java.util.function.Supplier<? extends FlowingFluid> supplier, Block.Properties p_i48368_1_) {
+ super(p_i48368_1_);
+ this.field_204517_c = null;
+ this.field_212565_c = Lists.newArrayList();
+ this.func_180632_j(this.field_176227_L.func_177621_b().func_206870_a(field_176367_b, Integer.valueOf(0)));
+ this.supplier = supplier;
+ }
+
public void func_196265_a(BlockState p_196265_1_, World p_196265_2_, BlockPos p_196265_3_, Random p_196265_4_) {
p_196265_2_.func_204610_c(p_196265_3_).func_206891_b(p_196265_2_, p_196265_3_, p_196265_4_);
}
@@ -61,6 +76,7 @@
public IFluidState func_204507_t(BlockState p_204507_1_) {
int i = p_204507_1_.func_177229_b(field_176367_b);
+ if (!fluidStateCacheInitialized) initFluidStateCache();
return this.field_212565_c.get(Math.min(i, 8));
}
@@ -121,13 +137,13 @@
if (flag) {
IFluidState ifluidstate = p_204515_1_.func_204610_c(p_204515_2_);
if (ifluidstate.func_206889_d()) {
@ -16,3 +59,26 @@
this.func_180688_d(p_204515_1_, p_204515_2_);
return false;
}
@@ -160,4 +176,22 @@
}
}
+
+ // Forge start
+ private final java.util.function.Supplier<? extends Fluid> supplier;
+ public FlowingFluid getFluid() {
+ return (FlowingFluid)supplier.get();
+ }
+
+ private boolean fluidStateCacheInitialized;
+ protected void initFluidStateCache() {
+ this.field_212565_c.add(getFluid().func_207204_a(false));
+
+ for(int i = 1; i < 8; ++i) {
+ this.field_212565_c.add(getFluid().func_207207_a(8 - i, false));
+ }
+
+ this.field_212565_c.add(getFluid().func_207207_a(8, true));
+ fluidStateCacheInitialized = true;
+ }
}

View file

@ -1,15 +1,13 @@
--- a/net/minecraft/client/renderer/FluidBlockRenderer.java
+++ b/net/minecraft/client/renderer/FluidBlockRenderer.java
@@ -58,8 +58,10 @@
@@ -58,8 +58,8 @@
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 @@
private final Map<ResourceLocation, IUnbakedModel> field_217851_H = Maps.newHashMap();
private final Map<ResourceLocation, IBakedModel> field_217852_I = Maps.newHashMap();
private final AtlasTexture.SheetData field_217853_J;
@@ -142,6 +142,12 @@
@@ -142,12 +142,19 @@
p_i51735_4_.func_219895_b("special");
this.func_217843_a(new ModelResourceLocation("minecraft:trident_in_hand#inventory"));
@ -22,7 +22,14 @@
p_i51735_4_.func_219895_b("textures");
Set<String> set = Sets.newLinkedHashSet();
Set<ResourceLocation> set1 = this.field_217851_H.values().stream().flatMap((p_217838_2_) -> {
@@ -288,7 +294,7 @@
return p_217838_2_.func_209559_a(this::func_209597_a, set).stream();
}).collect(Collectors.toSet());
set1.addAll(field_177602_b);
+ net.minecraftforge.client.ForgeHooksClient.gatherFluidTextures(set1);
set.forEach((p_217833_0_) -> {
field_177603_c.warn("Unable to resolve texture reference: {}", (Object)p_217833_0_);
});
@@ -288,7 +295,7 @@
{
lvt_13_5_ = this.field_177598_f.func_199004_b(resourcelocation1).stream().map((p_217839_1_) -> {
try (InputStream inputstream = p_217839_1_.func_199027_b()) {
@ -31,7 +38,7 @@
return pair2;
} catch (Exception exception1) {
throw new ModelBakery.BlockStateDefinitionException(String.format("Exception loading blockstate definition: '%s' in resourcepack: '%s': %s", p_217839_1_.func_199029_a(), p_217839_1_.func_199026_d(), exception1.getMessage()));
@@ -404,7 +410,12 @@
@@ -404,7 +411,12 @@
@Nullable
public IBakedModel func_217845_a(ResourceLocation p_217845_1_, ISprite p_217845_2_) {
@ -45,7 +52,7 @@
if (this.field_217850_G.containsKey(triple)) {
return this.field_217850_G.get(triple);
} else {
@@ -412,11 +423,11 @@
@@ -412,11 +424,11 @@
if (iunbakedmodel instanceof BlockModel) {
BlockModel blockmodel = (BlockModel)iunbakedmodel;
if (blockmodel.func_178310_f() == field_177606_o) {
@ -59,7 +66,7 @@
this.field_217850_G.put(triple, ibakedmodel);
return ibakedmodel;
}
@@ -471,6 +482,10 @@
@@ -471,6 +483,10 @@
return this.field_225367_M;
}

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,40 @@
@@ -102,4 +102,26 @@
}
public abstract VoxelShape func_215664_b(IFluidState p_215664_1_, IBlockReader p_215664_2_, BlockPos p_215664_3_);
@ -24,29 +24,15 @@
+ * 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)
+ protected net.minecraftforge.fluids.FluidAttributes createAttributes()
+ {
+ 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().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"))
+ .vanillaColor().luminosity(15).density(3000).viscosity(6000).temperature(1300).build();
+ throw new RuntimeException("Mod fluids must override createAttributes.");
+ return net.minecraftforge.common.ForgeHooks.createVanillaFluidAttributes(this);
+ }
+
+ private net.minecraftforge.fluids.FluidAttributes forgeFluidAttributes;
+ public final net.minecraftforge.fluids.FluidAttributes getAttributes() {
+ if (forgeFluidAttributes == null)
+ forgeFluidAttributes = createAttributes(this);
+ forgeFluidAttributes = createAttributes();
+ return forgeFluidAttributes;
+ }
}

View file

@ -1,6 +1,26 @@
--- a/net/minecraft/item/BucketItem.java
+++ b/net/minecraft/item/BucketItem.java
@@ -38,6 +38,8 @@
@@ -30,14 +30,28 @@
public class BucketItem extends Item {
private final Fluid field_77876_a;
+ // Forge: Use the other constructor that takes a Supplier
+ @Deprecated
public BucketItem(Fluid p_i49025_1_, Item.Properties p_i49025_2_) {
super(p_i49025_2_);
this.field_77876_a = p_i49025_1_;
+ this.fluidSupplier = p_i49025_1_.delegate;
}
+ /**
+ * @param supplier A fluid supplier such as {@link net.minecraftforge.fml.RegistryObject<Fluid>}
+ */
+ public BucketItem(java.util.function.Supplier<? extends Fluid> supplier, Item.Properties builder) {
+ super(builder);
+ this.field_77876_a = null;
+ this.fluidSupplier = supplier;
+ }
+
public ActionResult<ItemStack> func_77659_a(World p_77659_1_, PlayerEntity p_77659_2_, Hand p_77659_3_) {
ItemStack itemstack = p_77659_2_.func_184586_b(p_77659_3_);
RayTraceResult raytraceresult = func_219968_a(p_77659_1_, p_77659_2_, this.field_77876_a == Fluids.field_204541_a ? RayTraceContext.FluidMode.SOURCE_ONLY : RayTraceContext.FluidMode.NONE);
@ -9,24 +29,24 @@
if (raytraceresult.func_216346_c() == RayTraceResult.Type.MISS) {
return new ActionResult<>(ActionResultType.PASS, itemstack);
} else if (raytraceresult.func_216346_c() != RayTraceResult.Type.BLOCK) {
@@ -52,7 +54,10 @@
@@ -52,7 +66,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();
+ SoundEvent soundevent = this.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 @@
@@ -147,7 +164,19 @@
}
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();
+ SoundEvent soundevent = this.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);
}
@ -39,5 +59,6 @@
+ return super.initCapabilities(stack, nbt);
+ }
+
+ public Fluid getFluid() { return field_77876_a; }
+ private final java.util.function.Supplier<? extends Fluid> fluidSupplier;
+ public Fluid getFluid() { return fluidSupplier.get(); }
}

View file

@ -146,6 +146,7 @@ import net.minecraftforge.resource.ReloadRequirements;
import net.minecraftforge.resource.SelectiveReloadStateHandler;
import net.minecraftforge.resource.VanillaResourceType;
import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.registries.ForgeRegistries;
public class ForgeHooksClient
{
@ -380,9 +381,9 @@ public class ForgeHooksClient
}
@SuppressWarnings("deprecation")
public static Matrix4f getMatrix(net.minecraft.client.renderer.model.ItemTransformVec3f transform)
public static Matrix4f getMatrix(ItemTransformVec3f transform)
{
javax.vecmath.Matrix4f m = new javax.vecmath.Matrix4f(), t = new javax.vecmath.Matrix4f();
Matrix4f m = new Matrix4f(), t = new Matrix4f();
m.setIdentity();
m.setTranslation(TRSRTransformation.toVecmath(transform.translation));
t.setIdentity();
@ -569,6 +570,13 @@ public class ForgeHooksClient
};
}
public static void gatherFluidTextures(Set<ResourceLocation> textures)
{
ForgeRegistries.FLUIDS.getValues().stream()
.flatMap(f -> f.getAttributes().getTextures())
.forEach(textures::add);
}
private static class LightGatheringTransformer extends QuadGatheringTransformer {
private static final VertexFormat FORMAT = new VertexFormat().addElement(DefaultVertexFormats.TEX_2F).addElement(DefaultVertexFormats.TEX_2S);
@ -702,7 +710,7 @@ public class ForgeHooksClient
private static void drawSegment(ItemRenderer ri, int baseColor, ItemStack stack, List<BakedQuad> segment, int bl, int sl, boolean shade, boolean updateLighting, boolean updateShading)
{
BufferBuilder bufferbuilder = Tessellator.getInstance().getBuffer();
bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM);
bufferbuilder.begin(GL_QUADS, DefaultVertexFormats.ITEM);
float lastBl = GLX.lastBrightnessX;
float lastSl = GLX.lastBrightnessY;

View file

@ -442,7 +442,7 @@ public final class ModelDynBucket implements IUnbakedModel
BakedDynBucket model = (BakedDynBucket)originalModel;
Fluid fluid = fluidStack.getFluid();
String name = fluid.getAttributes().getName();
String name = fluid.getRegistryName().toString();
if (!model.cache.containsKey(name))
{

View file

@ -45,6 +45,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import net.minecraft.advancements.Advancement;
import net.minecraft.block.Block;
import net.minecraft.fluid.*;
import net.minecraft.util.CachedBlockInfo;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
@ -59,9 +60,7 @@ import net.minecraft.entity.item.minecart.ContainerMinecartEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.fluid.IFluidState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluids;
import net.minecraft.inventory.container.RepairContainer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
@ -141,6 +140,7 @@ import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.event.world.NoteBlockEvent;
import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.registries.DataSerializerEntry;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry;
@ -831,6 +831,30 @@ public class ForgeHooks
return ret;
}
public static FluidAttributes createVanillaFluidAttributes(Fluid fluid)
{
if (fluid instanceof EmptyFluid)
return net.minecraftforge.fluids.FluidAttributes.builder(
new net.minecraft.util.ResourceLocation("white"),
new net.minecraft.util.ResourceLocation("white"))
.translationKey("block.minecraft.air")
.color(0).density(0).temperature(0).luminosity(0).viscosity(0).build(fluid);
if (fluid instanceof WaterFluid)
return net.minecraftforge.fluids.FluidAttributes.Water.builder(
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"))
.translationKey("block.minecraft.water")
.color(0x3F76E4).build(fluid);
if (fluid instanceof LavaFluid)
return net.minecraftforge.fluids.FluidAttributes.builder(
new net.minecraft.util.ResourceLocation("block/lava_still"),
new net.minecraft.util.ResourceLocation("block/lava_flow"))
.translationKey("block.minecraft.lava")
.luminosity(15).density(3000).viscosity(6000).temperature(1300).build(fluid);
throw new RuntimeException("Mod fluids must override createAttributes.");
}
private static class LootTableContext
{
public final ResourceLocation name;

View file

@ -22,30 +22,25 @@ package net.minecraftforge.fluids;
import javax.annotation.Nullable;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.*;
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 java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Stream;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.SoundEvents;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.translation.LanguageMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import net.minecraft.item.Rarity;
import net.minecraft.world.biome.BiomeColors;
/**
* Minecraft Forge Fluid Implementation
@ -67,10 +62,6 @@ public class FluidAttributes
{
public static final int BUCKET_VOLUME = 1000;
/** The unique identification name for this fluid. */
private final String fluidName;
/** The translation key of this fluid. */
private String translationKey;
private final ResourceLocation stillTexture;
@ -141,10 +132,9 @@ public class FluidAttributes
*/
private final int color;
protected FluidAttributes(Builder builder)
protected FluidAttributes(Builder builder, Fluid fluid)
{
this.fluidName = builder.name;
this.translationKey = builder.translationKey;
this.translationKey = builder.translationKey != null ? builder.translationKey : Util.makeTranslationKey("fluid", fluid.getRegistryName());
this.stillTexture = builder.stillTexture;
this.flowingTexture = builder.flowingTexture;
this.overlayTexture = builder.overlayTexture;
@ -159,11 +149,6 @@ public class FluidAttributes
this.rarity = builder.rarity;
}
public final String getName()
{
return this.fluidName;
}
public ItemStack getBucket(FluidStack stack)
{
return new ItemStack(stack.getFluid().getFilledBucket());
@ -240,7 +225,7 @@ public class FluidAttributes
}
/**
* A FluidStack sensitive version of getUnlocalizedName
* A FluidStack sensitive version of getTranslationKey
*/
public String getTranslationKey(FluidStack stack)
{
@ -248,11 +233,11 @@ public class FluidAttributes
}
/**
* Returns the unlocalized name of this fluid.
* Returns the translation key of this fluid.
*/
public String getTranslationKey()
{
return "fluid." + this.translationKey;
return this.translationKey;
}
/* Default Accessors */
@ -343,17 +328,23 @@ public class FluidAttributes
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 Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) {
return new Builder(stillTexture, flowingTexture, FluidAttributes::new);
}
public Stream<ResourceLocation> getTextures()
{
if (overlayTexture != null)
return Stream.of(stillTexture, flowingTexture, overlayTexture);
return Stream.of(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 int color = 0xFFFFFFFF;
private String translationKey;
private SoundEvent fillSound;
private SoundEvent emptySound;
@ -363,12 +354,12 @@ public class FluidAttributes
private int viscosity = 1000;
private boolean isGaseous;
private Rarity rarity = Rarity.COMMON;
private BiFunction<Builder,Fluid,FluidAttributes> factory;
protected Builder(String name, ResourceLocation stillTexture, ResourceLocation flowingTexture) {
this.name = name.toLowerCase(Locale.ENGLISH);
protected Builder(ResourceLocation stillTexture, ResourceLocation flowingTexture, BiFunction<Builder,Fluid,FluidAttributes> factory) {
this.factory = factory;
this.stillTexture = stillTexture;
this.flowingTexture = flowingTexture;
this.translationKey = "fluid." + this.name + ".name";
}
public final Builder translationKey(String translationKey)
@ -383,12 +374,6 @@ public class FluidAttributes
return this;
}
public final Builder vanillaColor()
{
this.color = -1;
return this;
}
public final Builder overlay(ResourceLocation texture)
{
overlayTexture = texture;
@ -444,9 +429,27 @@ public class FluidAttributes
return this;
}
public FluidAttributes build()
public FluidAttributes build(Fluid fluid)
{
return new FluidAttributes(this);
return factory.apply(this, fluid);
}
}
public static class Water extends FluidAttributes
{
protected Water(Builder builder, Fluid fluid)
{
super(builder, fluid);
}
@Override
public int getColor(IEnviromentBlockReader world, BlockPos pos)
{
return BiomeColors.getWaterColor(world, pos);
}
public static Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) {
return new Builder(stillTexture, flowingTexture, Water::new);
}
}
}

View file

@ -161,7 +161,7 @@ public class FluidStack
}
protected void updateEmpty() {
isEmpty = getRawFluid() == Fluids.EMPTY || amount == 0;
isEmpty = getRawFluid() == Fluids.EMPTY || amount <= 0;
}
public int getAmount()

View file

@ -0,0 +1,263 @@
/*
* 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.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.fluid.FlowingFluid;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item;
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.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import javax.annotation.Nullable;
import java.util.function.Supplier;
public abstract class ForgeFlowingFluid extends FlowingFluid
{
private final Supplier<? extends Fluid> flowing;
private final Supplier<? extends Fluid> still;
@Nullable
private final Supplier<? extends Item> bucket;
@Nullable
private final Supplier<? extends FlowingFluidBlock> block;
private final FluidAttributes.Builder builder;
private final boolean canMultiply;
private final int slopeFindDistance;
private final int levelDecreasePerBlock;
private final float explosionResistance;
private final BlockRenderLayer renderLayer;
private final int tickRate;
protected ForgeFlowingFluid(Properties properties)
{
this.flowing = properties.flowing;
this.still = properties.still;
this.builder = properties.attributes;
this.canMultiply = properties.canMultiply;
this.bucket = properties.bucket;
this.block = properties.block;
this.slopeFindDistance = properties.slopeFindDistance;
this.levelDecreasePerBlock = properties.levelDecreasePerBlock;
this.explosionResistance = properties.explosionResistance;
this.renderLayer = properties.renderLayer;
this.tickRate = properties.tickRate;
}
@Override
public Fluid getFlowingFluid()
{
return flowing.get();
}
@Override
public Fluid getStillFluid()
{
return still.get();
}
@Override
protected boolean canSourcesMultiply()
{
return canMultiply;
}
@Override
protected void beforeReplacingBlock(IWorld worldIn, BlockPos pos, BlockState state)
{
TileEntity tileentity = state.getBlock().hasTileEntity() ? worldIn.getTileEntity(pos) : null;
Block.spawnDrops(state, worldIn.getWorld(), pos, tileentity);
}
@Override
protected int getSlopeFindDistance(IWorldReader worldIn)
{
return slopeFindDistance;
}
@Override
protected int getLevelDecreasePerBlock(IWorldReader worldIn)
{
return levelDecreasePerBlock;
}
@Override
public BlockRenderLayer getRenderLayer()
{
return renderLayer;
}
@Override
public Item getFilledBucket()
{
return bucket != null ? bucket.get() : Items.AIR;
}
@Override
protected boolean func_215665_a(IFluidState state, IBlockReader world, BlockPos pos, Fluid fluidIn, Direction direction)
{
// Based on the water implementation, may need to be overriden for mod fluids that shouldn't behave like water.
return direction == Direction.DOWN && !isEquivalentTo(fluidIn);
}
@Override
public int getTickRate(IWorldReader world)
{
return tickRate;
}
@Override
protected float getExplosionResistance()
{
return explosionResistance;
}
@Override
protected BlockState getBlockState(IFluidState state)
{
if (block != null)
return block.get().getDefaultState().with(FlowingFluidBlock.LEVEL, getLevelFromState(state));
return Blocks.AIR.getDefaultState();
}
@Override
public boolean isEquivalentTo(Fluid fluidIn) {
return fluidIn == still.get() || fluidIn == flowing.get();
}
@Override
protected FluidAttributes createAttributes()
{
return builder.build(this);
}
public static class Flowing extends ForgeFlowingFluid
{
public Flowing(Properties properties)
{
super(properties);
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 state) {
return state.get(LEVEL_1_8);
}
public boolean isSource(IFluidState state) {
return false;
}
}
public static class Source extends ForgeFlowingFluid
{
public Source(Properties properties)
{
super(properties);
}
public int getLevel(IFluidState state) {
return 8;
}
public boolean isSource(IFluidState state) {
return true;
}
}
public static class Properties
{
private Supplier<? extends Fluid> still;
private Supplier<? extends Fluid> flowing;
private FluidAttributes.Builder attributes;
private boolean canMultiply;
private Supplier<? extends Item> bucket;
private Supplier<? extends FlowingFluidBlock> block;
private int slopeFindDistance = 4;
private int levelDecreasePerBlock = 1;
private float explosionResistance = 1;
private BlockRenderLayer renderLayer = BlockRenderLayer.TRANSLUCENT;
private int tickRate = 5;
public Properties(Supplier<? extends Fluid> still, Supplier<? extends Fluid> flowing, FluidAttributes.Builder attributes)
{
this.still = still;
this.flowing = flowing;
this.attributes = attributes;
}
public Properties canMultiply()
{
canMultiply = true;
return this;
}
public Properties bucket(Supplier<? extends Item> bucket)
{
this.bucket = bucket;
return this;
}
public Properties block(Supplier<? extends FlowingFluidBlock> block)
{
this.block = block;
return this;
}
public Properties slopeFindDistance(int slopeFindDistance)
{
this.slopeFindDistance = slopeFindDistance;
return this;
}
public Properties levelDecreasePerBlock(int levelDecreasePerBlock)
{
this.levelDecreasePerBlock = levelDecreasePerBlock;
return this;
}
public Properties explosionResistance(float explosionResistance)
{
this.explosionResistance = explosionResistance;
return this;
}
public Properties renderLayer(BlockRenderLayer layer)
{
this.renderLayer = layer;
return this;
}
}
}

View file

@ -19,10 +19,10 @@
package net.minecraftforge.fluids.capability;
import net.minecraft.item.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.INBT;
import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;

View file

@ -65,7 +65,7 @@ public interface IFluidHandler
* </p>
*
* @param tank Tank to query.
* @return FluidStack in a given tank. NULL if the tank is empty.
* @return FluidStack in a given tank. FluidStack.EMPTY if the tank is empty.
*/
@Nonnull
FluidStack getFluidInTank(int tank);

View file

@ -35,7 +35,7 @@ import java.util.stream.Stream;
import javax.annotation.Nullable;
public final class RegistryObject<T extends IForgeRegistryEntry<? super T>>
public final class RegistryObject<T extends IForgeRegistryEntry<? super T>> implements Supplier<T>
{
private final ResourceLocation name;
@Nullable

View file

@ -21,6 +21,8 @@ package net.minecraftforge.registries;
import net.minecraft.util.ResourceLocation;
import java.util.function.Supplier;
/**
* A registry delegate for holding references to items or blocks
@ -31,7 +33,7 @@ import net.minecraft.util.ResourceLocation;
*
* @param <T> the type of thing we're holding onto
*/
public interface IRegistryDelegate<T> {
public interface IRegistryDelegate<T> extends Supplier<T> {
/**
* Get the referent pointed at by this delegate. This will be the currently active item or block, and will change
* as world saves come and go. Note that item.delegate.get() may NOT be the same object as item, due to item and

View file

@ -11,6 +11,30 @@ function initializeCoreMod() {
asmapi.redirectFieldToMethod(classNode, fn, asmapi.mapMethod('func_188419_a'))
return classNode;
}
},
'flowingfluidblock': {
'target': {
'type': 'CLASS',
'name': 'net.minecraft.block.FlowingFluidBlock'
},
'transformer': function(classNode) {
var asmapi=Java.type('net.minecraftforge.coremod.api.ASMAPI')
var fn = asmapi.mapField('field_204517_c') // fluid field - remap to mcp if necessary
asmapi.redirectFieldToMethod(classNode, fn, 'getFluid') // forge added method, doesn't need mapping
return classNode;
}
},
'bucketitem': {
'target': {
'type': 'CLASS',
'name': 'net.minecraft.item.BucketItem'
},
'transformer': function(classNode) {
var asmapi=Java.type('net.minecraftforge.coremod.api.ASMAPI')
var fn = asmapi.mapField('field_77876_a') // containerFluid (wrongly named containedBlock) field - remap to mcp if necessary
asmapi.redirectFieldToMethod(classNode, fn, 'getFluid') // forge added method, doesn't need mapping
return classNode;
}
}
}
}

View file

@ -27,81 +27,59 @@ 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.*;
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.fluids.FluidStack;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fluids.ForgeFlowingFluid;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.registries.ObjectHolder;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import org.apache.commons.lang3.Validate;
@Mod("new_fluid_test")
@Mod(NewFluidTest.MODID)
public class NewFluidTest
{
public static final String MODID = "new_fluid_test";
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;
public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID);
public static final DeferredRegister<Item> ITEMS = new DeferredRegister<>(ForgeRegistries.ITEMS, MODID);
public static final DeferredRegister<Fluid> FLUIDS = new DeferredRegister<>(ForgeRegistries.FLUIDS, MODID);
@ObjectHolder("forge:test_fluid_flowing")
public static Fluid test_fluid_flowing;
public static RegistryObject<FlowingFluid> test_fluid = FLUIDS.register("test_fluid", () ->
new ForgeFlowingFluid.Source(NewFluidTest.test_fluid_properties)
);
public static RegistryObject<FlowingFluid> test_fluid_flowing = FLUIDS.register("test_fluid_flowing", () ->
new ForgeFlowingFluid.Flowing(NewFluidTest.test_fluid_properties)
);
@ObjectHolder("forge:test_fluid_bucket")
public static Item test_fluid_bucket;
public static RegistryObject<FlowingFluidBlock> test_fluid_block = BLOCKS.register("test_fluid_block", () ->
new FlowingFluidBlock(test_fluid, Block.Properties.create(Material.WATER).doesNotBlockMovement().hardnessAndResistance(100.0F).noDrops())
);
public static RegistryObject<Item> test_fluid_bucket = ITEMS.register("test_fluid_bucket", () ->
new BucketItem(test_fluid, new Item.Properties().containerItem(Items.BUCKET).maxStackSize(1).group(ItemGroup.MISC))
);
@ObjectHolder("forge:test_fluid_block")
public static Block test_fluid_block;
public static final ForgeFlowingFluid.Properties test_fluid_properties =
new ForgeFlowingFluid.Properties(test_fluid, test_fluid_flowing, FluidAttributes.builder(FLUID_STILL, FLUID_FLOWING).color(0x1080FF))
.bucket(test_fluid_bucket).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);
modEventBus.addListener(this::loadComplete);
}
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);
BLOCKS.register(modEventBus);
ITEMS.register(modEventBus);
FLUIDS.register(modEventBus);
}
public void loadComplete(FMLLoadCompleteEvent event)
@ -113,124 +91,4 @@ public class NewFluidTest
ItemStack stack = Fluids.WATER.getAttributes().getBucket(new FluidStack(Fluids.WATER, 1));
Validate.isTrue(stack.getItem() == Fluids.WATER.getFilledBucket());
}
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
protected 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;
}
}
}
}