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 09:38] – example of abstract fluid class alexiy | tutorial:fluids [2022/08/17 22:38] – Fixed small typos clomclem | ||
---|---|---|---|
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> | + | < |
- | public abstract class BasicFluid | + | public abstract class TutorialFluid extends class_3609 { |
+ | /** | ||
+ | * @return whether the given fluid an instance of this fluid | ||
+ | */ | ||
+ | @Override | ||
+ | public boolean method_15780(class_3611 fluid) { | ||
+ | return fluid == method_15751() || fluid == method_15750(); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @return whether the fluid is infinite like water | ||
+ | */ | ||
+ | @Override | ||
+ | protected boolean method_15737() { | ||
+ | return false; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Perform actions when the fluid flows into a replaceable block. Water drops | ||
+ | * the block' | ||
+ | */ | ||
+ | @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 | ||
+ | * Fluid is Water. | ||
+ | * | ||
+ | * @return whether the given Fluid can flow into this FluidState | ||
+ | */ | ||
+ | @Override | ||
+ | protected boolean method_15777(class_3610 fluidState, class_1922 blockView, class_2338 blockPos, class_3611 fluid, class_2350 direction) { | ||
+ | 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 | ||
+ | protected int method_15733(class_4538 worldView) { | ||
+ | return 4; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Water returns 1. Lava returns 2 in the Overworld and 1 in the Nether. | ||
+ | */ | ||
+ | @Override | ||
+ | protected int method_15739(class_4538 worldView) { | ||
+ | return 1; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Water returns 5. Lava returns 30 in the Overworld and 10 in the Nether. | ||
+ | */ | ||
+ | @Override | ||
+ | public int method_15789(class_4538 worldView) { | ||
+ | return 5; | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * Water and Lava both return 100.0F. | ||
+ | */ | ||
+ | @Override | ||
+ | protected float method_15784() { | ||
+ | return 100.0F; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | ===== 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. | ||
+ | |||
+ | < | ||
+ | public abstract class AcidFluid | ||
+ | @Override | ||
+ | public class_3611 method_15751() { | ||
+ | return YOUR_STILL_FLUID_HERE; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public class_3611 method_15750() { | ||
+ | return YOUR_FLOWING_FLUID_HERE; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public class_1792 method_15774() { | ||
+ | return YOUR_BUCKET_ITEM_HERE; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | protected class_2680 method_15790(class_3610 fluidState) { | ||
+ | return YOUR_FLUID_BLOCK_HERE.method_9564().method_11657(class_2741.field_12538, | ||
+ | } | ||
+ | |||
+ | public static class Flowing extends AcidFluid { | ||
+ | @Override | ||
+ | protected void method_15775(class_2689.class_2690< | ||
+ | super.method_15775(builder); | ||
+ | builder.method_11667(field_15900); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int method_15779(class_3610 fluidState) { | ||
+ | return fluidState.method_11654(field_15900); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean method_15793(class_3610 fluidState) { | ||
+ | return false; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | public static class Still extends AcidFluid { | ||
+ | @Override | ||
+ | public int method_15779(class_3610 fluidState) { | ||
+ | return 8; | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public boolean method_15793(class_3610 fluidState) { | ||
+ | return true; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Next, we'll make static instances of still and flowing acid variants, and an acid bucket. In your '' | ||
+ | |||
+ | < | ||
+ | public static class_3609 STILL_ACID; | ||
+ | public static class_3609 FLOWING_ACID; | ||
+ | public static class_1792 ACID_BUCKET; | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | STILL_ACID = class_2378.method_10230(class_2378.field_11154, | ||
+ | FLOWING_ACID = class_2378.method_10230(class_2378.field_11154, | ||
+ | ACID_BUCKET = class_2378.method_10230(class_2378.field_11142, | ||
+ | new class_1755(STILL_ACID, | ||
+ | |||
+ | // ... | ||
+ | } | ||
+ | |||
+ | // ... | ||
+ | </ | ||
+ | |||
+ | 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=" | ||
{ | { | ||
- | | + | " |
- | * @return | + | " |
- | */ | + | [ |
- | @Override | + | " |
- | protected | + | " |
- | { | + | ] |
- | return | + | } |
- | } | + | </code> |
+ | |||
+ | ===== Making a fluid block ===== | ||
+ | Next we need to create a block which will represent acid in the world. ''< | ||
+ | |||
+ | < | ||
+ | public static class_2248 ACID; | ||
+ | |||
+ | @Override | ||
+ | public void onInitialize() { | ||
+ | ACID = class_2378.method_10230(class_2378.field_11146, | ||
+ | |||
+ | // ... | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now that we have these static objects, we can go back to '' | ||
+ | |||
+ | < | ||
+ | public abstract class AcidFluid extends TutorialFluid { | ||
+ | @Override | ||
+ | public class_3611 method_15751() { | ||
+ | return | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | 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, | ||
+ | } | ||
+ | |||
+ | public static class Flowing extends AcidFluid { | ||
+ | @Override | ||
+ | protected | ||
+ | super.method_15775(builder); | ||
+ | builder.method_11667(field_15900); | ||
+ | } | ||
+ | |||
+ | @Override | ||
+ | public int method_15779(class_3610 fluidState) | ||
+ | return | ||
+ | } | ||
- | // make it transparent | + | @Override |
- | | + | public boolean method_15793(class_3610 fluidState) { |
- | | + | return |
- | | + | } |
- | return | + | } |
- | } | + | |
- | /** | + | public static class Still extends AcidFluid { |
- | * | + | @Override |
- | * @return an associated item that " | + | public |
- | */ | + | return 8; |
- | | + | } |
- | public | + | |
- | /** | + | @Override |
- | * | + | public boolean method_15793(class_3610 fluidState) { |
- | * @return | + | return |
- | */ | + | } |
- | @Override | + | } |
- | protected abstract BlockState toBlockState(FluidState var1); | + | } |
+ | </yarncode> | ||
- | /** | + | ===== Rendering setup ===== |
- | * | + | For your fluids to have textures or be tinted with a color, you will need to register a '' |
- | * @return flowing static instance of this fluid | + | |
- | */ | + | |
- | @Override | + | |
- | public abstract Fluid getFlowing(); | + | |
- | /** | + | < |
- | * | + | public |
- | * @return still static instance of this fluid | + | |
- | */ | + | |
- | @Override | + | |
- | | + | |
- | // how much does the height of the fluid block decreases | + | @Override |
- | | + | public void onInitializeClient() { |
- | | + | FluidRenderHandlerRegistry.INSTANCE.register(TutorialMod.STILL_ACID, |
- | | + | new class_2960(" |
- | | + | new class_2960(" |
- | } | + | 0x4CC248 |
+ | )); | ||
- | /** | + | BlockRenderLayerMap.INSTANCE.putFluids(class_1921.method_23583(), |
- | * | + | |
- | * @return update rate | + | |
- | */ | + | |
- | @Override | + | |
- | public int getTickRate(ViewableWorld var1) | + | |
- | { | + | |
- | return 5; | + | |
- | } | + | |
- | @Override | + | //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. |
- | | + | // |
- | } | + | // registry.register(new Identifier(" |
+ | // registry.register(new Identifier(" | ||
+ | //}); | ||
- | | + | // ... |
- | | + | } |
- | | + | } |
- | { | + | </ |
- | return 4; | + | |
- | | + | |
- | | + | If you want to use your own fluid textures, you can refer to vanilla' |
- | @Override | + | |
- | protected void beforeBreakingBlock(IWorld iWorld_1, BlockPos blockPos_1, BlockState blockState_1) { | + | |
- | BlockEntity blockEntity_1 = blockState_1.getBlock().hasBlockEntity() ? iWorld_1.getBlockEntity(blockPos_1) : null; | + | |
- | Block.dropStacks(blockState_1, | + | |
- | } | + | |
- | // also don't know what it does | + | ===== Generation in the world ===== |
- | public boolean method_15777(FluidState fluidState_1, | + | To make lakes of acid generate in the world, you can create a ''< |
- | return direction_1 | + | |
- | } | + | |
- | /** | + | <code java [enable_line_numbers=" |
- | * | + | public |
- | * @return is given fluid instance of this fluid? | + | |
- | */ | + | |
- | @Override | + | |
- | | + | |
- | /** | + | @Override |
- | * Required for entities to behave in this fluid like in water | + | public |
- | */ | + | ACID_LAKE |
- | | + | |
- | public | + | // 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))) | ||
+ | ); | ||
} | } | ||
</ | </ | ||
tutorial/fluids.txt · Last modified: 2023/05/04 11:31 by solidblock