User Tools

Site Tools


zh_cn:tutorial:fluids

This is an old revision of the document!


创建流体

概述

在这里,我们将介绍自定义流体的创建。如果计划创建多个流体,建议创建一个抽象的基本流体类,在其中设置必要的默认值,这些默认值将在其子类中共享。我们还将使其像湖泊一样在世界中生成。

创建抽象流体

原版流体扩展了net.minecraft.fluid.FlowableFluid,我们也应如此。

  1. public abstract class TutorialFluid extends FlowableFluid
  2. {
  3. /**
  4. * @return is the given fluid an instance of this fluid?
  5. */
  6. @Override
  7. public boolean matchesType(Fluid fluid)
  8. {
  9. return fluid == getStill() || fluid == getFlowing();
  10. }
  11.  
  12. /**
  13. * @return is the fluid infinite like water?
  14. */
  15. @Override
  16. protected boolean isInfinite()
  17. {
  18. return false;
  19. }
  20.  
  21. /**
  22. * Perform actions when fluid flows into a replaceable block. Water drops
  23. * the block's loot table. Lava plays the "block.lava.extinguish" sound.
  24. */
  25. @Override
  26. protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state)
  27. {
  28. final BlockEntity blockEntity = state.getBlock().hasBlockEntity() ? world.getBlockEntity(pos) : null;
  29. Block.dropStacks(state, world, pos, blockEntity);
  30. }
  31.  
  32. /**
  33. * Lava returns true if its FluidState is above a certain height and the
  34. * Fluid is Water.
  35. *
  36. * @return if the given Fluid can flow into this FluidState?
  37. */
  38. @Override
  39. protected boolean canBeReplacedWith(FluidState fluidState, BlockView blockView, BlockPos blockPos, Fluid fluid, Direction direction)
  40. {
  41. return false;
  42. }
  43.  
  44. /**
  45. * Possibly related to the distance checks for flowing into nearby holes?
  46. * Water returns 4. Lava returns 2 in the Overworld and 4 in the Nether.
  47. */
  48. @Override
  49. protected int getFlowSpeed(WorldView worldView)
  50. {
  51. return 4;
  52. }
  53.  
  54. /**
  55. * Water returns 1. Lava returns 2 in the Overworld and 1 in the Nether.
  56. */
  57. @Override
  58. protected int getLevelDecreasePerBlock(WorldView worldView)
  59. {
  60. return 1;
  61. }
  62.  
  63. /**
  64. * Water returns 5. Lava returns 30 in the Overworld and 10 in the Nether.
  65. */
  66. @Override
  67. public int getTickRate(WorldView worldView)
  68. {
  69. return 5;
  70. }
  71.  
  72. /**
  73. * Water and Lava both return 100.0F.
  74. */
  75. @Override
  76. protected float getBlastResistance()
  77. {
  78. return 100.0F;
  79. }
  80. }

进行

现在让我们制作一个拥有静止和流动两个变种的实际流体。在此教程中,我们将其称为“酸”。缺失的引用稍后补全。

  1. public abstract class AcidFluid extends TutorialFluid
  2. {
  3. @Override
  4. public Fluid getStill()
  5. {
  6. return <YOUR_STILL_FLUID_HERE>;
  7. }
  8.  
  9. @Override
  10. public Fluid getFlowing()
  11. {
  12. return <YOUR_FLOWING_FLUID_HERE>;
  13. }
  14.  
  15. @Override
  16. public Item getBucketItem()
  17. {
  18. return <YOUR_BUCKET_ITEM_HERE>;
  19. }
  20.  
  21. @Override
  22. protected BlockState toBlockState(FluidState fluidState)
  23. {
  24. // method_15741 converts the LEVEL_1_8 of the fluid state to the LEVEL_15 the fluid block uses
  25. return <YOUR_FLUID_BLOCK_HERE>.getDefaultState().with(Properties.LEVEL_15, method_15741(fluidState));
  26. }
  27.  
  28. public static class Flowing extends AcidFluid
  29. {
  30. @Override
  31. protected void appendProperties(StateManager.Builder<Fluid, FluidState> builder)
  32. {
  33. super.appendProperties(builder);
  34. builder.add(LEVEL);
  35. }
  36.  
  37. @Override
  38. public int getLevel(FluidState fluidState)
  39. {
  40. return fluidState.get(LEVEL);
  41. }
  42.  
  43. @Override
  44. public boolean isStill(FluidState fluidState)
  45. {
  46. return false;
  47. }
  48. }
  49.  
  50. public static class Still extends AcidFluid
  51. {
  52. @Override
  53. public int getLevel(FluidState fluidState)
  54. {
  55. return 8;
  56. }
  57.  
  58. @Override
  59. public boolean isStill(FluidState fluidState)
  60. {
  61. return true;
  62. }
  63. }
  64. }

接下来,我们将制作静态和动态酸变体的静态实例,以及一个酸桶。 在您的ModInitializer中:

  1. // ...
  2.  
  3. public static FlowableFluid STILL_ACID;
  4. public static FlowableFluid FLOWING_ACID;
  5.  
  6. public static Item ACID_BUCKET;
  7.  
  8. // ...
  9.  
  10. @Override
  11. public void onInitialize()
  12. {
  13. // ...
  14.  
  15. STILL_ACID = Registry.register(Registry.FLUID, new Identifier(MOD_ID, "acid"), new AcidFluid.Still());
  16.  
  17. FLOWING_ACID = Registry.register(Registry.FLUID, new Identifier(MOD_ID, "flowing_acid"), new AcidFluid.Flowing());
  18.  
  19. ACID_BUCKET = Registry.register(Registry.ITEM, new Identifier(MOD_ID, "acid_bucket"), new BucketItem(STILL_ACID, new Item.Settings().recipeRemainder(Items.BUCKET).maxCount(1)));
  20.  
  21. // ...
  22. }
  23.  
  24. // ...

为了使自定义流体表现得像水或熔岩,您必须将其添加到相应的流体标签中:对于水,制作data/minecraft/tags/fluids/ water.json文件,并在其中写入流体的标识符:

  1. {
  2. "replace": false,
  3. "values":
  4. [
  5. "your_mod_id:acid",
  6. "your_mod_id:flowing_acid"
  7. ]
  8. }

制作一个流体方块

接下来,我们需要在世界中创建表示酸的方块。net.minecraft.block.FluidBlock是我们需要使用的类,但由于其构造器受保护,我们不能直接构造它。一种解决方法是制作子类或者匿名子类。这里我们展示后一种方式。在您的ModInitializer中:

  1. // ...
  2.  
  3. public static Block ACID;
  4.  
  5. // ...
  6.  
  7. @Override
  8. public void onInitialize()
  9. {
  10. // ...
  11.  
  12. ACID = Registry.register(Registry.BLOCK, new Identifier(MOD_ID, "acid"), new FluidBlock(STILL_ACID, FabricBlockSettings.copy(Blocks.WATER)){});
  13.  
  14. // ...
  15. }
  16.  
  17. // ...

既然我们有了这些静态对象,我们回到AcidFluid并补全被重写的方法:

  1. public abstract class AcidFluid extends TutorialFluid
  2. {
  3. @Override
  4. public Fluid getStill()
  5. {
  6. return TutorialMod.STILL_ACID;
  7. }
  8.  
  9. @Override
  10. public Fluid getFlowing()
  11. {
  12. return TutorialMod.FLOWING_ACID;
  13. }
  14.  
  15. @Override
  16. public Item getBucketItem()
  17. {
  18. return TutorialMod.ACID_BUCKET;
  19. }
  20.  
  21. @Override
  22. protected BlockState toBlockState(FluidState fluidState)
  23. {
  24. // method_15741 converts the LEVEL_1_8 of the fluid state to the LEVEL_15 the fluid block uses
  25. return TutorialMod.ACID.getDefaultState().with(Properties.LEVEL_15, method_15741(fluidState));
  26. }
  27.  
  28. // ...
  29. }

渲染设置

为了让流体拥有材质,或者与一个颜色绑定,你需要为其注册一个FluidRenderHandler。这里,我们重用水的材质,并仅仅改变用于其上的颜色。为确保材质渲染为半透明的,你可以使用Fabric的BlockRenderLayerMap

  1. public class TutorialModClient implements ClientModInitializer
  2. {
  3. // ...
  4.  
  5. @Override
  6. public void onInitializeClient()
  7. {
  8. // ...
  9.  
  10. setupFluidRendering(TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID, new Identifier("minecraft", "water"), 0x4CC248);
  11. BlockRenderLayerMap.INSTANCE.putFluids(RenderLayer.getTranslucent(), TutorialMod.STILL_ACID, TutorialMod.FLOWING_ACID);
  12.  
  13. // ...
  14. }
  15.  
  16. // ...
  17.  
  18. public static void setupFluidRendering(final Fluid still, final Fluid flowing, final Identifier textureFluidId, final int color)
  19. {
  20. final Identifier stillSpriteId = new Identifier(textureFluidId.getNamespace(), "block/" + textureFluidId.getPath() + "_still");
  21. final Identifier flowingSpriteId = new Identifier(textureFluidId.getNamespace(), "block/" + textureFluidId.getPath() + "_flow");
  22.  
  23. // If they're not already present, add the sprites to the block atlas
  24. ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEX).register((atlasTexture, registry) ->
  25. {
  26. registry.register(stillSpriteId);
  27. registry.register(flowingSpriteId);
  28. });
  29.  
  30. final Identifier fluidId = Registry.FLUID.getId(still);
  31. final Identifier listenerId = new Identifier(fluidId.getNamespace(), fluidId.getPath() + "_reload_listener");
  32.  
  33. final Sprite[] fluidSprites = { null, null };
  34.  
  35. ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(new SimpleSynchronousResourceReloadListener()
  36. {
  37. @Override
  38. public Identifier getFabricId()
  39. {
  40. return listenerId;
  41. }
  42.  
  43. /**
  44. * Get the sprites from the block atlas when resources are reloaded
  45. */
  46. @Override
  47. public void apply(ResourceManager resourceManager)
  48. {
  49. final Function<Identifier, Sprite> atlas = MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEX);
  50. fluidSprites[0] = atlas.apply(stillSpriteId);
  51. fluidSprites[1] = atlas.apply(flowingSpriteId);
  52. }
  53. });
  54.  
  55. // The FluidRenderer gets the sprites and color from a FluidRenderHandler during rendering
  56. final FluidRenderHandler renderHandler = new FluidRenderHandler()
  57. {
  58. @Override
  59. public Sprite[] getFluidSprites(BlockRenderView view, BlockPos pos, FluidState state)
  60. {
  61. return fluidSprites;
  62. }
  63.  
  64. @Override
  65. public int getFluidColor(BlockRenderView view, BlockPos pos, FluidState state)
  66. {
  67. return color;
  68. }
  69. };
  70.  
  71. FluidRenderHandlerRegistry.INSTANCE.register(still, renderHandler);
  72. FluidRenderHandlerRegistry.INSTANCE.register(flowing, renderHandler);
  73. }
  74.  
  75. // ...
  76. }

如果你需要使用你自己的流体材质,你可以参考原版资源包1)作为一个模板。

Generation in a world

要在世界上产生酸湖,可以使用在ModInitializer中创建的 net.minecraft.world.gen.feature.LakeFeature

        LakeFeature acidFeature = Registry.register(Registry.FEATURE, new Identifier(MODID,"acid_lake"), new LakeFeature(dynamic -> new LakeFeatureConfig(acid.getDefaultState())));

然后将其放入所需的生物群系中以生成:

        // I tell it to generate like water lakes, with a rarity of 40 (the higher is the number, the lesser is the generation chance):
        Biomes.FOREST.addFeature(GenerationStep.Feature.LOCAL_MODIFICATIONS, Biome.configureFeature(acidFeature, new LakeFeatureConfig(acid.getDefaultState()), Decorator.WATER_LAKE, new LakeDecoratorConfig(40)));

本教程到此结束。

1)
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
zh_cn/tutorial/fluids.1605403389.txt.gz · Last modified: 2020/11/15 01:23 by solidblock