tutorial:fluids
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:fluids [2019/09/24 10:46] – fluid implementation alexiy | tutorial:fluids [2023/05/04 11:22] – [Making an abstract fluid] solidblock | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== Creating a fluid ====== | ====== Creating a fluid ====== | ||
+ | |||
===== Overview ===== | ===== Overview ===== | ||
Here we'll cover creation of a custom fluid. If you plan to create several fluids, it is recommended to make an abstract basic fluid class where you'll set necessary defaults that will be shared in its subclasses. We'll also make it generate in the world like lakes. | Here we'll cover creation of a custom fluid. If you plan to create several fluids, it is recommended to make an abstract basic fluid class where you'll set necessary defaults that will be shared in its subclasses. We'll also make it generate in the world like lakes. | ||
+ | |||
===== Making an abstract fluid ===== | ===== Making an abstract fluid ===== | ||
- | Vanilla fluids extend | + | Vanilla fluids extend |
- | <code java> | + | <yarncode |
- | public abstract class BasicFluid | + | public abstract class TutorialFluid |
- | { | + | /** |
- | /** | + | * @return |
- | | + | */ |
- | | + | @Override |
- | @Override | + | public |
- | | + | return |
- | | + | } |
- | return | + | |
- | } | + | |
- | | + | /** |
- | @Override | + | * @return whether the fluid is infinite (which means can be infinitely created like water). In vanilla, |
- | protected | + | */ |
- | | + | @Override |
- | return | + | protected |
- | } | + | return |
+ | } | ||
- | | + | /** |
- | | + | * Perform actions when the fluid flows into a replaceable block. Water drops |
- | | + | * the block' |
- | | + | */ |
- | @Override | + | @Override |
- | | + | 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; | ||
+ | class_2248.method_9610(state, | ||
+ | } | ||
- | | + | /** |
- | | + | * Lava returns true if it's FluidState is above a certain height and the |
- | | + | * Fluid is Water. |
- | | + | * |
- | @Override | + | * @return |
- | protected | + | */ |
+ | @Override | ||
+ | protected | ||
+ | return false; | ||
+ | } | ||
- | | + | /** |
- | | + | * Possibly related to the distance checks for flowing into nearby holes? |
- | | + | * Water returns 4. Lava returns 2 in the Overworld and 4 in the Nether. |
- | | + | */ |
- | @Override | + | @Override |
- | | + | protected int method_15733(class_4538 worldView) { |
+ | return 4; | ||
+ | } | ||
- | | + | /** |
- | | + | * Water returns 1. Lava returns 2 in the Overworld and 1 in the Nether. |
- | * @return still static instance of this fluid | + | */ |
- | */ | + | @Override |
- | @Override | + | protected int method_15739(class_4538 worldView) { |
- | | + | return 1; |
+ | } | ||
- | | + | /** |
- | @Override | + | * Water returns 5. Lava returns 30 in the Overworld and 10 in the Nether. |
- | | + | */ |
- | | + | @Override |
- | return | + | public |
- | } | + | return |
+ | } | ||
- | | + | /** |
- | | + | * Water and Lava both return |
- | * @return | + | */ |
- | | + | @Override |
- | @Override | + | protected float method_15784() { |
- | | + | return |
- | | + | } |
- | return | + | } |
- | } | + | </ |
- | @Override | + | ===== Implementation ===== |
- | | + | 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. |
- | { | + | |
- | return 100; | + | |
- | } | + | |
- | // this seems to determine fluid' | + | < |
- | @Override | + | public abstract class AcidFluid extends TutorialFluid { |
- | | + | @Override |
- | | + | public class_3611 method_15751() { |
- | return | + | return |
- | } | + | } |
- | // I don't know what this does, but it's present in the water fluid | + | @Override |
- | | + | public class_3611 method_15750() { |
- | | + | return YOUR_FLOWING_FLUID_HERE; |
- | | + | } |
- | Block.dropStacks(blockState_1, | + | |
- | } | + | |
- | // also don't know what it does | + | @Override |
- | public | + | public |
- | return | + | return |
- | } | + | } |
- | /** | + | @Override |
- | * | + | protected class_2680 method_15790(class_3610 fluidState) { |
- | * @return is given fluid instance of this fluid? | + | return YOUR_FLUID_BLOCK_HERE.method_9564().method_11657(class_2741.field_12538, |
- | */ | + | } |
- | | + | |
- | | + | |
- | /** | + | public static class Flowing extends AcidFluid { |
- | * Required for entities to behave in this fluid like in water | + | @Override |
- | */ | + | protected void method_15775(class_2689.class_2690<class_3611, class_3610> builder) { |
- | @Override | + | super.method_15775(builder); |
- | | + | builder.method_11667(field_15900); |
- | | + | } |
- | | + | |
- | } | + | |
- | } | + | |
- | </ | + | |
- | ===== Implementation ===== | + | @Override |
- | Now let's make an actual fluid; it will have a //still// and //flowing// variants; will name it " | + | public int method_15779(class_3610 fluidState) { |
+ | return fluidState.method_11654(field_15900); | ||
+ | } | ||
- | <code java> | + | @Override |
- | public abstract class Acid extends BasicFluid | + | public |
- | { | + | return |
- | | + | } |
- | public | + | } |
- | | + | |
- | return | + | |
- | } | + | |
- | | + | |
- | protected BlockState toBlockState(FluidState var1) | + | |
- | { | + | |
- | return null; | + | |
- | | + | |
- | | + | public static class Still extends AcidFluid { |
- | public | + | @Override |
- | | + | public |
- | return | + | return |
- | } | + | } |
- | | + | @Override |
- | public | + | public |
- | | + | return |
- | return | + | } |
- | } | + | } |
+ | } | ||
+ | </ | ||
- | @Override | + | Next, we'll make static instances of still and flowing acid variants, and an acid bucket. In your '' |
- | public boolean matchesType(Fluid fluid_1) | + | |
- | { | + | |
- | return false; | + | |
- | } | + | |
- | // still acid | + | < |
- | public static | + | public static |
- | { | + | public static class_3609 FLOWING_ACID; |
+ | public static class_1792 ACID_BUCKET; | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() | ||
+ | STILL_ACID = class_2378.method_10230(class_7923.field_41173, | ||
+ | FLOWING_ACID = class_2378.method_10230(class_7923.field_41173, | ||
+ | ACID_BUCKET = class_2378.method_10230(class_7923.field_41178, | ||
+ | new class_1755(STILL_ACID, | ||
+ | |||
+ | // ... | ||
+ | } | ||
+ | |||
+ | // ... | ||
+ | </ | ||
- | @Override | + | To make a custom fluid behave more like water or lava, you must add it to a corresponding fluid tag: For water, make a '' |
- | | + | <code json [enable_line_numbers=" |
- | { | + | { |
- | | + | " |
- | } | + | " |
+ | [ | ||
+ | " | ||
+ | " | ||
+ | ] | ||
+ | } | ||
+ | </ | ||
- | /** | + | ===== Making a fluid block ===== |
- | * @return height of the fluid block | + | Next we need to create a block which will represent acid in the world. ''< |
- | */ | + | |
- | @Override | + | |
- | public int getLevel(FluidState fluidState) | + | |
- | { | + | |
- | return 8; | + | |
- | } | + | |
- | } | + | |
- | // flowing acid | + | < |
- | public static | + | public static |
- | { | + | |
- | | + | @Override |
- | public | + | public |
- | | + | ACID = class_2378.method_10230(class_7923.field_41175, |
- | | + | |
- | } | + | // ... |
+ | } | ||
+ | </ | ||
- | /** | + | Now that we have these static objects, we can go back to '' |
- | * @return height of the fluid block | + | |
- | */ | + | |
- | @Override | + | |
- | public int getLevel(FluidState fluidState) | + | |
- | { | + | |
- | return fluidState.get(LEVEL); | + | |
- | } | + | |
- | | + | < |
- | | + | public abstract class AcidFluid extends TutorialFluid { |
- | | + | @Override |
- | super.appendProperties(stateFactory$Builder_1); | + | public class_3611 method_15751() { |
- | | + | return TutorialMod.STILL_ACID; |
- | } | + | } |
- | } | + | |
- | } | + | @Override |
- | </code> | + | public class_3611 method_15750() { |
+ | return TutorialMod.FLOWING_ACID; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public class_1792 method_15774() { | ||
+ | return TutorialMod.ACID_BUCKET; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | 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 | ||
+ | return TutorialMod.ACID.method_9564().method_11657(class_2741.field_12538, | ||
+ | } | ||
- | Next, we'll make static | + | public |
+ | @Override | ||
+ | protected void method_15775(class_2689.class_2690< | ||
+ | super.method_15775(builder); | ||
+ | builder.method_11667(field_15900); | ||
+ | } | ||
- | <code java> | + | @Override |
+ | public int method_15779(class_3610 fluidState) { | ||
+ | return fluidState.method_11654(field_15900); | ||
+ | } | ||
- | | + | @Override |
- | public | + | public |
- | | + | return false; |
- | + | } | |
- | | + | } |
- | | + | public static class Still extends AcidFluid { |
- | public | + | @Override |
- | | + | public |
- | + | return 8; | |
- | stillAcid = Registry.register(Registry.FLUID, | + | } |
- | | + | |
- | + | ||
- | acidBucket=new BucketItem(stillAcid, | + | |
- | Registry.register(Registry.ITEM, | + | |
- | | + | |
- | </ | + | |
- | ==== Making a fluid block ==== | + | @Override |
- | 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 for " | + | public boolean method_15793(class_3610 fluidState) { |
+ | return true; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
- | <code java> | + | ===== Rendering setup ===== |
- | public class BaseFluidBlock extends FluidBlock | + | For your fluids to have textures or be tinted with a color, you will need to register a '' |
- | { | + | |
- | public BaseFluidBlock(BaseFluid fluid, Settings settings) | + | |
- | { | + | |
- | super(fluid, settings); | + | |
- | } | + | |
- | } | + | |
- | </ | + | |
- | Now make a static block instance: | + | < |
+ | public class TutorialModClient implements ClientModInitializer { | ||
- | <code java> | + | @Override |
- | ... | + | public void onInitializeClient() { |
- | + | FluidRenderHandlerRegistry.INSTANCE.register(TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID, | |
- | | + | new class_2960(" |
+ | new class_2960(" | ||
+ | 0x4CC248 | ||
+ | )); | ||
- | @Override | + | BlockRenderLayerMap.INSTANCE.putFluids(class_1921.method_23583(), TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID); |
- | public void onInitialize() | + | |
- | { | + | |
- | + | ||
- | | + | |
- | + | ||
- | acid=new BaseFluidBlock(stillAcid, | + | |
- | Registry.register(Registry.BLOCK, | + | |
- | } | + | |
- | </ | + | |
- | Now when we have these static objects, we go back to **Acid** class and complete | + | //if you want to use custom textures they needs to be registered. |
+ | //In this example this is unnecessary because | ||
+ | //To register your custom textures use this method. | ||
+ | // | ||
+ | // registry.register(new Identifier(" | ||
+ | // registry.register(new Identifier(" | ||
+ | //}); | ||
- | <code java> | + | // ... |
- | public abstract class Acid extends BasicFluid | + | } |
- | { | + | } |
- | @Override | + | </ |
- | public Item getBucketItem() | + | |
- | { | + | |
- | return [ModInitializer].acidBucket; | + | |
- | } | + | |
- | + | ||
- | @Override | + | |
- | protected BlockState toBlockState(FluidState fluidState) | + | |
- | { | + | |
- | | + | |
- | | + | |
- | } | + | |
- | @Override | + | If you want to use your own fluid textures, you can refer to vanilla' |
- | public Fluid getFlowing() | + | |
- | { | + | |
- | return [ModInitializer].flowingAcid; | + | |
- | } | + | |
- | @Override | + | ===== Generation in the world ===== |
- | public Fluid getStill() | + | TODO Update to 1.19.4 |
- | { | + | |
- | return [ModInitializer].stillAcid; | + | |
- | } | + | |
- | + | ||
- | @Override | + | |
- | public boolean matchesType(Fluid fluid_1) | + | |
- | { | + | |
- | return fluid_1==[ModInitializer].flowingAcid || fluid_1==[ModInitializer].stillAcid; | + | |
- | } | + | |
- | | + | |
- | ... | + | |
- | + | ||
- | } | + | |
</ | </ | ||
- | |||
- | Now we can assert that the Acid class is complete. |
tutorial/fluids.txt · Last modified: 2023/05/04 11:31 by solidblock