User Tools

Site Tools


tutorial:fluids

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
tutorial:fluids [2020/02/22 02:15] – Mappings + minor fixes earthcomputertutorial:fluids [2023/05/04 11:31] (current) – [Rendering setup] solidblock
Line 5: Line 5:
  
 ===== Making an abstract fluid ===== ===== Making an abstract fluid =====
-Vanilla fluids extend ''net.minecraft.fluid.BaseFluid'', and so shall we. +Vanilla fluids extend ''<yarn net.minecraft.class_3609>'', and so shall we. 
-<code java [enable_line_numbers="true"]> +<yarncode java [enable_line_numbers="true"]> 
-public abstract class TutorialFluid extends BaseFluid +public abstract class TutorialFluid extends class_3609 {
-{+
  /**  /**
- * @return is the given fluid an instance of this fluid?+ * @return whether the given fluid an instance of this fluid
  */  */
  @Override  @Override
- public boolean matchesType(Fluid fluid) + public boolean method_15780(class_3611 fluid) { 
- + return fluid == method_15751() || fluid == method_15750();
- return fluid == getStill() || fluid == getFlowing();+
  }  }
- +
  /**  /**
- * @return is the fluid infinite like water?+ * @return whether the fluid is infinite (which means can be infinitely created like water). In vanilla, it depends on the game rule.
  */  */
  @Override  @Override
- protected boolean isInfinite() + protected boolean method_15737() {
- {+
  return false;  return false;
  }  }
- +
  /**  /**
- * Perform actions when fluid flows into a replaceable block. Water drops+ * Perform actions when the fluid flows into a replaceable block. Water drops
  * the block's loot table. Lava plays the "block.lava.extinguish" sound.  * the block's loot table. Lava plays the "block.lava.extinguish" sound.
  */  */
  @Override  @Override
- protected void beforeBreakingBlock(IWorld world, BlockPos pos, BlockState state) + protected void method_15730(class_1936 world, class_2338 pos, class_2680 state) { 
- + final class_2586 blockEntity = state.method_31709() ? world.method_8321(pos) : null; 
- final BlockEntity blockEntity = state.getBlock().hasBlockEntity() ? world.getBlockEntity(pos) : null; + class_2248.method_9610(state, world, pos, blockEntity);
- Block.dropStacks(state, world.getWorld(), pos, blockEntity);+
  }  }
- +
  /**  /**
- * Lava returns true if its FluidState is above a certain height and the+ * Lava returns true if it'FluidState is above a certain height and the
  * Fluid is Water.  * Fluid is Water.
  
- * @return if the given Fluid can flow into this FluidState?+ * @return whether the given Fluid can flow into this FluidState
  */  */
  @Override  @Override
- protected boolean canBeReplacedWith(FluidState fluidState, BlockView blockView, BlockPos blockPos, Fluid fluid, Direction direction) + protected boolean method_15777(class_3610 fluidState, class_1922 blockView, class_2338 blockPos, class_3611 fluid, class_2350 direction) {
- {+
  return false;  return false;
  }  }
- +
  /**  /**
  * Possibly related to the distance checks for flowing into nearby holes?  * Possibly related to the distance checks for flowing into nearby holes?
Line 55: Line 50:
  */  */
  @Override  @Override
- protected int method_15733(WorldView worldView) + protected int method_15733(class_4538 worldView) {
- {+
  return 4;  return 4;
  }  }
- +
  /**  /**
  * Water returns 1. Lava returns 2 in the Overworld and 1 in the Nether.  * Water returns 1. Lava returns 2 in the Overworld and 1 in the Nether.
  */  */
  @Override  @Override
- protected int getLevelDecreasePerBlock(WorldView worldView) + protected int method_15739(class_4538 worldView) {
- {+
  return 1;  return 1;
  }  }
- +
  /**  /**
  * Water returns 5. Lava returns 30 in the Overworld and 10 in the Nether.  * Water returns 5. Lava returns 30 in the Overworld and 10 in the Nether.
  */  */
  @Override  @Override
- public int getTickRate(WorldView worldView) + public int method_15789(class_4538 worldView) {
- {+
  return 5;  return 5;
  }  }
- +
  /**  /**
  * Water and Lava both return 100.0F.  * Water and Lava both return 100.0F.
  */  */
  @Override  @Override
- protected float getBlastResistance() + protected float method_15784() {
- {+
  return 100.0F;  return 100.0F;
  }  }
 } }
-</code>+</yarncode>
  
 ===== Implementation ===== ===== Implementation =====
-Now let's make an actual fluid which'll have still and flowing variants. For this tutorial, we will call it Acid. The missing references will be filled in shortly.+Now let's make an actual fluid which will have still and flowing variants. For this tutorial, we will call it Acid. The missing references will be filled in shortly.
  
-<code java [enable_line_numbers="true"]> +<yarncode java [enable_line_numbers="true"]> 
-public abstract class AcidFluid extends TutorialFluid +public abstract class AcidFluid extends TutorialFluid {
-{+
  @Override  @Override
- public Fluid getStill() + public class_3611 method_15751() { 
- + return YOUR_STILL_FLUID_HERE;
- return <YOUR_STILL_FLUID_HERE>;+
  }  }
- +
  @Override  @Override
- public Fluid getFlowing() + public class_3611 method_15750() { 
- + return YOUR_FLOWING_FLUID_HERE;
- return <YOUR_FLOWING_FLUID_HERE>;+
  }  }
- +
  @Override  @Override
- public Item getBucketItem() + public class_1792 method_15774() { 
- + return YOUR_BUCKET_ITEM_HERE;
- return <YOUR_BUCKET_ITEM_HERE>;+
  }  }
- +
  @Override  @Override
- protected BlockState toBlockState(FluidState fluidState) + protected class_2680 method_15790(class_3610 fluidState) { 
- { + return YOUR_FLUID_BLOCK_HERE.method_9564().method_11657(class_2741.field_12538, method_15741(fluidState));
- // method_15741 converts the LEVEL_1_8 of the fluid state to the LEVEL_15 the fluid block uses +
- return <YOUR_FLUID_BLOCK_HERE>.getDefaultState().with(Properties.LEVEL_15, method_15741(fluidState));+
  }  }
-  + 
- public static class Flowing extends AcidFluid + public static class Flowing extends AcidFluid {
- {+
  @Override  @Override
- protected void appendProperties(StateManager.Builder<FluidFluidState> builder) + protected void method_15775(class_2689.class_2690<class_3611class_3610> builder) { 
- + super.method_15775(builder); 
- super.appendProperties(builder); + builder.method_11667(field_15900);
- builder.add(LEVEL);+
  }  }
- +
  @Override  @Override
- public int getLevel(FluidState fluidState) + public int method_15779(class_3610 fluidState) { 
- + return fluidState.method_11654(field_15900);
- return fluidState.get(LEVEL);+
  }  }
- +
  @Override  @Override
- public boolean isStill(FluidState fluidState) + public boolean method_15793(class_3610 fluidState) {
- {+
  return false;  return false;
  }  }
  }  }
-  + 
- public static class Still extends AcidFluid + public static class Still extends AcidFluid {
- {+
  @Override  @Override
- public int getLevel(FluidState fluidState) + public int method_15779(class_3610 fluidState) {
- {+
  return 8;  return 8;
  }  }
- +
  @Override  @Override
- public boolean isStill(FluidState fluidState) + public boolean method_15793(class_3610 fluidState) {
- {+
  return true;  return true;
  }  }
  }  }
 } }
-</code>+</yarncode>
  
 Next, we'll make static instances of still and flowing acid variants, and an acid bucket. In your ''ModInitializer'': Next, we'll make static instances of still and flowing acid variants, and an acid bucket. In your ''ModInitializer'':
  
-<code java [enable_line_numbers="true"]> +<yarncode java [enable_line_numbers="true"]> 
-// ... +public static class_3609 STILL_ACID; 
- +public static class_3609 FLOWING_ACID; 
-public static BaseFluid STILL_ACID; +public static class_1792 ACID_BUCKET; 
-public static BaseFluid FLOWING_ACID; + 
- +
-public static Item ACID_BUCKET; +
- +
-// ... +
 @Override @Override
-public void onInitialize() +public void onInitialize() { 
-{ + STILL_ACID = class_2378.method_10230(class_7923.field_41173, new class_2960("tutorial", "acid"), new AcidFluid.Still()); 
- // ... + FLOWING_ACID = class_2378.method_10230(class_7923.field_41173, new class_2960("tutorial", "flowing_acid"), new AcidFluid.Flowing()); 
-  + ACID_BUCKET = class_2378.method_10230(class_7923.field_41178, new class_2960("tutorial", "acid_bucket"),  
- STILL_ACID = Registry.register(Registry.FLUID, new Identifier(MOD_ID, "acid"), new AcidFluid.Still()); +        new class_1755(STILL_ACID, new class_1792.class_1793().method_7896(class_1802.field_8550).method_7889(1))); 
-  + 
- FLOWING_ACID = Registry.register(Registry.FLUID, new Identifier(MOD_ID, "flowing_acid"), new AcidFluid.Flowing()); +
-  +
- ACID_BUCKET = Registry.register(Registry.ITEM, new Identifier(MOD_ID, "acid_bucket"), new BucketItem(STILL_ACID, new Item.Settings().recipeRemainder(Items.BUCKET).maxCount(1))); +
- +
  // ...  // ...
 } }
 + 
 // ... // ...
-</code>+</yarncode>
  
 To make a custom fluid behave more like water or lava, you must add it to a corresponding fluid tag: For water, make a ''data/minecraft/tags/fluids/water.json'' file and write the identifiers of your fluids in there: To make a custom fluid behave more like water or lava, you must add it to a corresponding fluid tag: For water, make a ''data/minecraft/tags/fluids/water.json'' file and write the identifiers of your fluids in there:
Line 194: Line 163:
  "values":  "values":
  [  [
- "your_mod_id:acid", + "tutorial:acid", 
- "your_mod_id:flowing_acid"+ "tutorial:flowing_acid"
  ]  ]
 } }
Line 201: Line 170:
  
 ===== Making a fluid block ===== ===== Making a fluid block =====
-Next we need to create a block which will represent acid in the world. ''net.minecraft.block.FluidBlock'' is the class we need to use, but since its constructor is protected, we can't construct it directly. Some ways to use it are to make a subclass or an anonymous subclass. Here we will be showing the latter. In your ''ModInitializer'':+Next we need to create a block which will represent acid in the world. ''<yarn net.minecraft.class_2404>'' is the class we need to use, but since its constructor is protected, we can't construct it directly. Some ways to use it are to make a subclass or an anonymous subclass. Here we will be showing the latter. In your ''ModInitializer'':
  
-<code java [enable_line_numbers="true"]> +<yarncode java [enable_line_numbers="true"]> 
-// ... +public static class_2248 ACID;
- +
-public static Block ACID; +
- +
-// ...+
  
 @Override @Override
-public void onInitialize() +public void onInitialize() { 
-{ + ACID = class_2378.method_10230(class_7923.field_41175, new class_2960(MOD_ID, "acid"), new class_2404(STILL_ACID, FabricBlockSettings.method_9630(class_2246.field_10382)){});
- // ... +
-  +
- ACID = Registry.register(Registry.BLOCK, new Identifier(MOD_ID, "acid"), new FluidBlock(STILL_ACID, FabricBlockSettings.copy(Blocks.WATER).build()){});+
   
  // ...  // ...
-} +}  
- +</yarncode>
-// ...     +
-</code>+
  
 Now that we have these static objects, we can go back to ''AcidFluid'' and fill in the overridden methods: Now that we have these static objects, we can go back to ''AcidFluid'' and fill in the overridden methods:
  
-<code java [enable_line_numbers="true"]> +<yarncode java [enable_line_numbers="true"]> 
-public abstract class AcidFluid extends TutorialFluid +public abstract class AcidFluid extends TutorialFluid {
-{+
  @Override  @Override
- public Fluid getStill() + public class_3611 method_15751() {
- {+
  return TutorialMod.STILL_ACID;  return TutorialMod.STILL_ACID;
  }  }
- + 
  @Override  @Override
- public Fluid getFlowing() + public class_3611 method_15750() {
- {+
  return TutorialMod.FLOWING_ACID;  return TutorialMod.FLOWING_ACID;
  }  }
- + 
  @Override  @Override
- public Item getBucketItem() + public class_1792 method_15774() {
- {+
  return TutorialMod.ACID_BUCKET;  return TutorialMod.ACID_BUCKET;
  }  }
- + 
  @Override  @Override
- protected BlockState toBlockState(FluidState fluidState) + protected class_2680 method_15790(class_3610 fluidState) {
- {+
  // method_15741 converts the LEVEL_1_8 of the fluid state to the LEVEL_15 the fluid block uses  // method_15741 converts the LEVEL_1_8 of the fluid state to the LEVEL_15 the fluid block uses
- return TutorialMod.ACID.getDefaultState().with(Properties.LEVEL_15, method_15741(fluidState));+ return TutorialMod.ACID.method_9564().method_11657(class_2741.field_12538, method_15741(fluidState));
  }  }
-  
- // ... 
-}     
-</code> 
  
-===== Rendering setup ===== + public static class Flowing extends AcidFluid { 
-For your fluids to have textures or be tinted with a color, you will need to register a ''FluidRenderHandler'' for themHerewe will reuse water's textures and just change the tint color applied to themTo make sure the textures are rendered as translucent, you can use Fabric's ''BlockRenderLayerMap''.+ @Override 
 + protected void method_15775(class_2689.class_2690<class_3611class_3610> builder) { 
 + super.method_15775(builder); 
 + builder.method_11667(field_15900); 
 + }
  
-<code java [enable_line_numbers="true"]> + @Override 
-public class TutorialModClient implements ClientModInitializer + public int method_15779(class_3610 fluidState) { 
-+ return fluidState.method_11654(field_15900); 
- // ... +
-  + 
- @Override + @Override 
- public void onInitializeClient() + public boolean method_15793(class_3610 fluidState
- + return false
- // ..+ }
-  +
- setupFluidRendering(TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID, new Identifier("minecraft", "water"), 0x4CC248); +
- BlockRenderLayerMap.INSTANCE.putFluids(RenderLayer.getTranslucent(), TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID)+
-  +
- // ...+
  }  }
-  + 
- // ... + public static class Still extends AcidFluid 
-  + @Override 
- public static void setupFluidRendering(final Fluid still, final Fluid flowing, final Identifier textureFluidId, final int color) + public int method_15779(class_3610 fluidState{ 
- + return 8
- final Identifier stillSpriteId = new Identifier(textureFluidId.getNamespace(), "block/" + textureFluidId.getPath() + "_still"); +
- final Identifier flowingSpriteId = new Identifier(textureFluidId.getNamespace(), "block/" + textureFluidId.getPath() + "_flow"); + 
-  + @Override 
- // If they're not already present, add the sprites to the block atlas + public boolean method_15793(class_3610 fluidState) { 
- ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEX).register((atlasTexture, registry) -> + return true
-+ }
- registry.register(stillSpriteId); +
- registry.register(flowingSpriteId); +
- }); +
-  +
- final Identifier fluidId = Registry.FLUID.getId(still); +
- final Identifier listenerId = new Identifier(fluidId.getNamespace(), fluidId.getPath() + "_reload_listener"); +
-  +
- final Sprite[] fluidSprites = { null, null }; +
-  +
- ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener() +
-+
- @Override +
- public Identifier getFabricId() +
- +
- return listenerId; +
-+
-  +
- /** +
- * Get the sprites from the block atlas when resources are reloaded +
- */ +
- @Override +
- public void apply(ResourceManager resourceManager) +
-+
- final Function<Identifier, Sprite> atlas = MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEX); +
- fluidSprites[0] = atlas.apply(stillSpriteId); +
- fluidSprites[1] = atlas.apply(flowingSpriteId); +
- } +
- }); +
-  +
- // The FluidRenderer gets the sprites and color from a FluidRenderHandler during rendering +
- final FluidRenderHandler renderHandler = new FluidRenderHandler() +
-+
- @Override +
- public Sprite[] getFluidSprites(BlockRenderView view, BlockPos pos, FluidState state) +
- { +
- return fluidSprites; +
- +
-  +
- @Override +
- public int getFluidColor(BlockRenderView view, BlockPos pos, FluidState state) +
-+
- return color; +
- } +
- }+
-  +
- FluidRenderHandlerRegistry.INSTANCE.register(still, renderHandler); +
- FluidRenderHandlerRegistry.INSTANCE.register(flowing, renderHandler);+
  }  }
-  +  
- // ... +</yarncode>
-+
-</code>+
  
-If you want to use your own fluid textures, you can refer to vanilla's assets ((''assets/minecraft/blockstates/water.json''\\ ''assets/minecraft/models/block/water.json''\\ ''assets/minecraft/textures/block/water_still.png''\\ ''assets/minecraft/textures/block/water_still.png.mcmeta''\\ ''assets/minecraft/textures/block/water_flow.png''\\ ''assets/minecraft/textures/block/water_flow.png.mcmeta'')) as a template.+===== Rendering setup ===== 
 +For your fluids to have textures or be tinted with a color, you will need to register a ''FluidRenderHandler'' for themHere, we will reuse water'textures and just change the tint color applied to themTo make sure the textures are rendered as translucent, you can use Fabric'''BlockRenderLayerMap'' (see [[blockappearance]]).
  
-===== Generation in the world ===== +<yarncode java [enable_line_numbers="true"]> 
-To make lakes of acid generate in the world, you can create a ''net.minecraft.world.gen.feature.LakeFeature'' in your ''ModInitializer'' and then add it to the biomes you want it to generate in:+@Environment(EnvType.CLIENT) 
 +public class TutorialModClient implements ClientModInitializer {
  
-<code java [enable_line_numbers="true"]> + @Override 
-// ...+ public void onInitializeClient() { 
 + FluidRenderHandlerRegistry.INSTANCE.register(TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID, new SimpleFluidRenderHandler( 
 + new class_2960("minecraft:block/water_still"), 
 + new class_2960("minecraft:block/water_flow"), 
 + 0x4CC248 
 + ));
  
-public static LakeFeature ACID_LAKE;+ BlockRenderLayerMap.INSTANCE.putFluids(class_1921.method_23583(), TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID);
  
-// ...+ //if you want to use custom textures they needs to be registered. 
 + //In this example this is unnecessary because the vanilla water textures are already registered. 
 + //To register your custom textures use this method. 
 + //ClientSpriteRegistryCallback.event(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE).register((atlasTexture, registry) -> { 
 + //    registry.register(new Identifier("tutorial:block/custom_fluid_still")); 
 + //    registry.register(new Identifier("tutorial:block/custom_fluid_flowing")); 
 + //});
  
-@Override + // ... 
-public void onInitialize() + }
-+
- // ... +
-  +
- ACID_LAKE = Registry.register(Registry.FEATURE, new Identifier(MOD_ID, "acid_lake"), new LakeFeature(SingleStateFeatureConfig::deserialize)); +
-  +
- // generate in swamps, similar to water lakes, but with a chance of 40 (the higher the number, the lower the generation chance) +
- Biomes.SWAMP.addFeature( +
- GenerationStep.Feature.LOCAL_MODIFICATIONS, +
- ACID_LAKE.configure(new SingleStateFeatureConfig(ACID.getDefaultState())) +
- .createDecoratedFeature(Decorator.WATER_LAKE.configure(new ChanceDecoratorConfig(40))) +
- ); +
-  +
- // ...+
 } }
 +</yarncode>
  
-// ...+If you want to use your own fluid textures, you can refer to vanilla's assets ((''assets/minecraft/blockstates/water.json''\\ ''assets/minecraft/models/block/water.json''\\ ''assets/minecraft/textures/block/water_still.png''\\ ''assets/minecraft/textures/block/water_still.png.mcmeta''\\ ''assets/minecraft/textures/block/water_flow.png''\\ ''assets/minecraft/textures/block/water_flow.png.mcmeta'')) as a template. 
 + 
 +===== Generation in the world ===== 
 +TODO Update to 1.19.4
 </code> </code>
- 
tutorial/fluids.1582337756.txt.gz · Last modified: 2020/02/22 02:15 by earthcomputer