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 --- a/net/minecraft/block/FlowingFluidBlock.java
+++ b/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) { if (flag) {
IFluidState ifluidstate = p_204515_1_.func_204610_c(p_204515_2_); IFluidState ifluidstate = p_204515_1_.func_204610_c(p_204515_2_);
if (ifluidstate.func_206889_d()) { if (ifluidstate.func_206889_d()) {
@ -16,3 +59,26 @@
this.func_180688_d(p_204515_1_, p_204515_2_); this.func_180688_d(p_204515_1_, p_204515_2_);
return false; 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 --- a/net/minecraft/client/renderer/FluidBlockRenderer.java
+++ b/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_) { 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); boolean flag = p_217638_4_.func_206884_a(FluidTags.field_206960_b);
- TextureAtlasSprite[] atextureatlassprite = flag ? this.field_178272_a : this.field_178271_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_); - 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_); + 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_); + 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 f = (float)(i >> 16 & 255) / 255.0F;
float f1 = (float)(i >> 8 & 255) / 255.0F; float f1 = (float)(i >> 8 & 255) / 255.0F;
float f2 = (float)(i & 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, IUnbakedModel> field_217851_H = Maps.newHashMap();
private final Map<ResourceLocation, IBakedModel> field_217852_I = Maps.newHashMap(); private final Map<ResourceLocation, IBakedModel> field_217852_I = Maps.newHashMap();
private final AtlasTexture.SheetData field_217853_J; private final AtlasTexture.SheetData field_217853_J;
@@ -142,6 +142,12 @@ @@ -142,12 +142,19 @@
p_i51735_4_.func_219895_b("special"); p_i51735_4_.func_219895_b("special");
this.func_217843_a(new ModelResourceLocation("minecraft:trident_in_hand#inventory")); this.func_217843_a(new ModelResourceLocation("minecraft:trident_in_hand#inventory"));
@ -22,7 +22,14 @@
p_i51735_4_.func_219895_b("textures"); p_i51735_4_.func_219895_b("textures");
Set<String> set = Sets.newLinkedHashSet(); Set<String> set = Sets.newLinkedHashSet();
Set<ResourceLocation> set1 = this.field_217851_H.values().stream().flatMap((p_217838_2_) -> { 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_) -> { 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()) { try (InputStream inputstream = p_217839_1_.func_199027_b()) {
@ -31,7 +38,7 @@
return pair2; return pair2;
} catch (Exception exception1) { } 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())); 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 @Nullable
public IBakedModel func_217845_a(ResourceLocation p_217845_1_, ISprite p_217845_2_) { public IBakedModel func_217845_a(ResourceLocation p_217845_1_, ISprite p_217845_2_) {
@ -45,7 +52,7 @@
if (this.field_217850_G.containsKey(triple)) { if (this.field_217850_G.containsKey(triple)) {
return this.field_217850_G.get(triple); return this.field_217850_G.get(triple);
} else { } else {
@@ -412,11 +423,11 @@ @@ -412,11 +424,11 @@
if (iunbakedmodel instanceof BlockModel) { if (iunbakedmodel instanceof BlockModel) {
BlockModel blockmodel = (BlockModel)iunbakedmodel; BlockModel blockmodel = (BlockModel)iunbakedmodel;
if (blockmodel.func_178310_f() == field_177606_o) { if (blockmodel.func_178310_f() == field_177606_o) {
@ -59,7 +66,7 @@
this.field_217850_G.put(triple, ibakedmodel); this.field_217850_G.put(triple, ibakedmodel);
return ibakedmodel; return ibakedmodel;
} }
@@ -471,6 +482,10 @@ @@ -471,6 +483,10 @@
return this.field_225367_M; return this.field_225367_M;
} }

View file

@ -9,7 +9,7 @@
public static final ObjectIntIdentityMap<IFluidState> field_207201_d = new ObjectIntIdentityMap<>(); public static final ObjectIntIdentityMap<IFluidState> field_207201_d = new ObjectIntIdentityMap<>();
protected final StateContainer<Fluid, IFluidState> field_207202_e; protected final StateContainer<Fluid, IFluidState> field_207202_e;
private IFluidState field_207200_b; 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_); 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. + * 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()} + * 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.common.ForgeHooks.createVanillaFluidAttributes(this);
+ 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.");
+ } + }
+ +
+ private net.minecraftforge.fluids.FluidAttributes forgeFluidAttributes; + private net.minecraftforge.fluids.FluidAttributes forgeFluidAttributes;
+ public final net.minecraftforge.fluids.FluidAttributes getAttributes() { + public final net.minecraftforge.fluids.FluidAttributes getAttributes() {
+ if (forgeFluidAttributes == null) + if (forgeFluidAttributes == null)
+ forgeFluidAttributes = createAttributes(this); + forgeFluidAttributes = createAttributes();
+ return forgeFluidAttributes; + return forgeFluidAttributes;
+ } + }
} }

View file

@ -1,6 +1,26 @@
--- a/net/minecraft/item/BucketItem.java --- a/net/minecraft/item/BucketItem.java
+++ b/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_) { 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_); 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); 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) { if (raytraceresult.func_216346_c() == RayTraceResult.Type.MISS) {
return new ActionResult<>(ActionResultType.PASS, itemstack); return new ActionResult<>(ActionResultType.PASS, itemstack);
} else if (raytraceresult.func_216346_c() != RayTraceResult.Type.BLOCK) { } 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); Fluid fluid = ((IBucketPickupHandler)blockstate1.func_177230_c()).func_204508_a(p_77659_1_, blockpos, blockstate1);
if (fluid != Fluids.field_204541_a) { if (fluid != Fluids.field_204541_a) {
p_77659_2_.func_71029_a(Stats.field_75929_E.func_199076_b(this)); 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); - 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; + 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); + 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()); ItemStack itemstack1 = this.func_150910_a(itemstack, p_77659_2_, fluid.func_204524_b());
if (!p_77659_1_.field_72995_K) { if (!p_77659_1_.field_72995_K) {
CriteriaTriggers.field_204813_j.func_204817_a((ServerPlayerEntity)p_77659_2_, new ItemStack(fluid.func_204524_b())); 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_) { 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 = 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; + 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); 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); + 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.SelectiveReloadStateHandler;
import net.minecraftforge.resource.VanillaResourceType; import net.minecraftforge.resource.VanillaResourceType;
import net.minecraftforge.versions.forge.ForgeVersion; import net.minecraftforge.versions.forge.ForgeVersion;
import net.minecraftforge.registries.ForgeRegistries;
public class ForgeHooksClient public class ForgeHooksClient
{ {
@ -380,9 +381,9 @@ public class ForgeHooksClient
} }
@SuppressWarnings("deprecation") @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.setIdentity();
m.setTranslation(TRSRTransformation.toVecmath(transform.translation)); m.setTranslation(TRSRTransformation.toVecmath(transform.translation));
t.setIdentity(); 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 class LightGatheringTransformer extends QuadGatheringTransformer {
private static final VertexFormat FORMAT = new VertexFormat().addElement(DefaultVertexFormats.TEX_2F).addElement(DefaultVertexFormats.TEX_2S); 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) 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 bufferbuilder = Tessellator.getInstance().getBuffer();
bufferbuilder.begin(GL11.GL_QUADS, DefaultVertexFormats.ITEM); bufferbuilder.begin(GL_QUADS, DefaultVertexFormats.ITEM);
float lastBl = GLX.lastBrightnessX; float lastBl = GLX.lastBrightnessX;
float lastSl = GLX.lastBrightnessY; float lastSl = GLX.lastBrightnessY;

View file

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

View file

@ -45,6 +45,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.minecraft.advancements.Advancement; import net.minecraft.advancements.Advancement;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.fluid.*;
import net.minecraft.util.CachedBlockInfo; import net.minecraft.util.CachedBlockInfo;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft; 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.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.fluid.IFluidState;
import net.minecraft.block.Blocks; import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluids;
import net.minecraft.inventory.container.RepairContainer; import net.minecraft.inventory.container.RepairContainer;
import net.minecraft.inventory.IInventory; import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item; 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.BlockEvent;
import net.minecraftforge.event.world.NoteBlockEvent; import net.minecraftforge.event.world.NoteBlockEvent;
import net.minecraftforge.eventbus.api.Event.Result; import net.minecraftforge.eventbus.api.Event.Result;
import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.registries.DataSerializerEntry; import net.minecraftforge.registries.DataSerializerEntry;
import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.ForgeRegistry;
@ -831,6 +831,30 @@ public class ForgeHooks
return ret; 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 private static class LootTableContext
{ {
public final ResourceLocation name; public final ResourceLocation name;

View file

@ -22,30 +22,25 @@ package net.minecraftforge.fluids;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks; import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState; import net.minecraft.fluid.IFluidState;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.particles.ParticleTypes; import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IEnviromentBlockReader; import net.minecraft.world.IEnviromentBlockReader;
import java.util.Locale; import java.util.function.BiFunction;
import java.util.function.Supplier; import java.util.function.Function;
import java.util.stream.Stream;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material; import net.minecraft.block.material.Material;
import net.minecraft.entity.player.PlayerEntity; 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.math.BlockPos;
import net.minecraft.util.text.translation.LanguageMap;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraft.item.Rarity; import net.minecraft.item.Rarity;
import net.minecraft.world.biome.BiomeColors;
/** /**
* Minecraft Forge Fluid Implementation * Minecraft Forge Fluid Implementation
@ -67,10 +62,6 @@ public class FluidAttributes
{ {
public static final int BUCKET_VOLUME = 1000; 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 String translationKey;
private final ResourceLocation stillTexture; private final ResourceLocation stillTexture;
@ -141,10 +132,9 @@ public class FluidAttributes
*/ */
private final int color; private final int color;
protected FluidAttributes(Builder builder) protected FluidAttributes(Builder builder, Fluid fluid)
{ {
this.fluidName = builder.name; this.translationKey = builder.translationKey != null ? builder.translationKey : Util.makeTranslationKey("fluid", fluid.getRegistryName());
this.translationKey = builder.translationKey;
this.stillTexture = builder.stillTexture; this.stillTexture = builder.stillTexture;
this.flowingTexture = builder.flowingTexture; this.flowingTexture = builder.flowingTexture;
this.overlayTexture = builder.overlayTexture; this.overlayTexture = builder.overlayTexture;
@ -159,11 +149,6 @@ public class FluidAttributes
this.rarity = builder.rarity; this.rarity = builder.rarity;
} }
public final String getName()
{
return this.fluidName;
}
public ItemStack getBucket(FluidStack stack) public ItemStack getBucket(FluidStack stack)
{ {
return new ItemStack(stack.getFluid().getFilledBucket()); 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) 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() public String getTranslationKey()
{ {
return "fluid." + this.translationKey; return this.translationKey;
} }
/* Default Accessors */ /* Default Accessors */
@ -343,17 +328,23 @@ public class FluidAttributes
public SoundEvent getFillSound(IEnviromentBlockReader world, BlockPos pos) { return getFillSound(); } public SoundEvent getFillSound(IEnviromentBlockReader world, BlockPos pos) { return getFillSound(); }
public SoundEvent getEmptySound(IEnviromentBlockReader world, BlockPos pos) { return getEmptySound(); } public SoundEvent getEmptySound(IEnviromentBlockReader world, BlockPos pos) { return getEmptySound(); }
public static Builder builder(String name, ResourceLocation stillTexture, ResourceLocation flowingTexture) { public static Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) {
return new Builder(name, stillTexture, 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 public static class Builder
{ {
private final String name;
private final ResourceLocation stillTexture; private final ResourceLocation stillTexture;
private final ResourceLocation flowingTexture; private final ResourceLocation flowingTexture;
private ResourceLocation overlayTexture; private ResourceLocation overlayTexture;
private int color = 0xFFFFFF; private int color = 0xFFFFFFFF;
private String translationKey; private String translationKey;
private SoundEvent fillSound; private SoundEvent fillSound;
private SoundEvent emptySound; private SoundEvent emptySound;
@ -363,12 +354,12 @@ public class FluidAttributes
private int viscosity = 1000; private int viscosity = 1000;
private boolean isGaseous; private boolean isGaseous;
private Rarity rarity = Rarity.COMMON; private Rarity rarity = Rarity.COMMON;
private BiFunction<Builder,Fluid,FluidAttributes> factory;
protected Builder(String name, ResourceLocation stillTexture, ResourceLocation flowingTexture) { protected Builder(ResourceLocation stillTexture, ResourceLocation flowingTexture, BiFunction<Builder,Fluid,FluidAttributes> factory) {
this.name = name.toLowerCase(Locale.ENGLISH); this.factory = factory;
this.stillTexture = stillTexture; this.stillTexture = stillTexture;
this.flowingTexture = flowingTexture; this.flowingTexture = flowingTexture;
this.translationKey = "fluid." + this.name + ".name";
} }
public final Builder translationKey(String translationKey) public final Builder translationKey(String translationKey)
@ -383,12 +374,6 @@ public class FluidAttributes
return this; return this;
} }
public final Builder vanillaColor()
{
this.color = -1;
return this;
}
public final Builder overlay(ResourceLocation texture) public final Builder overlay(ResourceLocation texture)
{ {
overlayTexture = texture; overlayTexture = texture;
@ -444,9 +429,27 @@ public class FluidAttributes
return this; 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() { protected void updateEmpty() {
isEmpty = getRawFluid() == Fluids.EMPTY || amount == 0; isEmpty = getRawFluid() == Fluids.EMPTY || amount <= 0;
} }
public int getAmount() 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; package net.minecraftforge.fluids.capability;
import net.minecraft.item.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.INBT; import net.minecraft.item.Items;
import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.common.capabilities.CapabilityInject;
@ -39,7 +39,7 @@ public class CapabilityFluidHandler
@CapabilityInject(IFluidHandlerItem.class) @CapabilityInject(IFluidHandlerItem.class)
public static Capability<IFluidHandlerItem> FLUID_HANDLER_ITEM_CAPABILITY = null; 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(FluidAttributes.BUCKET_VOLUME)); CapabilityManager.INSTANCE.register(IFluidHandler.class, new DefaultFluidHandlerStorage<>(), () -> new FluidTank(FluidAttributes.BUCKET_VOLUME));
@ -48,27 +48,27 @@ public class CapabilityFluidHandler
private static class DefaultFluidHandlerStorage<T extends IFluidHandler> implements Capability.IStorage<T> { private static class DefaultFluidHandlerStorage<T extends IFluidHandler> implements Capability.IStorage<T> {
@Override @Override
public INBT writeNBT(Capability<T> capability, T instance, Direction side) public INBT writeNBT(Capability<T> capability, T instance, Direction side)
{ {
if (!(instance instanceof FluidTank)) if (!(instance instanceof FluidTank))
throw new RuntimeException("Cannot serialize to an instance that isn't the default implementation"); throw new RuntimeException("Cannot serialize to an instance that isn't the default implementation");
CompoundNBT nbt = new CompoundNBT(); CompoundNBT nbt = new CompoundNBT();
FluidTank tank = (FluidTank) instance; FluidTank tank = (FluidTank) instance;
FluidStack fluid = tank.getFluid(); FluidStack fluid = tank.getFluid();
fluid.writeToNBT(nbt); fluid.writeToNBT(nbt);
nbt.putInt("Capacity", tank.getCapacity()); nbt.putInt("Capacity", tank.getCapacity());
return nbt; return nbt;
} }
@Override @Override
public void readNBT(Capability<T> capability, T instance, Direction side, INBT nbt) public void readNBT(Capability<T> capability, T instance, Direction side, INBT nbt)
{ {
if (!(instance instanceof FluidTank)) if (!(instance instanceof FluidTank))
throw new RuntimeException("Cannot deserialize to an instance that isn't the default implementation"); throw new RuntimeException("Cannot deserialize to an instance that isn't the default implementation");
CompoundNBT tags = (CompoundNBT) nbt; CompoundNBT tags = (CompoundNBT) nbt;
FluidTank tank = (FluidTank) instance; FluidTank tank = (FluidTank) instance;
tank.setCapacity(tags.getInt("Capacity")); tank.setCapacity(tags.getInt("Capacity"));
tank.readFromNBT(tags); tank.readFromNBT(tags);
} }
} }
} }

View file

@ -65,7 +65,7 @@ public interface IFluidHandler
* </p> * </p>
* *
* @param tank Tank to query. * @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 @Nonnull
FluidStack getFluidInTank(int tank); FluidStack getFluidInTank(int tank);

View file

@ -35,7 +35,7 @@ import java.util.stream.Stream;
import javax.annotation.Nullable; 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; private final ResourceLocation name;
@Nullable @Nullable

View file

@ -21,6 +21,8 @@ package net.minecraftforge.registries;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import java.util.function.Supplier;
/** /**
* A registry delegate for holding references to items or blocks * 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 * @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 * 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 * 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')) asmapi.redirectFieldToMethod(classNode, fn, asmapi.mapMethod('func_188419_a'))
return classNode; 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.FlowingFluid;
import net.minecraft.fluid.Fluid; import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids; import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.inventory.container.ContainerType;
import net.minecraft.item.*; 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.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.eventbus.api.IEventBus;
import net.minecraftforge.fluids.FluidAttributes; import net.minecraftforge.fluids.FluidAttributes;
import net.minecraftforge.fluids.FluidStack; 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.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; 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; import org.apache.commons.lang3.Validate;
@Mod("new_fluid_test") @Mod(NewFluidTest.MODID)
public class NewFluidTest 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_STILL = new ResourceLocation("minecraft:block/brown_mushroom_block");
public static final ResourceLocation FLUID_FLOWING = new ResourceLocation("minecraft:block/mushroom_stem"); public static final ResourceLocation FLUID_FLOWING = new ResourceLocation("minecraft:block/mushroom_stem");
@ObjectHolder("forge:test_fluid") public static final DeferredRegister<Block> BLOCKS = new DeferredRegister<>(ForgeRegistries.BLOCKS, MODID);
public static FlowingFluid test_fluid; 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 RegistryObject<FlowingFluid> test_fluid = FLUIDS.register("test_fluid", () ->
public static Fluid test_fluid_flowing; 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 RegistryObject<FlowingFluidBlock> test_fluid_block = BLOCKS.register("test_fluid_block", () ->
public static Item test_fluid_bucket; 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 final ForgeFlowingFluid.Properties test_fluid_properties =
public static Block test_fluid_block; 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() public NewFluidTest()
{ {
IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); 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); modEventBus.addListener(this::loadComplete);
}
public void registerBlocks(RegistryEvent.Register<Block> event) BLOCKS.register(modEventBus);
{ ITEMS.register(modEventBus);
(test_fluid = new MyFlowingFluid.Source()).setRegistryName("forge:test_fluid"); FLUIDS.register(modEventBus);
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);
} }
public void loadComplete(FMLLoadCompleteEvent event) public void loadComplete(FMLLoadCompleteEvent event)
@ -113,124 +91,4 @@ public class NewFluidTest
ItemStack stack = Fluids.WATER.getAttributes().getBucket(new FluidStack(Fluids.WATER, 1)); ItemStack stack = Fluids.WATER.getAttributes().getBucket(new FluidStack(Fluids.WATER, 1));
Validate.isTrue(stack.getItem() == Fluids.WATER.getFilledBucket()); 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;
}
}
}
} }