net.minecraftforge.fluids.FluidAttributes.java Source code

Java tutorial

Introduction

Here is the source code for net.minecraftforge.fluids.FluidAttributes.java

Source

/*
 * 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 javax.annotation.Nullable;

import net.minecraft.block.BlockState;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.ItemStack;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.*;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.ILightReader;

import java.util.function.BiFunction;
import java.util.stream.Stream;

import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.item.Rarity;
import net.minecraft.world.biome.BiomeColors;

/**
 * Minecraft Forge Fluid Implementation
 *
 * This class is a fluid (liquid or gas) equivalent to "Item." It describes the nature of a fluid
 * and contains its general properties.
 *
 * These properties do not have inherent gameplay mechanics - they are provided so that mods may
 * choose to take advantage of them.
 *
 * Fluid implementations are not required to actively use these properties, nor are objects
 * interfacing with fluids required to make use of them, but it is encouraged.
 *
 * The default values can be used as a reference point for mods adding fluids such as oil or heavy
 * water.
 *
 */
public class FluidAttributes {
    public static final int BUCKET_VOLUME = 1000;

    private String translationKey;

    private final ResourceLocation stillTexture;
    private final ResourceLocation flowingTexture;

    @Nullable
    private final ResourceLocation overlayTexture;

    private final SoundEvent fillSound;
    private final SoundEvent emptySound;

    /**
     * The light level emitted by this fluid.
     *
     * Default value is 0, as most fluids do not actively emit light.
     */
    private final int luminosity;

    /**
     * Density of the fluid - completely arbitrary; negative density indicates that the fluid is
     * lighter than air.
     *
     * Default value is approximately the real-life density of water in kg/m^3.
     */
    private final int density;

    /**
     * Temperature of the fluid - completely arbitrary; higher temperature indicates that the fluid is
     * hotter than air.
     *
     * Default value is approximately the real-life room temperature of water in degrees Kelvin.
     */
    private final int temperature;

    /**
     * Viscosity ("thickness") of the fluid - completely arbitrary; negative values are not
     * permissible.
     *
     * Default value is approximately the real-life density of water in m/s^2 (x10^-3).
     *
     * Higher viscosity means that a fluid flows more slowly, like molasses.
     * Lower viscosity means that a fluid flows more quickly, like helium.
     *
     */
    private final int viscosity;

    /**
     * This indicates if the fluid is gaseous.
     *
     * Generally this is associated with negative density fluids.
     */
    private final boolean isGaseous;

    /**
     * The rarity of the fluid.
     *
     * Used primarily in tool tips.
     */
    private final Rarity rarity;

    /**
     * Color used by universal bucket and the ModelFluid baked model.
     * Note that this int includes the alpha so converting this to RGB with alpha would be
     *   float r = ((color >> 16) & 0xFF) / 255f; // red
     *   float g = ((color >> 8) & 0xFF) / 255f; // green
     *   float b = ((color >> 0) & 0xFF) / 255f; // blue
     *   float a = ((color >> 24) & 0xFF) / 255f; // alpha
     */
    private final int color;

    protected FluidAttributes(Builder builder, Fluid fluid) {
        this.translationKey = builder.translationKey != null ? builder.translationKey
                : Util.makeTranslationKey("fluid", fluid.getRegistryName());
        this.stillTexture = builder.stillTexture;
        this.flowingTexture = builder.flowingTexture;
        this.overlayTexture = builder.overlayTexture;
        this.color = builder.color;
        this.fillSound = builder.fillSound;
        this.emptySound = builder.emptySound;
        this.luminosity = builder.luminosity;
        this.temperature = builder.temperature;
        this.viscosity = builder.viscosity;
        this.density = builder.density;
        this.isGaseous = builder.isGaseous;
        this.rarity = builder.rarity;
    }

    public ItemStack getBucket(FluidStack stack) {
        return new ItemStack(stack.getFluid().getFilledBucket());
    }

    public BlockState getBlock(ILightReader reader, BlockPos pos, IFluidState state) {
        return state.getBlockState();
    }

    public IFluidState getStateForPlacement(ILightReader reader, BlockPos pos, FluidStack state) {
        return state.getFluid().getDefaultState();
    }

    public final boolean canBePlacedInWorld(ILightReader reader, BlockPos pos, IFluidState state) {
        return !getBlock(reader, pos, state).isAir(reader, pos);
    }

    public final boolean canBePlacedInWorld(ILightReader reader, BlockPos pos, FluidStack state) {
        return !getBlock(reader, pos, getStateForPlacement(reader, pos, state)).isAir(reader, pos);
    }

    public final boolean isLighterThanAir() {
        return this.density <= 0;
    }

    /**
     * Determines if this fluid should vaporize in dimensions where water vaporizes when placed.
     * To preserve the intentions of vanilla, fluids that can turn lava into obsidian should vaporize.
     * This prevents players from making the nether safe with a single bucket.
     * Based on {@link net.minecraft.item.BucketItem#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
     *
     * @param fluidStack The fluidStack is trying to be placed.
     * @return true if this fluid should vaporize in dimensions where water vaporizes when placed.
     */
    public boolean doesVaporize(ILightReader reader, BlockPos pos, FluidStack fluidStack) {
        BlockState blockstate = getBlock(reader, pos, getStateForPlacement(reader, pos, fluidStack));
        if (blockstate == null)
            return false;
        return blockstate.getMaterial() == net.minecraft.block.material.Material.WATER;
    }

    /**
     * Called instead of placing the fluid block if {@link net.minecraft.world.dimension.Dimension#doesWaterVaporize()} and {@link #doesVaporize(FluidStack)} are true.
     * Override this to make your explosive liquid blow up instead of the default smoke, etc.
     * Based on {@link net.minecraft.item.BucketItem#tryPlaceContainedLiquid(PlayerEntity, World, BlockPos)}
     *
     * @param player     Player who tried to place the fluid. May be null for blocks like dispensers.
     * @param worldIn    World to vaporize the fluid in.
     * @param pos        The position in the world the fluid block was going to be placed.
     * @param fluidStack The fluidStack that was going to be placed.
     */
    public void vaporize(@Nullable PlayerEntity player, World worldIn, BlockPos pos, FluidStack fluidStack) {
        worldIn.playSound(player, pos, SoundEvents.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 0.5F,
                2.6F + (worldIn.rand.nextFloat() - worldIn.rand.nextFloat()) * 0.8F);

        for (int l = 0; l < 8; ++l) {
            worldIn.addOptionalParticle(ParticleTypes.LARGE_SMOKE, (double) pos.getX() + Math.random(),
                    (double) pos.getY() + Math.random(), (double) pos.getZ() + Math.random(), 0.0D, 0.0D, 0.0D);
        }
    }

    /**
     * Returns the localized name of this fluid.
     */
    public ITextComponent getDisplayName(FluidStack stack) {
        return new TranslationTextComponent(getTranslationKey());
    }

    /**
     * A FluidStack sensitive version of getTranslationKey
     */
    public String getTranslationKey(FluidStack stack) {
        return this.getTranslationKey();
    }

    /**
     * Returns the translation key of this fluid.
     */
    public String getTranslationKey() {
        return this.translationKey;
    }

    /* Default Accessors */
    public final int getLuminosity() {
        return this.luminosity;
    }

    public final int getDensity() {
        return this.density;
    }

    public final int getTemperature() {
        return this.temperature;
    }

    public final int getViscosity() {
        return this.viscosity;
    }

    public final boolean isGaseous() {
        return this.isGaseous;
    }

    public Rarity getRarity() {
        return rarity;
    }

    public int getColor() {
        return color;
    }

    public ResourceLocation getStillTexture() {
        return stillTexture;
    }

    public ResourceLocation getFlowingTexture() {
        return flowingTexture;
    }

    @Nullable
    public ResourceLocation getOverlayTexture() {
        return overlayTexture;
    }

    public SoundEvent getFillSound() {
        return fillSound;
    }

    public SoundEvent getEmptySound() {
        return emptySound;
    }

    /* Stack-based Accessors */
    public int getLuminosity(FluidStack stack) {
        return getLuminosity();
    }

    public int getDensity(FluidStack stack) {
        return getDensity();
    }

    public int getTemperature(FluidStack stack) {
        return getTemperature();
    }

    public int getViscosity(FluidStack stack) {
        return getViscosity();
    }

    public boolean isGaseous(FluidStack stack) {
        return isGaseous();
    }

    public Rarity getRarity(FluidStack stack) {
        return getRarity();
    }

    public int getColor(FluidStack stack) {
        return getColor();
    }

    public ResourceLocation getStillTexture(FluidStack stack) {
        return getStillTexture();
    }

    public ResourceLocation getFlowingTexture(FluidStack stack) {
        return getFlowingTexture();
    }

    public SoundEvent getFillSound(FluidStack stack) {
        return getFillSound();
    }

    public SoundEvent getEmptySound(FluidStack stack) {
        return getEmptySound();
    }

    /* World-based Accessors */
    public int getLuminosity(ILightReader world, BlockPos pos) {
        return getLuminosity();
    }

    public int getDensity(ILightReader world, BlockPos pos) {
        return getDensity();
    }

    public int getTemperature(ILightReader world, BlockPos pos) {
        return getTemperature();
    }

    public int getViscosity(ILightReader world, BlockPos pos) {
        return getViscosity();
    }

    public boolean isGaseous(ILightReader world, BlockPos pos) {
        return isGaseous();
    }

    public Rarity getRarity(ILightReader world, BlockPos pos) {
        return getRarity();
    }

    public int getColor(ILightReader world, BlockPos pos) {
        return getColor();
    }

    public ResourceLocation getStillTexture(ILightReader world, BlockPos pos) {
        return getStillTexture();
    }

    public ResourceLocation getFlowingTexture(ILightReader world, BlockPos pos) {
        return getFlowingTexture();
    }

    public SoundEvent getFillSound(ILightReader world, BlockPos pos) {
        return getFillSound();
    }

    public SoundEvent getEmptySound(ILightReader world, BlockPos pos) {
        return getEmptySound();
    }

    public static Builder builder(ResourceLocation stillTexture, ResourceLocation 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 {
        private final ResourceLocation stillTexture;
        private final ResourceLocation flowingTexture;
        private ResourceLocation overlayTexture;
        private int color = 0xFFFFFFFF;
        private String translationKey;
        private SoundEvent fillSound;
        private SoundEvent emptySound;
        private int luminosity = 0;
        private int density = 1000;
        private int temperature = 300;
        private int viscosity = 1000;
        private boolean isGaseous;
        private Rarity rarity = Rarity.COMMON;
        private BiFunction<Builder, Fluid, FluidAttributes> factory;

        protected Builder(ResourceLocation stillTexture, ResourceLocation flowingTexture,
                BiFunction<Builder, Fluid, FluidAttributes> factory) {
            this.factory = factory;
            this.stillTexture = stillTexture;
            this.flowingTexture = flowingTexture;
        }

        public final Builder translationKey(String translationKey) {
            this.translationKey = translationKey;
            return this;
        }

        public final Builder color(int color) {
            this.color = color;
            return this;
        }

        public final Builder overlay(ResourceLocation texture) {
            overlayTexture = texture;
            return this;
        }

        public final Builder luminosity(int luminosity) {
            this.luminosity = luminosity;
            return this;
        }

        public final Builder density(int density) {
            this.density = density;
            return this;
        }

        public final Builder temperature(int temperature) {
            this.temperature = temperature;
            return this;
        }

        public final Builder viscosity(int viscosity) {
            this.viscosity = viscosity;
            return this;
        }

        public final Builder gaseous() {
            isGaseous = true;
            return this;
        }

        public final Builder rarity(Rarity rarity) {
            this.rarity = rarity;
            return this;
        }

        public final Builder sound(SoundEvent sound) {
            this.fillSound = this.emptySound = sound;
            return this;
        }

        public final Builder sound(SoundEvent fillSound, SoundEvent emptySound) {
            this.fillSound = fillSound;
            this.emptySound = emptySound;
            return this;
        }

        public FluidAttributes build(Fluid fluid) {
            return factory.apply(this, fluid);
        }
    }

    public static class Water extends FluidAttributes {
        protected Water(Builder builder, Fluid fluid) {
            super(builder, fluid);
        }

        @Override
        public int getColor(ILightReader world, BlockPos pos) {
            return BiomeColors.func_228363_c_(world, pos) | 0xFF000000;
        }

        public static Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) {
            return new Builder(stillTexture, flowingTexture, Water::new);
        }
    }
}