Merge pull request #642 from MinecraftForge/newliquid
New liquid system
This commit is contained in:
commit
bc932a28ae
32 changed files with 3032 additions and 9 deletions
|
@ -13,9 +13,11 @@ import org.lwjgl.opengl.GL12;
|
||||||
import org.lwjgl.opengl.PixelFormat;
|
import org.lwjgl.opengl.PixelFormat;
|
||||||
|
|
||||||
import cpw.mods.fml.client.FMLClientHandler;
|
import cpw.mods.fml.client.FMLClientHandler;
|
||||||
|
import cpw.mods.fml.client.registry.RenderingRegistry;
|
||||||
|
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.BlockFluid;
|
||||||
import net.minecraft.entity.item.EntityItem;
|
import net.minecraft.entity.item.EntityItem;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityLiving;
|
import net.minecraft.entity.EntityLiving;
|
||||||
|
@ -39,6 +41,8 @@ import net.minecraftforge.client.event.DrawBlockHighlightEvent;
|
||||||
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
import net.minecraftforge.client.event.RenderWorldLastEvent;
|
||||||
import net.minecraftforge.client.event.TextureStitchEvent;
|
import net.minecraftforge.client.event.TextureStitchEvent;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.fluids.FluidRegistry;
|
||||||
|
import net.minecraftforge.fluids.RenderBlockFluid;
|
||||||
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
|
import static net.minecraftforge.client.IItemRenderer.ItemRenderType.*;
|
||||||
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
|
import static net.minecraftforge.client.IItemRenderer.ItemRendererHelper.*;
|
||||||
|
|
||||||
|
@ -235,6 +239,9 @@ public class ForgeHooksClient
|
||||||
public static void onTextureStitchedPost(TextureMap map)
|
public static void onTextureStitchedPost(TextureMap map)
|
||||||
{
|
{
|
||||||
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
|
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
|
||||||
|
|
||||||
|
FluidRegistry.WATER.setIcons(BlockFluid.func_94424_b("water"), BlockFluid.func_94424_b("water_flow"));
|
||||||
|
FluidRegistry.LAVA.setIcons(BlockFluid.func_94424_b("lava"), BlockFluid.func_94424_b("lava_flow"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -311,4 +318,12 @@ public class ForgeHooksClient
|
||||||
return base + name;
|
return base + name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization of Forge Renderers.
|
||||||
|
*/
|
||||||
|
static {
|
||||||
|
FluidRegistry.renderIdFluid = RenderingRegistry.getNextAvailableRenderId();
|
||||||
|
RenderingRegistry.registerBlockHandler(RenderBlockFluid.instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,7 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
||||||
public static boolean removeErroringEntities = false;
|
public static boolean removeErroringEntities = false;
|
||||||
public static boolean removeErroringTileEntities = false;
|
public static boolean removeErroringTileEntities = false;
|
||||||
public static boolean disableStitchedFileSaving = false;
|
public static boolean disableStitchedFileSaving = false;
|
||||||
|
public static boolean forceDuplicateFluidBlockCrash = true;
|
||||||
|
|
||||||
public ForgeDummyContainer()
|
public ForgeDummyContainer()
|
||||||
{
|
{
|
||||||
|
@ -99,7 +100,7 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
||||||
}
|
}
|
||||||
|
|
||||||
prop = config.get(Configuration.CATEGORY_GENERAL, "legacyFurnaceOutput", false);
|
prop = config.get(Configuration.CATEGORY_GENERAL, "legacyFurnaceOutput", false);
|
||||||
prop.comment = "Controls the sides of vanilla furnaces for Forge's ISidedInventroy, Vanilla defines the output as the bottom, but mods/Forge define it as the sides. Settings this to true will restore the old side relations.";
|
prop.comment = "Controls the sides of vanilla furnaces for Forge's ISidedInventory, Vanilla defines the output as the bottom, but mods/Forge define it as the sides. Settings this to true will restore the old side relations.";
|
||||||
legacyFurnaceSides = prop.getBoolean(false);
|
legacyFurnaceSides = prop.getBoolean(false);
|
||||||
|
|
||||||
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringEntities", false);
|
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringEntities", false);
|
||||||
|
@ -108,7 +109,7 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
||||||
|
|
||||||
if (removeErroringEntities)
|
if (removeErroringEntities)
|
||||||
{
|
{
|
||||||
FMLLog.warning("Enableing removal of erroring Entities USE AT YOUR OWN RISK");
|
FMLLog.warning("Enabling removal of erroring Entities - USE AT YOUR OWN RISK");
|
||||||
}
|
}
|
||||||
|
|
||||||
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringTileEntities", false);
|
prop = config.get(Configuration.CATEGORY_GENERAL, "removeErroringTileEntities", false);
|
||||||
|
@ -117,13 +118,22 @@ public class ForgeDummyContainer extends DummyModContainer implements WorldAcces
|
||||||
|
|
||||||
if (removeErroringTileEntities)
|
if (removeErroringTileEntities)
|
||||||
{
|
{
|
||||||
FMLLog.warning("Enableing removal of erroring Tile Entities USE AT YOUR OWN RISK");
|
FMLLog.warning("Enabling removal of erroring Tile Entities - USE AT YOUR OWN RISK");
|
||||||
}
|
}
|
||||||
|
|
||||||
prop = config.get(Configuration.CATEGORY_GENERAL, "disableStitchedFileSaving", true);
|
prop = config.get(Configuration.CATEGORY_GENERAL, "disableStitchedFileSaving", true);
|
||||||
prop.comment = "Set this to just disable the texture stitcher from writing the 'debug.stitched_{name}.png file to disc. Just a small performance tweak. Default: true";
|
prop.comment = "Set this to just disable the texture stitcher from writing the 'debug.stitched_{name}.png file to disc. Just a small performance tweak. Default: true";
|
||||||
disableStitchedFileSaving = prop.getBoolean(true);
|
disableStitchedFileSaving = prop.getBoolean(true);
|
||||||
|
|
||||||
|
prop = config.get(Configuration.CATEGORY_GENERAL, "forceDuplicateFluidBlockCrash", true);
|
||||||
|
prop.comment = "Set this to force a crash if more than one block attempts to link back to the same Fluid. Enabled by default.";
|
||||||
|
forceDuplicateFluidBlockCrash = prop.getBoolean(true);
|
||||||
|
|
||||||
|
if (!forceDuplicateFluidBlockCrash)
|
||||||
|
{
|
||||||
|
FMLLog.warning("Disabling forced crashes on duplicate Fluid Blocks - USE AT YOUR OWN RISK");
|
||||||
|
}
|
||||||
|
|
||||||
if (config.hasChanged())
|
if (config.hasChanged())
|
||||||
{
|
{
|
||||||
config.save();
|
config.save();
|
||||||
|
|
|
@ -4,8 +4,11 @@ import net.minecraft.network.INetworkManager;
|
||||||
import net.minecraft.network.NetLoginHandler;
|
import net.minecraft.network.NetLoginHandler;
|
||||||
import net.minecraft.network.packet.NetHandler;
|
import net.minecraft.network.packet.NetHandler;
|
||||||
import net.minecraft.network.packet.Packet1Login;
|
import net.minecraft.network.packet.Packet1Login;
|
||||||
|
import net.minecraft.network.packet.Packet250CustomPayload;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraftforge.fluids.FluidIdMapPacket;
|
||||||
import cpw.mods.fml.common.network.IConnectionHandler;
|
import cpw.mods.fml.common.network.IConnectionHandler;
|
||||||
|
import cpw.mods.fml.common.network.PacketDispatcher;
|
||||||
import cpw.mods.fml.common.network.Player;
|
import cpw.mods.fml.common.network.Player;
|
||||||
|
|
||||||
public class ForgeConnectionHandler implements IConnectionHandler {
|
public class ForgeConnectionHandler implements IConnectionHandler {
|
||||||
|
@ -13,7 +16,10 @@ public class ForgeConnectionHandler implements IConnectionHandler {
|
||||||
@Override
|
@Override
|
||||||
public void playerLoggedIn(Player player, NetHandler netHandler, INetworkManager manager)
|
public void playerLoggedIn(Player player, NetHandler netHandler, INetworkManager manager)
|
||||||
{
|
{
|
||||||
|
Packet250CustomPayload[] fluidPackets = ForgePacket.makePacketSet(new FluidIdMapPacket());
|
||||||
|
for (int i = 0; i < fluidPackets.length; i++) {
|
||||||
|
PacketDispatcher.sendPacketToPlayer(fluidPackets[i], player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,6 +9,7 @@ import net.minecraft.network.INetworkManager;
|
||||||
import net.minecraft.network.packet.NetHandler;
|
import net.minecraft.network.packet.NetHandler;
|
||||||
import net.minecraft.network.packet.Packet250CustomPayload;
|
import net.minecraft.network.packet.Packet250CustomPayload;
|
||||||
import net.minecraftforge.common.network.packet.DimensionRegisterPacket;
|
import net.minecraftforge.common.network.packet.DimensionRegisterPacket;
|
||||||
|
import net.minecraftforge.fluids.FluidIdMapPacket;
|
||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.google.common.collect.MapMaker;
|
import com.google.common.collect.MapMaker;
|
||||||
|
@ -29,7 +30,11 @@ public abstract class ForgePacket
|
||||||
/**
|
/**
|
||||||
* Registers a dimension for a provider on client
|
* Registers a dimension for a provider on client
|
||||||
*/
|
*/
|
||||||
REGISTERDIMENSION(DimensionRegisterPacket.class);
|
REGISTERDIMENSION(DimensionRegisterPacket.class),
|
||||||
|
/**
|
||||||
|
* The Fluid ID map to send to the client
|
||||||
|
*/
|
||||||
|
FLUID_IDMAP(FluidIdMapPacket.class);
|
||||||
|
|
||||||
private Class<? extends ForgePacket> packetType;
|
private Class<? extends ForgePacket> packetType;
|
||||||
private ConcurrentMap<INetworkManager, ForgePacket> partTracker;
|
private ConcurrentMap<INetworkManager, ForgePacket> partTracker;
|
||||||
|
|
416
common/net/minecraftforge/fluids/BlockFluidBase.java
Normal file
416
common/net/minecraftforge/fluids/BlockFluidBase.java
Normal file
|
@ -0,0 +1,416 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.material.Material;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.util.AxisAlignedBB;
|
||||||
|
import net.minecraft.util.Vec3;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a base implementation for Fluid blocks.
|
||||||
|
*
|
||||||
|
* It is highly recommended that you extend this class or one of the Forge-provided child classes.
|
||||||
|
*
|
||||||
|
* @author King Lemming, OvermindDL1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class BlockFluidBase extends Block implements IFluidBlock {
|
||||||
|
|
||||||
|
protected final static Map<Integer, Boolean> defaultDisplacementIds = new HashMap<Integer, Boolean>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
defaultDisplacementIds.put(Block.doorWood.blockID, false);
|
||||||
|
defaultDisplacementIds.put(Block.doorIron.blockID, false);
|
||||||
|
defaultDisplacementIds.put(Block.signPost.blockID, false);
|
||||||
|
defaultDisplacementIds.put(Block.signWall.blockID, false);
|
||||||
|
defaultDisplacementIds.put(Block.reed.blockID, false);
|
||||||
|
}
|
||||||
|
protected Map<Integer, Boolean> displacementIds = new HashMap<Integer, Boolean>();
|
||||||
|
|
||||||
|
protected int quantaPerBlock = 8;
|
||||||
|
protected float quantaPerBlockFloat = 8F;
|
||||||
|
protected int density = 1;
|
||||||
|
protected int densityDir = -1;
|
||||||
|
|
||||||
|
protected int tickRate = 20;
|
||||||
|
protected int renderPass = 1;
|
||||||
|
protected int maxScaledLight = 0;
|
||||||
|
|
||||||
|
protected final String fluidName;
|
||||||
|
|
||||||
|
public BlockFluidBase(int id, Fluid fluid, Material material) {
|
||||||
|
|
||||||
|
super(id, material);
|
||||||
|
this.setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 1.0F, 1.0F);
|
||||||
|
this.setTickRandomly(true);
|
||||||
|
this.disableStats();
|
||||||
|
|
||||||
|
this.fluidName = fluid.getName();
|
||||||
|
this.density = fluid.density;
|
||||||
|
this.maxScaledLight = fluid.luminosity;
|
||||||
|
this.tickRate = fluid.viscosity / 200;
|
||||||
|
fluid.setBlockID(id);
|
||||||
|
|
||||||
|
displacementIds.putAll(defaultDisplacementIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidBase setQuantaPerBlock(int quantaPerBlock) {
|
||||||
|
|
||||||
|
if (quantaPerBlock > 16 || quantaPerBlock < 1) {
|
||||||
|
quantaPerBlock = 8;
|
||||||
|
}
|
||||||
|
this.quantaPerBlock = quantaPerBlock;
|
||||||
|
this.quantaPerBlockFloat = quantaPerBlock;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidBase setDensity(int density) {
|
||||||
|
|
||||||
|
if (density == 0) {
|
||||||
|
density = 1;
|
||||||
|
}
|
||||||
|
this.density = density;
|
||||||
|
this.densityDir = density > 0 ? -1 : 1;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidBase setTickRate(int tickRate) {
|
||||||
|
|
||||||
|
if (tickRate <= 0) {
|
||||||
|
tickRate = 20;
|
||||||
|
}
|
||||||
|
this.tickRate = tickRate;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidBase setRenderPass(int renderPass) {
|
||||||
|
|
||||||
|
this.renderPass = renderPass;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidBase setMaxScaledLight(int maxScaledLight) {
|
||||||
|
|
||||||
|
this.maxScaledLight = maxScaledLight;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the block at (x, y, z) is displaceable. Does not displace the block.
|
||||||
|
*/
|
||||||
|
public boolean canDisplace(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
int bId = world.getBlockId(x, y, z);
|
||||||
|
|
||||||
|
if (bId == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (bId == blockID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (displacementIds.containsKey(bId)) {
|
||||||
|
return displacementIds.get(bId);
|
||||||
|
}
|
||||||
|
Material material = Block.blocksList[bId].blockMaterial;
|
||||||
|
|
||||||
|
if (material.blocksMovement() || material == Material.portal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to displace the block at (x, y, z), return true if it was displaced.
|
||||||
|
*/
|
||||||
|
public boolean displaceIfPossible(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
int bId = world.getBlockId(x, y, z);
|
||||||
|
|
||||||
|
if (bId == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (bId == blockID) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (displacementIds.containsKey(bId)) {
|
||||||
|
if (displacementIds.get(bId)) {
|
||||||
|
Block.blocksList[bId].dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Material material = Block.blocksList[bId].blockMaterial;
|
||||||
|
|
||||||
|
if (material.blocksMovement() || material == Material.portal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Block.blocksList[bId].dropBlockAsItem(world, x, y, z, world.getBlockMetadata(x, y, z), 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int getQuantaValue(IBlockAccess world, int x, int y, int z);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract boolean canCollideCheck(int meta, boolean fullHit);
|
||||||
|
|
||||||
|
public abstract int getMaxRenderHeightMeta();
|
||||||
|
|
||||||
|
/* BLOCK FUNCTIONS */
|
||||||
|
@Override
|
||||||
|
public void onBlockAdded(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
world.scheduleBlockUpdate(x, y, z, blockID, tickRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNeighborBlockChange(World world, int x, int y, int z, int blockId) {
|
||||||
|
|
||||||
|
world.scheduleBlockUpdate(x, y, z, blockID, tickRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to prevent updates on chunk generation
|
||||||
|
@Override
|
||||||
|
public boolean func_82506_l() {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getBlocksMovement(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int idDropped(int par1, Random par2Random, int par3) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int quantityDropped(Random par1Random) {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int tickRate(World world) {
|
||||||
|
|
||||||
|
return tickRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void velocityToAddToEntity(World world, int x, int y, int z, Entity entity, Vec3 vec) {
|
||||||
|
|
||||||
|
if (densityDir > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Vec3 vec_flow = this.getFlowVector(world, x, y, z);
|
||||||
|
vec.xCoord += vec_flow.xCoord * (quantaPerBlock * 4);
|
||||||
|
vec.yCoord += vec_flow.yCoord * (quantaPerBlock * 4);
|
||||||
|
vec.zCoord += vec_flow.zCoord * (quantaPerBlock * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightValue(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
if (maxScaledLight == 0) {
|
||||||
|
return super.getLightValue(world, x, y, z);
|
||||||
|
}
|
||||||
|
int data = world.getBlockMetadata(x, y, z);
|
||||||
|
return (int) (data / quantaPerBlockFloat * maxScaledLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRenderType() {
|
||||||
|
|
||||||
|
return FluidRegistry.renderIdFluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOpaqueCube() {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean renderAsNormalBlock() {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getBlockBrightness(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
float lightThis = world.getLightBrightness(x, y, z);
|
||||||
|
float lightUp = world.getLightBrightness(x, y + 1, z);
|
||||||
|
|
||||||
|
return lightThis > lightUp ? lightThis : lightUp;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMixedBrightnessForBlock(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
int lightThis = world.getLightBrightnessForSkyBlocks(x, y, z, 0);
|
||||||
|
int lightUp = world.getLightBrightnessForSkyBlocks(x, y + 1, z, 0);
|
||||||
|
int lightThisBase = lightThis & 255;
|
||||||
|
int lightUpBase = lightUp & 255;
|
||||||
|
int lightThisExt = lightThis >> 16 & 255;
|
||||||
|
int lightUpExt = lightUp >> 16 & 255;
|
||||||
|
|
||||||
|
return (lightThisBase > lightUpBase ? lightThisBase : lightUpBase) | (lightThisExt > lightUpExt ? lightThisExt : lightUpExt) << 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRenderBlockPass() {
|
||||||
|
|
||||||
|
return renderPass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldSideBeRendered(IBlockAccess world, int x, int y, int z, int side) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y, z) != blockID) {
|
||||||
|
return !world.isBlockOpaqueCube(x, y, z);
|
||||||
|
}
|
||||||
|
Material mat = world.getBlockMaterial(x, y, z);
|
||||||
|
return mat == this.blockMaterial ? false : super.shouldSideBeRendered(world, x, y, z, side);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FLUID FUNCTIONS */
|
||||||
|
public static final int getDensity(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
Block block = Block.blocksList[world.getBlockId(x, y, z)];
|
||||||
|
|
||||||
|
if (!(block instanceof BlockFluidBase)) {
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return ((BlockFluidBase) block).density;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getFlowDirection(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
Block block = Block.blocksList[world.getBlockId(x, y, z)];
|
||||||
|
|
||||||
|
if (!(Block.blocksList[world.getBlockId(x, y, z)] instanceof BlockFluidBase)) {
|
||||||
|
return -1000.0;
|
||||||
|
}
|
||||||
|
Vec3 vec = ((BlockFluidBase) block).getFlowVector(world, x, y, z);
|
||||||
|
return vec.xCoord == 0.0D && vec.zCoord == 0.0D ? -1000.0D : Math.atan2(vec.zCoord, vec.xCoord) - Math.PI / 2D;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getQuantaValueBelow(IBlockAccess world, int x, int y, int z, int belowThis) {
|
||||||
|
|
||||||
|
int quantaRemaining = getQuantaValue(world, x, y, z);
|
||||||
|
|
||||||
|
if (quantaRemaining >= belowThis) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return quantaRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getQuantaValueAbove(IBlockAccess world, int x, int y, int z, int aboveThis) {
|
||||||
|
|
||||||
|
int quantaRemaining = getQuantaValue(world, x, y, z);
|
||||||
|
|
||||||
|
if (quantaRemaining <= aboveThis) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return quantaRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final float getQuantaPercentage(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
int quantaRemaining = getQuantaValue(world, x, y, z);
|
||||||
|
return quantaRemaining / quantaPerBlockFloat;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vec3 getFlowVector(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
Vec3 vec = world.getWorldVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D);
|
||||||
|
int decay = quantaPerBlock - getQuantaValue(world, x, y, z);
|
||||||
|
|
||||||
|
for (int side = 0; side < 4; ++side) {
|
||||||
|
int x2 = x;
|
||||||
|
int z2 = z;
|
||||||
|
|
||||||
|
switch (side) {
|
||||||
|
case 0:
|
||||||
|
--x2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
--z2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
++x2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
++z2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int otherDecay = quantaPerBlock - getQuantaValue(world, x2, y, z2);
|
||||||
|
|
||||||
|
if (otherDecay >= quantaPerBlock) {
|
||||||
|
if (!world.getBlockMaterial(x2, y, z2).blocksMovement()) {
|
||||||
|
otherDecay = quantaPerBlock - getQuantaValue(world, x2, y - 1, z2);
|
||||||
|
|
||||||
|
if (otherDecay >= 0) {
|
||||||
|
int power = otherDecay - (decay - quantaPerBlock);
|
||||||
|
vec = vec.addVector((x2 - x) * power, (y - y) * power, (z2 - z) * power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (otherDecay >= 0) {
|
||||||
|
int power = otherDecay - decay;
|
||||||
|
vec = vec.addVector((x2 - x) * power, (y - y) * power, (z2 - z) * power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (world.getBlockId(x, y + 1, z) == blockID) {
|
||||||
|
boolean flag = false;
|
||||||
|
|
||||||
|
if (this.isBlockSolid(world, x, y, z - 1, 2)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x, y, z + 1, 3)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x - 1, y, z, 4)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x + 1, y, z, 5)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x, y + 1, z - 1, 2)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x, y + 1, z + 1, 3)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x - 1, y + 1, z, 4)) {
|
||||||
|
flag = true;
|
||||||
|
} else if (this.isBlockSolid(world, x + 1, y + 1, z, 5)) {
|
||||||
|
flag = true;
|
||||||
|
}
|
||||||
|
if (flag) {
|
||||||
|
vec = vec.normalize().addVector(0.0D, -6.0D, 0.0D);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec = vec.normalize();
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidBlock */
|
||||||
|
@Override
|
||||||
|
public Fluid getFluid() {
|
||||||
|
|
||||||
|
return FluidRegistry.getFluid(fluidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
309
common/net/minecraftforge/fluids/BlockFluidClassic.java
Normal file
309
common/net/minecraftforge/fluids/BlockFluidClassic.java
Normal file
|
@ -0,0 +1,309 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.material.Material;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a fluid block implementation which emulates vanilla Minecraft fluid behavior.
|
||||||
|
*
|
||||||
|
* It is highly recommended that you use/extend this class for "classic" fluid blocks.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BlockFluidClassic extends BlockFluidBase {
|
||||||
|
|
||||||
|
protected boolean[] isOptimalFlowDirection = new boolean[4];
|
||||||
|
protected int[] flowCost = new int[4];
|
||||||
|
|
||||||
|
protected FluidStack stack;
|
||||||
|
|
||||||
|
public BlockFluidClassic(int id, Fluid fluid, Material material) {
|
||||||
|
|
||||||
|
super(id, fluid, material);
|
||||||
|
stack = new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidClassic setFluidStack(FluidStack stack) {
|
||||||
|
|
||||||
|
this.stack = stack;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BlockFluidClassic setFluidStackAmount(int amount) {
|
||||||
|
|
||||||
|
this.stack.amount = amount;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getQuantaValue(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y, z) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (world.getBlockId(x, y, z) != blockID) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int quantaRemaining = quantaPerBlock - world.getBlockMetadata(x, y, z);
|
||||||
|
return quantaRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCollideCheck(int meta, boolean fullHit) {
|
||||||
|
|
||||||
|
return fullHit && meta == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxRenderHeightMeta() {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLightValue(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
if (maxScaledLight == 0) {
|
||||||
|
return super.getLightValue(world, x, y, z);
|
||||||
|
}
|
||||||
|
int data = quantaPerBlock - world.getBlockMetadata(x, y, z) - 1;
|
||||||
|
return (int) (data / quantaPerBlockFloat * maxScaledLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTick(World world, int x, int y, int z, Random rand) {
|
||||||
|
|
||||||
|
int quantaRemaining = quantaPerBlock - world.getBlockMetadata(x, y, z);
|
||||||
|
int expQuanta = -101;
|
||||||
|
|
||||||
|
// check adjacent block levels if non-source
|
||||||
|
if (quantaRemaining < quantaPerBlock) {
|
||||||
|
int y2 = y - densityDir;
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y2, z) == blockID || world.getBlockId(x - 1, y2, z) == blockID || world.getBlockId(x + 1, y2, z) == blockID
|
||||||
|
|| world.getBlockId(x, y2, z - 1) == blockID || world.getBlockId(x, y2, z + 1) == blockID) {
|
||||||
|
expQuanta = quantaPerBlock - 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
int maxQuanta = -100;
|
||||||
|
maxQuanta = getLargerQuanta(world, x - 1, y, z, maxQuanta);
|
||||||
|
maxQuanta = getLargerQuanta(world, x + 1, y, z, maxQuanta);
|
||||||
|
maxQuanta = getLargerQuanta(world, x, y, z - 1, maxQuanta);
|
||||||
|
maxQuanta = getLargerQuanta(world, x, y, z + 1, maxQuanta);
|
||||||
|
|
||||||
|
expQuanta = maxQuanta - 1;
|
||||||
|
}
|
||||||
|
// decay calculation
|
||||||
|
if (expQuanta != quantaRemaining) {
|
||||||
|
quantaRemaining = expQuanta;
|
||||||
|
|
||||||
|
if (expQuanta <= 0) {
|
||||||
|
world.setBlockToAir(x, y, z);
|
||||||
|
} else {
|
||||||
|
world.setBlockMetadataWithNotify(x, y, z, quantaPerBlock - expQuanta, 3);
|
||||||
|
world.scheduleBlockUpdate(x, y, z, blockID, tickRate);
|
||||||
|
world.notifyBlocksOfNeighborChange(x, y, z, blockID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (quantaRemaining > quantaPerBlock) {
|
||||||
|
world.setBlockMetadataWithNotify(x, y, z, 0, 3);
|
||||||
|
}
|
||||||
|
// Flow vertically if possible
|
||||||
|
if (canDisplace(world, x, y + densityDir, z)) {
|
||||||
|
flowIntoBlock(world, x, y + densityDir, z, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Flow outward if possible
|
||||||
|
int flowMeta = quantaPerBlock - quantaRemaining + 1;
|
||||||
|
if (flowMeta >= quantaPerBlock) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isSourceBlock(world, x, y, z) || !isFlowingVertically(world, x, y, z)) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y - densityDir, z) == blockID) {
|
||||||
|
flowMeta = 1;
|
||||||
|
}
|
||||||
|
boolean flowTo[] = getOptimalFlowDirections(world, x, y, z);
|
||||||
|
|
||||||
|
if (flowTo[0]) {
|
||||||
|
flowIntoBlock(world, x - 1, y, z, flowMeta);
|
||||||
|
}
|
||||||
|
if (flowTo[1]) {
|
||||||
|
flowIntoBlock(world, x + 1, y, z, flowMeta);
|
||||||
|
}
|
||||||
|
if (flowTo[2]) {
|
||||||
|
flowIntoBlock(world, x, y, z - 1, flowMeta);
|
||||||
|
}
|
||||||
|
if (flowTo[3]) {
|
||||||
|
flowIntoBlock(world, x, y, z + 1, flowMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFlowingVertically(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return world.getBlockId(x, y + densityDir, z) == blockID || world.getBlockId(x, y, z) == blockID && canFlowInto(world, x, y + densityDir, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSourceBlock(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return world.getBlockId(x, y, z) == blockID && world.getBlockMetadata(x, y, z) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean[] getOptimalFlowDirections(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
for (int side = 0; side < 4; side++) {
|
||||||
|
flowCost[side] = 1000;
|
||||||
|
|
||||||
|
int x2 = x;
|
||||||
|
int y2 = y;
|
||||||
|
int z2 = z;
|
||||||
|
|
||||||
|
switch (side) {
|
||||||
|
case 0:
|
||||||
|
--x2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
++x2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
--z2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
++z2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canFlowInto(world, x2, y2, z2) || isSourceBlock(world, x2, y2, z2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (canFlowInto(world, x2, y2 + densityDir, z2)) {
|
||||||
|
flowCost[side] = 0;
|
||||||
|
} else {
|
||||||
|
flowCost[side] = calculateFlowCost(world, x2, y2, z2, 1, side);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int min = flowCost[0];
|
||||||
|
for (int side = 1; side < 4; side++) {
|
||||||
|
if (flowCost[side] < min) {
|
||||||
|
min = flowCost[side];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int side = 0; side < 4; side++) {
|
||||||
|
isOptimalFlowDirection[side] = flowCost[side] == min;
|
||||||
|
}
|
||||||
|
return isOptimalFlowDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int calculateFlowCost(World world, int x, int y, int z, int recurseDepth, int side) {
|
||||||
|
|
||||||
|
int cost = 1000;
|
||||||
|
|
||||||
|
for (int adjSide = 0; adjSide < 4; adjSide++) {
|
||||||
|
if (adjSide == 0 && side == 1 || adjSide == 1 && side == 0 || adjSide == 2 && side == 3 || adjSide == 3 && side == 2) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int x2 = x;
|
||||||
|
int y2 = y;
|
||||||
|
int z2 = z;
|
||||||
|
|
||||||
|
switch (adjSide) {
|
||||||
|
case 0:
|
||||||
|
--x2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
++x2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
--z2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
++z2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!canFlowInto(world, x2, y2, z2) || isSourceBlock(world, x2, y2, z2)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (canFlowInto(world, x2, y2 + densityDir, z2)) {
|
||||||
|
return recurseDepth;
|
||||||
|
}
|
||||||
|
if (recurseDepth >= 4) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int min = calculateFlowCost(world, x2, y2, z2, recurseDepth + 1, adjSide);
|
||||||
|
if (min < cost) {
|
||||||
|
cost = min;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void flowIntoBlock(World world, int x, int y, int z, int meta) {
|
||||||
|
|
||||||
|
if (meta < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (displaceIfPossible(world, x, y, z)) {
|
||||||
|
world.setBlock(x, y, z, this.blockID, meta, 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canFlowInto(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
int bId = world.getBlockId(x, y, z);
|
||||||
|
if (bId == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (bId == blockID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (displacementIds.containsKey(bId)) {
|
||||||
|
return displacementIds.get(bId);
|
||||||
|
}
|
||||||
|
Material material = Block.blocksList[bId].blockMaterial;
|
||||||
|
if (material.blocksMovement() || material == Material.water || material == Material.lava || material == Material.portal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getLargerQuanta(IBlockAccess world, int x, int y, int z, int compare) {
|
||||||
|
|
||||||
|
int quantaRemaining = getQuantaValue(world, x, y, z);
|
||||||
|
|
||||||
|
if (quantaRemaining <= 0) {
|
||||||
|
return compare;
|
||||||
|
}
|
||||||
|
return quantaRemaining >= compare ? quantaRemaining : compare;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidBlock */
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(World world, int x, int y, int z, boolean doDrain) {
|
||||||
|
|
||||||
|
if (!isSourceBlock(world, x, y, z)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (doDrain) {
|
||||||
|
world.setBlockToAir(x, y, z);
|
||||||
|
}
|
||||||
|
return stack.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDrain(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return isSourceBlock(world, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
271
common/net/minecraftforge/fluids/BlockFluidFinite.java
Normal file
271
common/net/minecraftforge/fluids/BlockFluidFinite.java
Normal file
|
@ -0,0 +1,271 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.material.Material;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a cellular-automata based finite fluid block implementation.
|
||||||
|
*
|
||||||
|
* It is highly recommended that you use/extend this class for finite fluid blocks.
|
||||||
|
*
|
||||||
|
* @author OvermindDL1, KingLemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class BlockFluidFinite extends BlockFluidBase {
|
||||||
|
|
||||||
|
public BlockFluidFinite(int id, Fluid fluid, Material material) {
|
||||||
|
|
||||||
|
super(id, fluid, material);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getQuantaValue(IBlockAccess world, int x, int y, int z) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y, z) == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (world.getBlockId(x, y, z) != blockID) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
int quantaRemaining = world.getBlockMetadata(x, y, z) + 1;
|
||||||
|
return quantaRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canCollideCheck(int meta, boolean fullHit) {
|
||||||
|
|
||||||
|
return fullHit && meta == quantaPerBlock - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxRenderHeightMeta() {
|
||||||
|
|
||||||
|
return quantaPerBlock - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateTick(World world, int x, int y, int z, Random rand) {
|
||||||
|
|
||||||
|
boolean changed = false;
|
||||||
|
int quantaRemaining = world.getBlockMetadata(x, y, z) + 1;
|
||||||
|
|
||||||
|
// Flow vertically if possible
|
||||||
|
int prevRemaining = quantaRemaining;
|
||||||
|
quantaRemaining = tryToFlowVerticallyInto(world, x, y, z, quantaRemaining);
|
||||||
|
|
||||||
|
if (quantaRemaining < 1) {
|
||||||
|
return;
|
||||||
|
} else if (quantaRemaining != prevRemaining) {
|
||||||
|
changed = true;
|
||||||
|
|
||||||
|
if (quantaRemaining == 1) {
|
||||||
|
world.setBlockMetadataWithNotify(x, y, z, quantaRemaining - 1, 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (quantaRemaining == 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flow out if possible
|
||||||
|
int lowerthan = quantaRemaining - 1;
|
||||||
|
|
||||||
|
if (displaceIfPossible(world, x, y, z - 1)) {
|
||||||
|
world.setBlock(x, y, z - 1, 0);
|
||||||
|
}
|
||||||
|
if (displaceIfPossible(world, x, y, z + 1)) {
|
||||||
|
world.setBlock(x, y, z + 1, 0);
|
||||||
|
}
|
||||||
|
if (displaceIfPossible(world, x - 1, y, z)) {
|
||||||
|
world.setBlock(x - 1, y, z, 0);
|
||||||
|
}
|
||||||
|
if (displaceIfPossible(world, x + 1, y, z)) {
|
||||||
|
world.setBlock(x + 1, y, z, 0);
|
||||||
|
}
|
||||||
|
int north = getQuantaValueBelow(world, x, y, z - 1, lowerthan);
|
||||||
|
int south = getQuantaValueBelow(world, x, y, z + 1, lowerthan);
|
||||||
|
int west = getQuantaValueBelow(world, x - 1, y, z, lowerthan);
|
||||||
|
int east = getQuantaValueBelow(world, x + 1, y, z, lowerthan);
|
||||||
|
int total = quantaRemaining;
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
if (north >= 0) {
|
||||||
|
++count;
|
||||||
|
total += north;
|
||||||
|
}
|
||||||
|
if (south >= 0) {
|
||||||
|
++count;
|
||||||
|
total += south;
|
||||||
|
}
|
||||||
|
if (west >= 0) {
|
||||||
|
++count;
|
||||||
|
total += west;
|
||||||
|
}
|
||||||
|
if (east >= 0) {
|
||||||
|
++count;
|
||||||
|
total += east;
|
||||||
|
}
|
||||||
|
if (count == 1) {
|
||||||
|
if (changed) {
|
||||||
|
world.setBlockMetadataWithNotify(x, y, z, quantaRemaining - 1, 2);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int each = total / count;
|
||||||
|
int rem = total % count;
|
||||||
|
if (north >= 0) {
|
||||||
|
int newnorth = each;
|
||||||
|
|
||||||
|
if (rem == count || rem > 1 && rand.nextInt(count - rem) != 0) {
|
||||||
|
++newnorth;
|
||||||
|
--rem;
|
||||||
|
}
|
||||||
|
if (newnorth != north) {
|
||||||
|
if (newnorth == 0) {
|
||||||
|
world.setBlock(x, y, z - 1, 0);
|
||||||
|
} else {
|
||||||
|
world.setBlock(x, y, z - 1, blockID, newnorth - 1, 2);
|
||||||
|
}
|
||||||
|
world.scheduleBlockUpdate(x, y, z - 1, blockID, tickRate);
|
||||||
|
}
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
if (south >= 0) {
|
||||||
|
int newsouth = each;
|
||||||
|
|
||||||
|
if (rem == count || rem > 1 && rand.nextInt(count - rem) != 0) {
|
||||||
|
++newsouth;
|
||||||
|
--rem;
|
||||||
|
}
|
||||||
|
if (newsouth != south) {
|
||||||
|
if (newsouth == 0) {
|
||||||
|
world.setBlock(x, y, z + 1, 0);
|
||||||
|
} else {
|
||||||
|
world.setBlock(x, y, z + 1, blockID, newsouth - 1, 2);
|
||||||
|
}
|
||||||
|
world.scheduleBlockUpdate(x, y, z + 1, blockID, tickRate);
|
||||||
|
}
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
if (west >= 0) {
|
||||||
|
int newwest = each;
|
||||||
|
|
||||||
|
if (rem == count || rem > 1 && rand.nextInt(count - rem) != 0) {
|
||||||
|
++newwest;
|
||||||
|
--rem;
|
||||||
|
}
|
||||||
|
if (newwest != west) {
|
||||||
|
if (newwest == 0) {
|
||||||
|
world.setBlock(x - 1, y, z, 0);
|
||||||
|
} else {
|
||||||
|
world.setBlock(x - 1, y, z, blockID, newwest - 1, 2);
|
||||||
|
}
|
||||||
|
world.scheduleBlockUpdate(x - 1, y, z, blockID, tickRate);
|
||||||
|
}
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
if (east >= 0) {
|
||||||
|
int neweast = each;
|
||||||
|
|
||||||
|
if (rem == count || rem > 1 && rand.nextInt(count - rem) != 0) {
|
||||||
|
++neweast;
|
||||||
|
--rem;
|
||||||
|
}
|
||||||
|
if (neweast != east) {
|
||||||
|
if (neweast == 0) {
|
||||||
|
world.setBlock(x + 1, y, z, 0);
|
||||||
|
} else {
|
||||||
|
world.setBlock(x + 1, y, z, blockID, neweast - 1, 2);
|
||||||
|
}
|
||||||
|
world.scheduleBlockUpdate(x + 1, y, z, blockID, tickRate);
|
||||||
|
}
|
||||||
|
--count;
|
||||||
|
}
|
||||||
|
if (rem > 0) {
|
||||||
|
++each;
|
||||||
|
}
|
||||||
|
world.setBlockMetadataWithNotify(x, y, z, each - 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int tryToFlowVerticallyInto(World world, int x, int y, int z, int amtToInput) {
|
||||||
|
|
||||||
|
int otherY = y + densityDir;
|
||||||
|
|
||||||
|
if (otherY < 0 || otherY >= world.getHeight()) {
|
||||||
|
world.setBlockToAir(x, y, z);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int amt = getQuantaValueBelow(world, x, otherY, z, quantaPerBlock);
|
||||||
|
|
||||||
|
if (amt >= 0) {
|
||||||
|
amt += amtToInput;
|
||||||
|
if (amt > quantaPerBlock) {
|
||||||
|
world.setBlock(x, otherY, z, blockID, quantaPerBlock - 1, 3);
|
||||||
|
world.scheduleBlockUpdate(x, otherY, z, blockID, tickRate);
|
||||||
|
return amt - quantaPerBlock;
|
||||||
|
} else if (amt > 0) {
|
||||||
|
world.setBlock(x, otherY, z, blockID, amt - 1, 3);
|
||||||
|
world.scheduleBlockUpdate(x, otherY, z, blockID, tickRate);
|
||||||
|
world.setBlockToAir(x, y, z);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return amtToInput;
|
||||||
|
} else {
|
||||||
|
int density_other = getDensity(world, x, otherY, z);
|
||||||
|
|
||||||
|
if (density_other == Integer.MAX_VALUE) {
|
||||||
|
if (displaceIfPossible(world, x, otherY, z)) {
|
||||||
|
world.setBlock(x, otherY, z, blockID, amtToInput - 1, 3);
|
||||||
|
world.scheduleBlockUpdate(x, otherY, z, blockID, tickRate);
|
||||||
|
world.setBlockToAir(x, y, z);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return amtToInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (densityDir < 0) {
|
||||||
|
if (density_other < density) // then swap
|
||||||
|
{
|
||||||
|
int bId = world.getBlockId(x, otherY, z);
|
||||||
|
BlockFluidBase block = (BlockFluidBase) Block.blocksList[bId];
|
||||||
|
int otherData = world.getBlockMetadata(x, otherY, z);
|
||||||
|
world.setBlock(x, otherY, z, blockID, amtToInput - 1, 3);
|
||||||
|
world.setBlock(x, y, z, bId, otherData, 3);
|
||||||
|
world.scheduleBlockUpdate(x, otherY, z, blockID, tickRate);
|
||||||
|
world.scheduleBlockUpdate(x, y, z, bId, block.tickRate(world));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (density_other > density) {
|
||||||
|
int bId = world.getBlockId(x, otherY, z);
|
||||||
|
BlockFluidBase block = (BlockFluidBase) Block.blocksList[bId];
|
||||||
|
int otherData = world.getBlockMetadata(x, otherY, z);
|
||||||
|
world.setBlock(x, otherY, z, blockID, amtToInput - 1, 3);
|
||||||
|
world.setBlock(x, y, z, bId, otherData, 3);
|
||||||
|
world.scheduleBlockUpdate(x, otherY, z, blockID, tickRate);
|
||||||
|
world.scheduleBlockUpdate(x, y, z, bId, block.tickRate(world));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return amtToInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidBlock */
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(World world, int x, int y, int z, boolean doDrain) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDrain(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
327
common/net/minecraftforge/fluids/Fluid.java
Normal file
327
common/net/minecraftforge/fluids/Fluid.java
Normal file
|
@ -0,0 +1,327 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.util.Icon;
|
||||||
|
import net.minecraft.util.StatCollector;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.ForgeDummyContainer;
|
||||||
|
import cpw.mods.fml.common.FMLLog;
|
||||||
|
import cpw.mods.fml.common.LoaderException;
|
||||||
|
import cpw.mods.fml.relauncher.Side;
|
||||||
|
import cpw.mods.fml.relauncher.SideOnly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Fluid {
|
||||||
|
|
||||||
|
/** The unique identification name for this fluid. */
|
||||||
|
protected final String fluidName;
|
||||||
|
|
||||||
|
/** The unlocalized name of this fluid. */
|
||||||
|
protected String unlocalizedName;
|
||||||
|
|
||||||
|
/** The Icons for this fluid. */
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
protected Icon stillIcon;
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
protected Icon flowingIcon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The light level emitted by this fluid.
|
||||||
|
*
|
||||||
|
* Default value is 0, as most fluids do not actively emit light.
|
||||||
|
*/
|
||||||
|
protected int luminosity = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
protected int density = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
protected int viscosity = 1000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This indicates if the fluid is gaseous.
|
||||||
|
*
|
||||||
|
* Useful for rendering the fluid in containers and the world.
|
||||||
|
*
|
||||||
|
* Generally this is associated with negative density fluids.
|
||||||
|
*/
|
||||||
|
protected boolean isGaseous;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If there is a Block implementation of the Fluid, the BlockID is linked here.
|
||||||
|
*
|
||||||
|
* The default value of -1 should remain for any Fluid without a Block implementation.
|
||||||
|
*/
|
||||||
|
protected int blockID = -1;
|
||||||
|
|
||||||
|
public Fluid(String fluidName) {
|
||||||
|
|
||||||
|
this.fluidName = fluidName.toLowerCase(Locale.ENGLISH);
|
||||||
|
this.unlocalizedName = fluidName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setUnlocalizedName(String unlocalizedName) {
|
||||||
|
|
||||||
|
this.unlocalizedName = unlocalizedName;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setBlockID(int blockID) {
|
||||||
|
|
||||||
|
if (this.blockID == -1 || this.blockID == blockID) {
|
||||||
|
this.blockID = blockID;
|
||||||
|
} else if (!ForgeDummyContainer.forceDuplicateFluidBlockCrash) {
|
||||||
|
FMLLog.warning("A mod has attempted to assign BlockID " + blockID + " to the Fluid '" + fluidName + "' but this Fluid has already been linked to BlockID "
|
||||||
|
+ this.blockID + ". Configure your mods to prevent this from happening.");
|
||||||
|
} else {
|
||||||
|
FMLLog.severe("A mod has attempted to assign BlockID " + blockID + " to the Fluid '" + fluidName + "' but this Fluid has already been linked to BlockID "
|
||||||
|
+ this.blockID + ". Configure your mods to prevent this from happening.");
|
||||||
|
throw new LoaderException(new RuntimeException("A mod has attempted to assign BlockID " + blockID + " to the Fluid '" + fluidName
|
||||||
|
+ "' but this Fluid has already been linked to BlockID " + this.blockID + ". Configure your mods to prevent this from happening."));
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setBlockID(Block block) {
|
||||||
|
|
||||||
|
return setBlockID(block.blockID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setLuminosity(int luminosity) {
|
||||||
|
|
||||||
|
this.luminosity = luminosity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setDensity(int density) {
|
||||||
|
|
||||||
|
this.density = density;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setViscosity(int viscosity) {
|
||||||
|
|
||||||
|
this.viscosity = viscosity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Fluid setGaseous(boolean isGaseous) {
|
||||||
|
|
||||||
|
this.isGaseous = isGaseous;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final String getName() {
|
||||||
|
|
||||||
|
return this.fluidName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getID() {
|
||||||
|
|
||||||
|
return FluidRegistry.getFluidID(this.fluidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getBlockID() {
|
||||||
|
|
||||||
|
return blockID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean canBePlacedInWorld() {
|
||||||
|
|
||||||
|
return blockID != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the localized name of this fluid.
|
||||||
|
*/
|
||||||
|
public String getLocalizedName() {
|
||||||
|
|
||||||
|
String s = this.getUnlocalizedName();
|
||||||
|
return s == null ? "" : StatCollector.translateToLocal(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unlocalized name of this fluid.
|
||||||
|
*/
|
||||||
|
public String getUnlocalizedName() {
|
||||||
|
|
||||||
|
return "fluid." + this.unlocalizedName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns 0 for "/terrain.png". ALL FLUID TEXTURES MUST BE ON THIS SHEET.
|
||||||
|
*/
|
||||||
|
public final int getSpriteNumber() {
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default Accessors */
|
||||||
|
public final int getLuminosity() {
|
||||||
|
|
||||||
|
return this.luminosity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getDensity() {
|
||||||
|
|
||||||
|
return this.density;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int getViscosity() {
|
||||||
|
|
||||||
|
return this.viscosity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isGaseous() {
|
||||||
|
|
||||||
|
return this.isGaseous;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor() {
|
||||||
|
|
||||||
|
return 0xFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stack-based Accessors */
|
||||||
|
public int getLuminosity(FluidStack stack) {
|
||||||
|
|
||||||
|
return getLuminosity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDensity(FluidStack stack) {
|
||||||
|
|
||||||
|
return getDensity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViscosity(FluidStack stack) {
|
||||||
|
|
||||||
|
return getViscosity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGaseous(FluidStack stack) {
|
||||||
|
|
||||||
|
return isGaseous();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(FluidStack stack) {
|
||||||
|
|
||||||
|
return getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* World-based Accessors */
|
||||||
|
public int getLuminosity(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return getLuminosity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDensity(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return getDensity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getViscosity(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return getViscosity();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGaseous(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return isGaseous();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getColor(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public final Fluid setStillIcon(Icon stillIcon) {
|
||||||
|
|
||||||
|
this.stillIcon = stillIcon;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public final Fluid setFlowingIcon(Icon flowingIcon) {
|
||||||
|
|
||||||
|
this.flowingIcon = flowingIcon;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public final Fluid setIcons(Icon stillIcon, Icon flowingIcon) {
|
||||||
|
|
||||||
|
this.stillIcon = stillIcon;
|
||||||
|
this.flowingIcon = flowingIcon;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public final Fluid setIcons(Icon commonIcon) {
|
||||||
|
|
||||||
|
this.stillIcon = commonIcon;
|
||||||
|
this.flowingIcon = commonIcon;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public Icon getIcon() {
|
||||||
|
|
||||||
|
return getStillIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public Icon getIcon(FluidStack stack) {
|
||||||
|
|
||||||
|
return getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public Icon getIcon(World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
return getIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public Icon getStillIcon() {
|
||||||
|
|
||||||
|
return this.stillIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SideOnly(Side.CLIENT)
|
||||||
|
public Icon getFlowingIcon() {
|
||||||
|
|
||||||
|
return this.flowingIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
260
common/net/minecraftforge/fluids/FluidContainerRegistry.java
Normal file
260
common/net/minecraftforge/fluids/FluidContainerRegistry.java
Normal file
|
@ -0,0 +1,260 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.Event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register simple items that contain fluids here. Useful for buckets, bottles, and things that have
|
||||||
|
* ID/metadata mappings.
|
||||||
|
*
|
||||||
|
* For more complex items, use {@link IFluidContainerItem} instead.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class FluidContainerRegistry {
|
||||||
|
|
||||||
|
private static Map<List, FluidContainerData> containerFluidMap = new HashMap();
|
||||||
|
private static Map<List, FluidContainerData> filledContainerMap = new HashMap();
|
||||||
|
private static Set<List> emptyContainers = new HashSet();
|
||||||
|
|
||||||
|
public static final int BUCKET_VOLUME = 1000;
|
||||||
|
public static final ItemStack EMPTY_BUCKET = new ItemStack(Item.bucketEmpty);
|
||||||
|
public static final ItemStack EMPTY_BOTTLE = new ItemStack(Item.glassBottle);
|
||||||
|
|
||||||
|
static {
|
||||||
|
registerFluidContainer(FluidRegistry.WATER, new ItemStack(Item.bucketWater), EMPTY_BUCKET);
|
||||||
|
registerFluidContainer(FluidRegistry.LAVA, new ItemStack(Item.bucketLava), EMPTY_BUCKET);
|
||||||
|
registerFluidContainer(FluidRegistry.WATER, new ItemStack(Item.potion), EMPTY_BOTTLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FluidContainerRegistry() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new fluid containing item.
|
||||||
|
*
|
||||||
|
* @param stack
|
||||||
|
* FluidStack containing the type and amount of the fluid stored in the item.
|
||||||
|
* @param filledContainer
|
||||||
|
* ItemStack representing the container when it is full.
|
||||||
|
* @param emptyContainer
|
||||||
|
* ItemStack representing the container when it is empty.
|
||||||
|
* @return True if container was successfully registered; false if it already is.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluidContainer(FluidStack stack, ItemStack filledContainer, ItemStack emptyContainer) {
|
||||||
|
|
||||||
|
return registerFluidContainer(new FluidContainerData(stack, filledContainer, emptyContainer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new fluid containing item. The item is assumed to hold 1000 mB of fluid. Also
|
||||||
|
* registers the Fluid if possible.
|
||||||
|
*
|
||||||
|
* @param fluid
|
||||||
|
* Fluid type that is stored in the item.
|
||||||
|
* @param filledContainer
|
||||||
|
* ItemStack representing the container when it is full.
|
||||||
|
* @param emptyContainer
|
||||||
|
* ItemStack representing the container when it is empty.
|
||||||
|
* @return True if container was successfully registered; false if it already is.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluidContainer(Fluid fluid, ItemStack filledContainer, ItemStack emptyContainer) {
|
||||||
|
|
||||||
|
if (!FluidRegistry.isFluidRegistered(fluid)) {
|
||||||
|
FluidRegistry.registerFluid(fluid);
|
||||||
|
}
|
||||||
|
return registerFluidContainer(new FluidStack(fluid, BUCKET_VOLUME), filledContainer, emptyContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new fluid containing item that does not have an empty container.
|
||||||
|
*
|
||||||
|
* @param stack
|
||||||
|
* FluidStack containing the type and amount of the fluid stored in the item.
|
||||||
|
* @param filledContainer
|
||||||
|
* ItemStack representing the container when it is full.
|
||||||
|
* @return True if container was successfully registered; false if it already is.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluidContainer(FluidStack stack, ItemStack filledContainer) {
|
||||||
|
|
||||||
|
return registerFluidContainer(new FluidContainerData(stack, filledContainer, null, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new fluid containing item that does not have an empty container. The item is
|
||||||
|
* assumed to hold 1000 mB of fluid. Also registers the Fluid if possible.
|
||||||
|
*
|
||||||
|
* @param fluid
|
||||||
|
* Fluid type that is stored in the item.
|
||||||
|
* @param filledContainer
|
||||||
|
* ItemStack representing the container when it is full.
|
||||||
|
* @return True if container was successfully registered; false if it already is.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluidContainer(Fluid fluid, ItemStack filledContainer) {
|
||||||
|
|
||||||
|
if (!FluidRegistry.isFluidRegistered(fluid)) {
|
||||||
|
FluidRegistry.registerFluid(fluid);
|
||||||
|
}
|
||||||
|
return registerFluidContainer(new FluidStack(fluid, BUCKET_VOLUME), filledContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new fluid containing item.
|
||||||
|
*
|
||||||
|
* @param data
|
||||||
|
* See {@link FluidContainerData}.
|
||||||
|
* @return True if container was successfully registered; false if it already is.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluidContainer(FluidContainerData data) {
|
||||||
|
|
||||||
|
if (isFilledContainer(data.filledContainer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
containerFluidMap.put(Arrays.asList(data.filledContainer.itemID, data.filledContainer.getItemDamage()), data);
|
||||||
|
|
||||||
|
if (data.emptyContainer != null) {
|
||||||
|
filledContainerMap.put(Arrays.asList(data.emptyContainer.itemID, data.emptyContainer.getItemDamage(), data.fluid.fluidID), data);
|
||||||
|
emptyContainers.add(Arrays.asList(data.emptyContainer.itemID, data.emptyContainer.getItemDamage()));
|
||||||
|
}
|
||||||
|
MinecraftForge.EVENT_BUS.post(new FluidContainerRegisterEvent(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines the fluid type and amount inside a container.
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* The fluid container.
|
||||||
|
* @return FluidStack representing stored fluid.
|
||||||
|
*/
|
||||||
|
public static FluidStack getFluidForFilledItem(ItemStack container) {
|
||||||
|
|
||||||
|
if (container == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FluidContainerData data = containerFluidMap.get(Arrays.asList(container.itemID, container.getItemDamage()));
|
||||||
|
return data == null ? null : data.fluid.copy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to fill an empty container with a fluid.
|
||||||
|
*
|
||||||
|
* NOTE: Returns null on fail, NOT the empty container.
|
||||||
|
*
|
||||||
|
* @param fluid
|
||||||
|
* FluidStack containing the type and amount of fluid to fill.
|
||||||
|
* @param container
|
||||||
|
* ItemStack representing the empty container.
|
||||||
|
* @return Filled container if successful, otherwise null.
|
||||||
|
*/
|
||||||
|
public static ItemStack fillFluidContainer(FluidStack fluid, ItemStack container) {
|
||||||
|
|
||||||
|
if (container == null || fluid == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FluidContainerData data = filledContainerMap.get(Arrays.asList(container.itemID, container.getItemDamage(), fluid.fluidID));
|
||||||
|
if (data != null && fluid.amount >= data.fluid.amount) {
|
||||||
|
return data.filledContainer.copy();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if a container holds a specific fluid.
|
||||||
|
*/
|
||||||
|
public static boolean containsFluid(ItemStack container, FluidStack fluid) {
|
||||||
|
|
||||||
|
if (container == null || fluid == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FluidContainerData data = filledContainerMap.get(Arrays.asList(container.itemID, container.getItemDamage(), fluid.fluidID));
|
||||||
|
return data == null ? false : data.fluid.isFluidEqual(fluid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isBucket(ItemStack container) {
|
||||||
|
|
||||||
|
if (container == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (container.isItemEqual(EMPTY_BUCKET)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
FluidContainerData data = containerFluidMap.get(Arrays.asList(container.itemID, container.getItemDamage()));
|
||||||
|
return data != null && data.emptyContainer.isItemEqual(EMPTY_BUCKET);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isContainer(ItemStack container) {
|
||||||
|
|
||||||
|
return isEmptyContainer(container) || isFilledContainer(container);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isEmptyContainer(ItemStack container) {
|
||||||
|
|
||||||
|
return container != null && emptyContainers.contains(Arrays.asList(container.itemID, container.getItemDamage()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFilledContainer(ItemStack container) {
|
||||||
|
|
||||||
|
return container != null && getFluidForFilledItem(container) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FluidContainerData[] getRegisteredFluidContainerData() {
|
||||||
|
|
||||||
|
return (FluidContainerData[]) containerFluidMap.values().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class for the registry entries. Ensures that none of the attempted registrations
|
||||||
|
* contain null references unless permitted.
|
||||||
|
*/
|
||||||
|
public static class FluidContainerData {
|
||||||
|
|
||||||
|
public final FluidStack fluid;
|
||||||
|
public final ItemStack filledContainer;
|
||||||
|
public final ItemStack emptyContainer;
|
||||||
|
|
||||||
|
public FluidContainerData(FluidStack stack, ItemStack filledContainer, ItemStack emptyContainer) {
|
||||||
|
|
||||||
|
this(stack, filledContainer, emptyContainer, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidContainerData(FluidStack stack, ItemStack filledContainer, ItemStack emptyContainer, boolean nullEmpty) {
|
||||||
|
|
||||||
|
this.fluid = stack;
|
||||||
|
this.filledContainer = filledContainer;
|
||||||
|
this.emptyContainer = emptyContainer;
|
||||||
|
|
||||||
|
if (stack == null || filledContainer == null || emptyContainer == null && !nullEmpty) {
|
||||||
|
throw new RuntimeException("Invalid FluidContainerData - a parameter was null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidContainerData copy() {
|
||||||
|
|
||||||
|
return new FluidContainerData(fluid, filledContainer, emptyContainer, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FluidContainerRegisterEvent extends Event {
|
||||||
|
|
||||||
|
public final FluidContainerData data;
|
||||||
|
|
||||||
|
public FluidContainerRegisterEvent(FluidContainerData data) {
|
||||||
|
|
||||||
|
this.data = data.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
100
common/net/minecraftforge/fluids/FluidEvent.java
Normal file
100
common/net/minecraftforge/fluids/FluidEvent.java
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.Event;
|
||||||
|
|
||||||
|
public class FluidEvent extends Event {
|
||||||
|
|
||||||
|
public final FluidStack fluid;
|
||||||
|
public final int x;
|
||||||
|
public final int y;
|
||||||
|
public final int z;
|
||||||
|
public final World world;
|
||||||
|
|
||||||
|
public FluidEvent(FluidStack fluid, World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
this.fluid = fluid;
|
||||||
|
this.world = world;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mods should fire this event when they move fluids around.
|
||||||
|
*
|
||||||
|
* @author cpw
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class FluidMotionEvent extends FluidEvent {
|
||||||
|
|
||||||
|
public FluidMotionEvent(FluidStack fluid, World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
super(fluid, world, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mods should fire this event when a fluid is {@link IFluidTank#fill(FluidStack, boolean)}
|
||||||
|
* their tank implementation. {@link FluidTank} does.
|
||||||
|
*
|
||||||
|
* @author cpw
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class FluidFillingEvent extends FluidEvent {
|
||||||
|
|
||||||
|
public final IFluidTank tank;
|
||||||
|
|
||||||
|
public FluidFillingEvent(FluidStack fluid, World world, int x, int y, int z, IFluidTank tank) {
|
||||||
|
|
||||||
|
super(fluid, world, x, y, z);
|
||||||
|
this.tank = tank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mods should fire this event when a fluid is {@link IFluidTank#drain(int, boolean)} from their
|
||||||
|
* tank.
|
||||||
|
*
|
||||||
|
* @author cpw
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class FluidDrainingEvent extends FluidEvent {
|
||||||
|
|
||||||
|
public final IFluidTank tank;
|
||||||
|
|
||||||
|
public FluidDrainingEvent(FluidStack fluid, World world, int x, int y, int z, IFluidTank tank) {
|
||||||
|
|
||||||
|
super(fluid, world, x, y, z);
|
||||||
|
this.tank = tank;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mods should fire this event when a fluid "spills", for example, if a block containing fluid
|
||||||
|
* is broken.
|
||||||
|
*
|
||||||
|
* @author cpw
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static class FluidSpilledEvent extends FluidEvent {
|
||||||
|
|
||||||
|
public FluidSpilledEvent(FluidStack fluid, World world, int x, int y, int z) {
|
||||||
|
|
||||||
|
super(fluid, world, x, y, z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A handy shortcut for firing the various fluid events.
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
public static final void fireEvent(FluidEvent event) {
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.post(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
52
common/net/minecraftforge/fluids/FluidIdMapPacket.java
Normal file
52
common/net/minecraftforge/fluids/FluidIdMapPacket.java
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
|
import net.minecraft.network.INetworkManager;
|
||||||
|
import net.minecraftforge.common.network.ForgePacket;
|
||||||
|
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.google.common.io.ByteArrayDataInput;
|
||||||
|
import com.google.common.io.ByteArrayDataOutput;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
|
||||||
|
public class FluidIdMapPacket extends ForgePacket {
|
||||||
|
|
||||||
|
private BiMap<String, Integer> fluidIds = HashBiMap.create();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] generatePacket() {
|
||||||
|
|
||||||
|
ByteArrayDataOutput dat = ByteStreams.newDataOutput();
|
||||||
|
|
||||||
|
dat.writeInt(FluidRegistry.maxID);
|
||||||
|
for (Map.Entry<String, Integer> entry : FluidRegistry.fluidIDs.entrySet()) {
|
||||||
|
dat.writeUTF(entry.getKey());
|
||||||
|
dat.writeInt(entry.getValue());
|
||||||
|
}
|
||||||
|
return dat.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ForgePacket consumePacket(byte[] data) {
|
||||||
|
|
||||||
|
ByteArrayDataInput dat = ByteStreams.newDataInput(data);
|
||||||
|
int listSize = dat.readInt();
|
||||||
|
for (int i = 0; i < listSize; i++) {
|
||||||
|
String fluidName = dat.readUTF();
|
||||||
|
int fluidId = dat.readInt();
|
||||||
|
fluidIds.put(fluidName, fluidId);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(INetworkManager network, EntityPlayer player) {
|
||||||
|
|
||||||
|
FluidRegistry.initFluidIDs(fluidIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
142
common/net/minecraftforge/fluids/FluidRegistry.java
Normal file
142
common/net/minecraftforge/fluids/FluidRegistry.java
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.Event;
|
||||||
|
|
||||||
|
import com.google.common.collect.BiMap;
|
||||||
|
import com.google.common.collect.HashBiMap;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles Fluid registrations. Fluids MUST be registered in order to function.
|
||||||
|
*
|
||||||
|
* @author King Lemming, CovertJaguar (LiquidDictionary)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class FluidRegistry {
|
||||||
|
|
||||||
|
static int maxID = 0;
|
||||||
|
|
||||||
|
static HashMap<String, Fluid> fluids = new HashMap();
|
||||||
|
static BiMap<String, Integer> fluidIDs = HashBiMap.create();
|
||||||
|
|
||||||
|
public static final Fluid WATER = new Fluid("water").setBlockID(Block.waterStill.blockID);
|
||||||
|
public static final Fluid LAVA = new Fluid("lava").setBlockID(Block.lavaStill.blockID).setLuminosity(15).setDensity(3000).setViscosity(6000);
|
||||||
|
|
||||||
|
public static int renderIdFluid = -1;
|
||||||
|
|
||||||
|
static {
|
||||||
|
registerFluid(WATER);
|
||||||
|
registerFluid(LAVA);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FluidRegistry() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by Forge to prepare the ID map for server -> client sync.
|
||||||
|
*/
|
||||||
|
static void initFluidIDs(BiMap<String, Integer> newfluidIDs) {
|
||||||
|
|
||||||
|
maxID = newfluidIDs.size();
|
||||||
|
fluidIDs.clear();
|
||||||
|
fluidIDs.putAll(newfluidIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a new Fluid. If a fluid with the same name already exists, registration is denied.
|
||||||
|
*
|
||||||
|
* @param fluid
|
||||||
|
* The fluid to register.
|
||||||
|
* @return True if the fluid was successfully registered; false if there is a name clash.
|
||||||
|
*/
|
||||||
|
public static boolean registerFluid(Fluid fluid) {
|
||||||
|
|
||||||
|
if (fluidIDs.containsKey(fluid.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fluids.put(fluid.getName(), fluid);
|
||||||
|
fluidIDs.put(fluid.getName(), ++maxID);
|
||||||
|
|
||||||
|
MinecraftForge.EVENT_BUS.post(new FluidRegisterEvent(fluid.getName(), maxID));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFluidRegistered(Fluid fluid) {
|
||||||
|
|
||||||
|
return fluidIDs.containsKey(fluid.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFluidRegistered(String fluidName) {
|
||||||
|
|
||||||
|
return fluidIDs.containsKey(fluidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Fluid getFluid(String fluidName) {
|
||||||
|
|
||||||
|
return fluids.get(fluidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Fluid getFluid(int fluidID) {
|
||||||
|
|
||||||
|
return fluids.get(getFluidName(fluidID));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFluidName(int fluidID) {
|
||||||
|
|
||||||
|
return fluidIDs.inverse().get(fluidID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getFluidName(FluidStack stack) {
|
||||||
|
|
||||||
|
return getFluidName(stack.fluidID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getFluidID(String fluidName) {
|
||||||
|
|
||||||
|
return fluidIDs.get(fluidName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FluidStack getFluidStack(String fluidName, int amount) {
|
||||||
|
|
||||||
|
if (!fluidIDs.containsKey(fluidName)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new FluidStack(getFluidID(fluidName), amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a read-only map containing Fluid Names and their associated Fluids.
|
||||||
|
*/
|
||||||
|
public static Map<String, Fluid> getRegisteredFluids() {
|
||||||
|
|
||||||
|
return ImmutableMap.copyOf(fluids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a read-only map containing Fluid Names and their associated IDs.
|
||||||
|
*/
|
||||||
|
public static Map<String, Integer> getRegisteredFluidIDs() {
|
||||||
|
|
||||||
|
return ImmutableMap.copyOf(fluidIDs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FluidRegisterEvent extends Event {
|
||||||
|
|
||||||
|
public final String fluidName;
|
||||||
|
public final int fluidID;
|
||||||
|
|
||||||
|
public FluidRegisterEvent(String fluidName, int fluidID) {
|
||||||
|
|
||||||
|
this.fluidName = fluidName;
|
||||||
|
this.fluidID = fluidID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
177
common/net/minecraftforge/fluids/FluidStack.java
Normal file
177
common/net/minecraftforge/fluids/FluidStack.java
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ItemStack substitute for Fluids.
|
||||||
|
*
|
||||||
|
* NOTE: Equality is based on the Fluid, not the amount. Use
|
||||||
|
* {@link #isFluidStackIdentical(FluidStack)} to determine if FluidID, Amount and NBT Tag are all
|
||||||
|
* equal.
|
||||||
|
*
|
||||||
|
* @author King Lemming, SirSengir (LiquidStack)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FluidStack {
|
||||||
|
|
||||||
|
public int fluidID;
|
||||||
|
public int amount;
|
||||||
|
public NBTTagCompound tag;
|
||||||
|
|
||||||
|
public FluidStack(Fluid fluid, int amount) {
|
||||||
|
|
||||||
|
this.fluidID = fluid.getID();
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack(int fluidID, int amount) {
|
||||||
|
|
||||||
|
this.fluidID = fluidID;
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack(int fluidID, int amount, NBTTagCompound nbt) {
|
||||||
|
|
||||||
|
this(fluidID, amount);
|
||||||
|
|
||||||
|
if (nbt != null) {
|
||||||
|
tag = (NBTTagCompound) nbt.copy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidStack(FluidStack stack, int amount) {
|
||||||
|
|
||||||
|
this(stack.fluidID, amount, stack.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This provides a safe method for retrieving a FluidStack - if the Fluid is invalid, the stack
|
||||||
|
* will return as null.
|
||||||
|
*/
|
||||||
|
public static FluidStack loadFluidStackFromNBT(NBTTagCompound nbt) {
|
||||||
|
|
||||||
|
if (nbt == null || FluidRegistry.getFluid(nbt.getString("FluidName")) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FluidStack stack = new FluidStack(FluidRegistry.getFluidID(nbt.getString("FluidName")), nbt.getInteger("Amount"));
|
||||||
|
|
||||||
|
if (nbt.hasKey("Tag")) {
|
||||||
|
stack.tag = nbt.getCompoundTag("Tag");
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
|
||||||
|
|
||||||
|
nbt.setString("FluidName", FluidRegistry.getFluidName(fluidID));
|
||||||
|
nbt.setInteger("Amount", amount);
|
||||||
|
|
||||||
|
if (tag != null) {
|
||||||
|
nbt.setTag("Tag", tag);
|
||||||
|
}
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final Fluid getFluid() {
|
||||||
|
|
||||||
|
return FluidRegistry.getFluid(fluidID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A copy of this FluidStack
|
||||||
|
*/
|
||||||
|
public FluidStack copy() {
|
||||||
|
|
||||||
|
return new FluidStack(fluidID, amount, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the FluidIDs and NBT Tags are equal. This does not check amounts.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* The FluidStack for comparison
|
||||||
|
* @return true if the Fluids (IDs and NBT Tags) are the same
|
||||||
|
*/
|
||||||
|
public boolean isFluidEqual(FluidStack other) {
|
||||||
|
|
||||||
|
return other != null && fluidID == other.fluidID && isFluidStackTagEqual(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFluidStackTagEqual(FluidStack other) {
|
||||||
|
|
||||||
|
return tag == null ? other.tag == null : other.tag == null ? false : tag.equals(other.tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the NBT Tags are equal. Useful if the FluidIDs are known to be equal.
|
||||||
|
*/
|
||||||
|
public static boolean areFluidStackTagsEqual(FluidStack stack1, FluidStack stack2) {
|
||||||
|
|
||||||
|
return stack1 == null && stack2 == null ? true : stack1 == null || stack2 == null ? false : stack1.isFluidStackTagEqual(stack2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the Fluids are equal and this stack is larger.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* @return true if this FluidStack contains the other FluidStack (same fluid and >= amount)
|
||||||
|
*/
|
||||||
|
public boolean containsFluid(FluidStack other) {
|
||||||
|
|
||||||
|
return isFluidEqual(other) && amount >= other.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the FluidIDs, Amounts, and NBT Tags are all equal.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* - the FluidStack for comparison
|
||||||
|
* @return true if the two FluidStacks are exactly the same
|
||||||
|
*/
|
||||||
|
public boolean isFluidStackIdentical(FluidStack other) {
|
||||||
|
|
||||||
|
return isFluidEqual(other) && amount == other.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the FluidIDs and NBT Tags are equal compared to a registered container
|
||||||
|
* ItemStack. This does not check amounts.
|
||||||
|
*
|
||||||
|
* @param other
|
||||||
|
* The ItemStack for comparison
|
||||||
|
* @return true if the Fluids (IDs and NBT Tags) are the same
|
||||||
|
*/
|
||||||
|
public boolean isFluidEqual(ItemStack other) {
|
||||||
|
|
||||||
|
if (other == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (other.getItem() instanceof IFluidContainerItem) {
|
||||||
|
return isFluidEqual(((IFluidContainerItem) other.getItem()).getFluid(other));
|
||||||
|
}
|
||||||
|
return isFluidEqual(FluidContainerRegistry.getFluidForFilledItem(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int hashCode() {
|
||||||
|
|
||||||
|
return fluidID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default equality comparison for a FluidStack. Same functionality as isFluidEqual().
|
||||||
|
*
|
||||||
|
* This is included for use in data structures.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public final boolean equals(Object o) {
|
||||||
|
|
||||||
|
if (!(o instanceof FluidStack)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return isFluidEqual((FluidStack) o);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
161
common/net/minecraftforge/fluids/FluidTank.java
Normal file
161
common/net/minecraftforge/fluids/FluidTank.java
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference implementation of {@link IFluidTank}. Use/extend this or implement your own.
|
||||||
|
*
|
||||||
|
* @author King Lemming, cpw (LiquidTank)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FluidTank implements IFluidTank {
|
||||||
|
|
||||||
|
protected FluidStack fluid;
|
||||||
|
protected int capacity;
|
||||||
|
protected TileEntity tile;
|
||||||
|
|
||||||
|
public FluidTank(int capacity) {
|
||||||
|
|
||||||
|
this(null, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidTank(FluidStack stack, int capacity) {
|
||||||
|
|
||||||
|
this.fluid = stack;
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidTank(Fluid fluid, int amount, int capacity) {
|
||||||
|
|
||||||
|
this(new FluidStack(fluid, amount), capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidTank readFromNBT(NBTTagCompound nbt) {
|
||||||
|
|
||||||
|
if (!nbt.hasKey("Empty")) {
|
||||||
|
FluidStack fluid = FluidStack.loadFluidStackFromNBT(nbt);
|
||||||
|
|
||||||
|
if (fluid != null) {
|
||||||
|
setFluid(fluid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
|
||||||
|
|
||||||
|
if (fluid != null) {
|
||||||
|
fluid.writeToNBT(nbt);
|
||||||
|
} else {
|
||||||
|
nbt.setString("Empty", "");
|
||||||
|
}
|
||||||
|
return nbt;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFluid(FluidStack fluid) {
|
||||||
|
|
||||||
|
this.fluid = fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCapacity(int capacity) {
|
||||||
|
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidTank */
|
||||||
|
@Override
|
||||||
|
public FluidStack getFluid() {
|
||||||
|
|
||||||
|
return fluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getFluidAmount() {
|
||||||
|
|
||||||
|
if (fluid == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return fluid.amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCapacity() {
|
||||||
|
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidTankInfo getInfo() {
|
||||||
|
|
||||||
|
return new FluidTankInfo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(FluidStack resource, boolean doFill) {
|
||||||
|
|
||||||
|
if (resource == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!doFill) {
|
||||||
|
if (fluid == null) {
|
||||||
|
return Math.min(capacity, resource.amount);
|
||||||
|
}
|
||||||
|
if (!fluid.isFluidEqual(resource)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.min(capacity - fluid.amount, resource.amount);
|
||||||
|
}
|
||||||
|
if (fluid == null) {
|
||||||
|
fluid = new FluidStack(resource, Math.min(capacity, resource.amount));
|
||||||
|
|
||||||
|
if (tile != null) {
|
||||||
|
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.worldObj, tile.xCoord, tile.yCoord, tile.zCoord, this));
|
||||||
|
}
|
||||||
|
return fluid.amount;
|
||||||
|
}
|
||||||
|
if (!fluid.isFluidEqual(resource)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int filled = capacity - fluid.amount;
|
||||||
|
|
||||||
|
if (resource.amount < filled) {
|
||||||
|
fluid.amount += resource.amount;
|
||||||
|
filled = resource.amount;
|
||||||
|
} else {
|
||||||
|
fluid.amount = capacity;
|
||||||
|
}
|
||||||
|
if (tile != null) {
|
||||||
|
FluidEvent.fireEvent(new FluidEvent.FluidFillingEvent(fluid, tile.worldObj, tile.xCoord, tile.yCoord, tile.zCoord, this));
|
||||||
|
}
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(int maxDrain, boolean doDrain) {
|
||||||
|
|
||||||
|
if (fluid == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int drained = maxDrain;
|
||||||
|
|
||||||
|
if (fluid.amount < drained) {
|
||||||
|
drained = fluid.amount;
|
||||||
|
}
|
||||||
|
FluidStack stack = new FluidStack(fluid, drained);
|
||||||
|
|
||||||
|
if (doDrain) {
|
||||||
|
fluid.amount -= drained;
|
||||||
|
|
||||||
|
if (fluid.amount <= 0) {
|
||||||
|
fluid = null;
|
||||||
|
}
|
||||||
|
if (tile != null) {
|
||||||
|
FluidEvent.fireEvent(new FluidEvent.FluidDrainingEvent(fluid, tile.worldObj, tile.xCoord, tile.yCoord, tile.zCoord, this));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
27
common/net/minecraftforge/fluids/FluidTankInfo.java
Normal file
27
common/net/minecraftforge/fluids/FluidTankInfo.java
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrapper class used to encapsulate information about an IFluidTank.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class FluidTankInfo {
|
||||||
|
|
||||||
|
public final FluidStack fluid;
|
||||||
|
public final int capacity;
|
||||||
|
|
||||||
|
public FluidTankInfo(FluidStack fluid, int capacity) {
|
||||||
|
|
||||||
|
this.fluid = fluid;
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FluidTankInfo(IFluidTank tank) {
|
||||||
|
|
||||||
|
this.fluid = tank.getFluid();
|
||||||
|
this.capacity = tank.getCapacity();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
common/net/minecraftforge/fluids/IFluidBlock.java
Normal file
41
common/net/minecraftforge/fluids/IFluidBlock.java
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface on Block classes which represent world-placeable Fluids.
|
||||||
|
*
|
||||||
|
* NOTE: Using/extending the reference implementations {@link BlockFluidBase} is encouraged.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IFluidBlock {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Fluid associated with this Block.
|
||||||
|
*/
|
||||||
|
Fluid getFluid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to drain the block. This method should be called by devices such as pumps.
|
||||||
|
*
|
||||||
|
* NOTE: The block is intended to handle its own state changes.
|
||||||
|
*
|
||||||
|
* @param doDrain
|
||||||
|
* If false, the drain will only be simulated.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
FluidStack drain(World world, int x, int y, int z, boolean doDrain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check to see if a block can be drained. This method should be called by devices such as
|
||||||
|
* pumps.
|
||||||
|
*
|
||||||
|
* @param doDrain
|
||||||
|
* If false, the drain will only be simulated.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
boolean canDrain(World world, int x, int y, int z);
|
||||||
|
}
|
61
common/net/minecraftforge/fluids/IFluidContainerItem.java
Normal file
61
common/net/minecraftforge/fluids/IFluidContainerItem.java
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface on Item classes that support external manipulation of their internal
|
||||||
|
* fluid storage.
|
||||||
|
*
|
||||||
|
* A reference implementation is provided {@link ItemFluidContainer}.
|
||||||
|
*
|
||||||
|
* NOTE: Use of NBT data on the containing ItemStack is encouraged.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IFluidContainerItem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* ItemStack which is the fluid container.
|
||||||
|
* @return FluidStack representing the fluid in the container, null if the container is empty.
|
||||||
|
*/
|
||||||
|
FluidStack getFluid(ItemStack container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* ItemStack which is the fluid container.
|
||||||
|
* @return Capacity of this fluid container.
|
||||||
|
*/
|
||||||
|
int getCapacity(ItemStack container);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* ItemStack which is the fluid container.
|
||||||
|
* @param resource
|
||||||
|
* FluidStack attempting to fill the container.
|
||||||
|
* @param doFill
|
||||||
|
* If false, the fill will only be simulated.
|
||||||
|
* @return Amount of fluid that was (or would have been, if simulated) filled into the
|
||||||
|
* container.
|
||||||
|
*/
|
||||||
|
int fill(ItemStack container, FluidStack resource, boolean doFill);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param container
|
||||||
|
* ItemStack which is the fluid container.
|
||||||
|
* @param maxDrain
|
||||||
|
* Maximum amount of fluid to be removed from the container.
|
||||||
|
* @param doFill
|
||||||
|
* If false, the drain will only be simulated.
|
||||||
|
* @return Amount of fluid that was (or would have been, if simulated) drained from the
|
||||||
|
* container.
|
||||||
|
*/
|
||||||
|
FluidStack drain(ItemStack container, int maxDrain, boolean doDrain);
|
||||||
|
|
||||||
|
}
|
84
common/net/minecraftforge/fluids/IFluidHandler.java
Normal file
84
common/net/minecraftforge/fluids/IFluidHandler.java
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraftforge.common.ForgeDirection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implement this interface on TileEntities which should handle fluids, generally storing them in
|
||||||
|
* one or more internal {@link IFluidTank} objects.
|
||||||
|
*
|
||||||
|
* A reference implementation is provided {@link TileFluidHandler}.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IFluidHandler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fills fluid into internal tanks, distribution is left entirely to the IFluidHandler.
|
||||||
|
*
|
||||||
|
* @param from
|
||||||
|
* Orientation the Fluid is pumped in from.
|
||||||
|
* @param resource
|
||||||
|
* FluidStack representing the Fluid and maximum amount of fluid to be filled.
|
||||||
|
* @param doFill
|
||||||
|
* If false, fill will only be simulated.
|
||||||
|
* @return Amount of resource that was (or would have been, if simulated) filled.
|
||||||
|
*/
|
||||||
|
int fill(ForgeDirection from, FluidStack resource, boolean doFill);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
|
||||||
|
*
|
||||||
|
* @param from
|
||||||
|
* Orientation the Fluid is drained to.
|
||||||
|
* @param resource
|
||||||
|
* FluidStack representing the Fluid and maximum amount of fluid to be drained.
|
||||||
|
* @param doDrain
|
||||||
|
* If false, drain will only be simulated.
|
||||||
|
* @return FluidStack representing the Fluid and amount that was (or would have been, if
|
||||||
|
* simulated) drained.
|
||||||
|
*/
|
||||||
|
FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Drains fluid out of internal tanks, distribution is left entirely to the IFluidHandler.
|
||||||
|
*
|
||||||
|
* This method is not Fluid-sensitive.
|
||||||
|
*
|
||||||
|
* @param from
|
||||||
|
* Orientation the fluid is drained to.
|
||||||
|
* @param maxDrain
|
||||||
|
* Maximum amount of fluid to drain.
|
||||||
|
* @param doDrain
|
||||||
|
* If false, drain will only be simulated.
|
||||||
|
* @return FluidStack representing the Fluid and amount that was (or would have been, if
|
||||||
|
* simulated) drained.
|
||||||
|
*/
|
||||||
|
FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given fluid can be inserted into the given direction.
|
||||||
|
*
|
||||||
|
* More formally, this should return true if fluid is able to enter from the given direction.
|
||||||
|
*/
|
||||||
|
boolean canFill(ForgeDirection from, Fluid fluid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given fluid can be extracted from the given direction.
|
||||||
|
*
|
||||||
|
* More formally, this should return true if fluid is able to leave from the given direction.
|
||||||
|
*/
|
||||||
|
boolean canDrain(ForgeDirection from, Fluid fluid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of objects which represent the internal tanks. These objects cannot be used
|
||||||
|
* to manipulate the internal tanks. See {@link FluidTankInfo}.
|
||||||
|
*
|
||||||
|
* @param from
|
||||||
|
* Orientation determining which tanks should be queried.
|
||||||
|
* @return Info for the relevant internal tanks.
|
||||||
|
*/
|
||||||
|
FluidTankInfo[] getTankInfo(ForgeDirection from);
|
||||||
|
|
||||||
|
}
|
59
common/net/minecraftforge/fluids/IFluidTank.java
Normal file
59
common/net/minecraftforge/fluids/IFluidTank.java
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A tank is the unit of interaction with Fluid inventories.
|
||||||
|
*
|
||||||
|
* A reference implementation can be found at {@link FluidTank}.
|
||||||
|
*
|
||||||
|
* @author King Lemming, cpw (ILiquidTank)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface IFluidTank {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return FluidStack representing the fluid in the tank, null if the tank is empty.
|
||||||
|
*/
|
||||||
|
FluidStack getFluid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Current amount of fluid in the tank.
|
||||||
|
*/
|
||||||
|
int getFluidAmount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Capacity of this fluid tank.
|
||||||
|
*/
|
||||||
|
int getCapacity();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a wrapper object {@link FluidTankInfo } containing the capacity of the tank and the
|
||||||
|
* FluidStack it holds.
|
||||||
|
*
|
||||||
|
* Should prevent manipulation of the IFluidTank. See {@link FluidTank}.
|
||||||
|
*
|
||||||
|
* @return State information for the IFluidTank.
|
||||||
|
*/
|
||||||
|
FluidTankInfo getInfo();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param resource
|
||||||
|
* FluidStack attempting to fill the tank.
|
||||||
|
* @param doFill
|
||||||
|
* If false, the fill will only be simulated.
|
||||||
|
* @return Amount of fluid that was accepted by the tank.
|
||||||
|
*/
|
||||||
|
int fill(FluidStack resource, boolean doFill);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param maxDrain
|
||||||
|
* Maximum amount of fluid to be removed from the container.
|
||||||
|
* @param doFill
|
||||||
|
* If false, the fill will only be simulated.
|
||||||
|
* @return Amount of fluid that was removed from the tank.
|
||||||
|
*/
|
||||||
|
FluidStack drain(int maxDrain, boolean doDrain);
|
||||||
|
|
||||||
|
}
|
132
common/net/minecraftforge/fluids/ItemFluidContainer.java
Normal file
132
common/net/minecraftforge/fluids/ItemFluidContainer.java
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.item.Item;
|
||||||
|
import net.minecraft.item.ItemStack;
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference implementation of {@link IFluidContainerItem}. Use/extend this or implement your own.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ItemFluidContainer extends Item implements IFluidContainerItem {
|
||||||
|
|
||||||
|
protected int capacity;
|
||||||
|
|
||||||
|
public ItemFluidContainer(int itemID) {
|
||||||
|
|
||||||
|
super(itemID);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemFluidContainer(int itemID, int capacity) {
|
||||||
|
|
||||||
|
super(itemID);
|
||||||
|
this.capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemFluidContainer setCapacity(int capacity) {
|
||||||
|
|
||||||
|
this.capacity = capacity;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidContainerItem */
|
||||||
|
@Override
|
||||||
|
public FluidStack getFluid(ItemStack container) {
|
||||||
|
|
||||||
|
if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Fluid")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return FluidStack.loadFluidStackFromNBT(container.stackTagCompound.getCompoundTag("Fluid"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCapacity(ItemStack container) {
|
||||||
|
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int fill(ItemStack container, FluidStack resource, boolean doFill) {
|
||||||
|
|
||||||
|
if (resource == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!doFill) {
|
||||||
|
if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Fluid")) {
|
||||||
|
return Math.min(capacity, resource.amount);
|
||||||
|
}
|
||||||
|
FluidStack stack = FluidStack.loadFluidStackFromNBT(container.stackTagCompound.getCompoundTag("Fluid"));
|
||||||
|
|
||||||
|
if (stack == null) {
|
||||||
|
return Math.min(capacity, resource.amount);
|
||||||
|
}
|
||||||
|
if (!stack.isFluidEqual(resource)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.min(capacity - stack.amount, resource.amount);
|
||||||
|
}
|
||||||
|
if (container.stackTagCompound == null) {
|
||||||
|
container.stackTagCompound = new NBTTagCompound();
|
||||||
|
}
|
||||||
|
if (!container.stackTagCompound.hasKey("Fluid")) {
|
||||||
|
NBTTagCompound fluidTag = resource.writeToNBT(new NBTTagCompound());
|
||||||
|
|
||||||
|
if (capacity < resource.amount) {
|
||||||
|
fluidTag.setInteger("Amount", capacity);
|
||||||
|
container.stackTagCompound.setTag("Fluid", fluidTag);
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
container.stackTagCompound.setTag("Fluid", fluidTag);
|
||||||
|
return resource.amount;
|
||||||
|
}
|
||||||
|
NBTTagCompound fluidTag = container.stackTagCompound.getCompoundTag("Fluid");
|
||||||
|
FluidStack stack = FluidStack.loadFluidStackFromNBT(fluidTag);
|
||||||
|
|
||||||
|
if (!stack.isFluidEqual(resource)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int filled = capacity - resource.amount;
|
||||||
|
|
||||||
|
if (resource.amount < filled) {
|
||||||
|
stack.amount += resource.amount;
|
||||||
|
filled = resource.amount;
|
||||||
|
} else {
|
||||||
|
stack.amount = capacity;
|
||||||
|
}
|
||||||
|
container.stackTagCompound.setTag("Fluid", stack.writeToNBT(fluidTag));
|
||||||
|
return filled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(ItemStack container, int maxDrain, boolean doDrain) {
|
||||||
|
|
||||||
|
if (container.stackTagCompound == null || !container.stackTagCompound.hasKey("Fluid")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
FluidStack stack = FluidStack.loadFluidStackFromNBT(container.stackTagCompound.getCompoundTag("Fluid"));
|
||||||
|
|
||||||
|
if (stack == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
stack.amount = Math.min(stack.amount, maxDrain);
|
||||||
|
|
||||||
|
if (doDrain) {
|
||||||
|
if (maxDrain >= capacity) {
|
||||||
|
container.stackTagCompound.removeTag("Fluid");
|
||||||
|
|
||||||
|
if (container.stackTagCompound.hasNoTags()) {
|
||||||
|
container.stackTagCompound = null;
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
NBTTagCompound fluidTag = container.stackTagCompound.getCompoundTag("Fluid");
|
||||||
|
fluidTag.setInteger("Amount", fluidTag.getInteger("Amount") - maxDrain);
|
||||||
|
container.stackTagCompound.setTag("Fluid", fluidTag);
|
||||||
|
}
|
||||||
|
return stack;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
290
common/net/minecraftforge/fluids/RenderBlockFluid.java
Normal file
290
common/net/minecraftforge/fluids/RenderBlockFluid.java
Normal file
|
@ -0,0 +1,290 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.client.renderer.RenderBlocks;
|
||||||
|
import net.minecraft.client.renderer.Tessellator;
|
||||||
|
import net.minecraft.util.Icon;
|
||||||
|
import net.minecraft.util.MathHelper;
|
||||||
|
import net.minecraft.world.IBlockAccess;
|
||||||
|
import cpw.mods.fml.client.registry.ISimpleBlockRenderingHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default renderer for Forge fluid blocks.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RenderBlockFluid implements ISimpleBlockRenderingHandler {
|
||||||
|
|
||||||
|
public static RenderBlockFluid instance = new RenderBlockFluid();
|
||||||
|
|
||||||
|
static final float LIGHT_Y_NEG = 0.5F;
|
||||||
|
static final float LIGHT_Y_POS = 1.0F;
|
||||||
|
static final float LIGHT_XZ_NEG = 0.8F;
|
||||||
|
static final float LIGHT_XZ_POS = 0.6F;
|
||||||
|
static final double RENDER_OFFSET = 0.0010000000474974513D;
|
||||||
|
|
||||||
|
public float getFluidHeightAverage(float[] flow) {
|
||||||
|
|
||||||
|
float total = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < flow.length; i++) {
|
||||||
|
if (flow[i] >= 0.875F) {
|
||||||
|
return flow[i];
|
||||||
|
}
|
||||||
|
if (flow[i] >= 0) {
|
||||||
|
total += flow[i];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total / count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getFluidHeightForRender(IBlockAccess world, int x, int y, int z, BlockFluidBase block) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y, z) == block.blockID) {
|
||||||
|
|
||||||
|
if (world.getBlockId(x, y - block.densityDir, z) == block.blockID) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (world.getBlockMetadata(x, y, z) == block.getMaxRenderHeightMeta()) {
|
||||||
|
return 0.875F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !world.getBlockMaterial(x, y, z).isSolid() && world.getBlockId(x, y - block.densityDir, z) == block.blockID ? 1 : block.getQuantaPercentage(world, x, y, z) * 0.875F;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ISimpleBlockRenderingHandler */
|
||||||
|
@Override
|
||||||
|
public void renderInventoryBlock(Block block, int metadata, int modelID, RenderBlocks renderer) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean renderWorldBlock(IBlockAccess world, int x, int y, int z, Block block, int modelId, RenderBlocks renderer) {
|
||||||
|
|
||||||
|
if (!(block instanceof BlockFluidBase)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Tessellator tessellator = Tessellator.instance;
|
||||||
|
int color = block.colorMultiplier(world, x, y, z);
|
||||||
|
float red = (color >> 16 & 255) / 255.0F;
|
||||||
|
float green = (color >> 8 & 255) / 255.0F;
|
||||||
|
float blue = (color & 255) / 255.0F;
|
||||||
|
|
||||||
|
BlockFluidBase theFluid = (BlockFluidBase) block;
|
||||||
|
int bMeta = world.getBlockMetadata(x, y, z);
|
||||||
|
|
||||||
|
boolean renderTop = world.getBlockId(x, y - theFluid.densityDir, z) != theFluid.blockID;
|
||||||
|
|
||||||
|
boolean renderBottom = block.shouldSideBeRendered(world, x, y + theFluid.densityDir, z, 0) && world.getBlockId(x, y + theFluid.densityDir, z) != theFluid.blockID;
|
||||||
|
|
||||||
|
boolean[] renderSides = new boolean[] { block.shouldSideBeRendered(world, x, y, z - 1, 2), block.shouldSideBeRendered(world, x, y, z + 1, 3),
|
||||||
|
block.shouldSideBeRendered(world, x - 1, y, z, 4), block.shouldSideBeRendered(world, x + 1, y, z, 5) };
|
||||||
|
|
||||||
|
if (!renderTop && !renderBottom && !renderSides[0] && !renderSides[1] && !renderSides[2] && !renderSides[3]) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
boolean rendered = false;
|
||||||
|
|
||||||
|
double heightNW, heightSW, heightSE, heightNE;
|
||||||
|
|
||||||
|
float flow11 = getFluidHeightForRender(world, x, y, z, theFluid);
|
||||||
|
|
||||||
|
if (flow11 != 1) {
|
||||||
|
float flow00 = getFluidHeightForRender(world, x - 1, y, z - 1, theFluid);
|
||||||
|
float flow01 = getFluidHeightForRender(world, x - 1, y, z, theFluid);
|
||||||
|
float flow02 = getFluidHeightForRender(world, x - 1, y, z + 1, theFluid);
|
||||||
|
float flow10 = getFluidHeightForRender(world, x, y, z - 1, theFluid);
|
||||||
|
float flow12 = getFluidHeightForRender(world, x, y, z + 1, theFluid);
|
||||||
|
float flow20 = getFluidHeightForRender(world, x + 1, y, z - 1, theFluid);
|
||||||
|
float flow21 = getFluidHeightForRender(world, x + 1, y, z, theFluid);
|
||||||
|
float flow22 = getFluidHeightForRender(world, x + 1, y, z + 1, theFluid);
|
||||||
|
|
||||||
|
heightNW = getFluidHeightAverage(new float[] { flow00, flow01, flow10, flow11 });
|
||||||
|
heightSW = getFluidHeightAverage(new float[] { flow01, flow02, flow12, flow11 });
|
||||||
|
heightSE = getFluidHeightAverage(new float[] { flow12, flow21, flow22, flow11 });
|
||||||
|
heightNE = getFluidHeightAverage(new float[] { flow10, flow20, flow21, flow11 });
|
||||||
|
} else {
|
||||||
|
heightNW = flow11;
|
||||||
|
heightSW = flow11;
|
||||||
|
heightSE = flow11;
|
||||||
|
heightNE = flow11;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean rises = theFluid.densityDir == 1;
|
||||||
|
|
||||||
|
if (renderer.renderAllFaces || renderTop) {
|
||||||
|
rendered = true;
|
||||||
|
|
||||||
|
Icon iconStill = block.getIcon(1, bMeta);
|
||||||
|
float flowDir = (float) BlockFluidBase.getFlowDirection(world, x, y, z);
|
||||||
|
|
||||||
|
if (flowDir > -999.0F) {
|
||||||
|
iconStill = block.getIcon(2, bMeta);
|
||||||
|
}
|
||||||
|
heightNW -= RENDER_OFFSET;
|
||||||
|
heightSW -= RENDER_OFFSET;
|
||||||
|
heightSE -= RENDER_OFFSET;
|
||||||
|
heightNE -= RENDER_OFFSET;
|
||||||
|
|
||||||
|
double u1, u2, u3, u4, v1, v2, v3, v4;
|
||||||
|
|
||||||
|
if (flowDir < -999.0F) {
|
||||||
|
u2 = iconStill.getInterpolatedU(0.0D);
|
||||||
|
v2 = iconStill.getInterpolatedV(0.0D);
|
||||||
|
u1 = u2;
|
||||||
|
v1 = iconStill.getInterpolatedV(16.0D);
|
||||||
|
u4 = iconStill.getInterpolatedU(16.0D);
|
||||||
|
v4 = v1;
|
||||||
|
u3 = u4;
|
||||||
|
v3 = v2;
|
||||||
|
} else {
|
||||||
|
float xFlow = MathHelper.sin(flowDir) * 0.25F;
|
||||||
|
float zFlow = MathHelper.cos(flowDir) * 0.25F;
|
||||||
|
u2 = iconStill.getInterpolatedU(8.0F + (-zFlow - xFlow) * 16.0F);
|
||||||
|
v2 = iconStill.getInterpolatedV(8.0F + (-zFlow + xFlow) * 16.0F);
|
||||||
|
u1 = iconStill.getInterpolatedU(8.0F + (-zFlow + xFlow) * 16.0F);
|
||||||
|
v1 = iconStill.getInterpolatedV(8.0F + (zFlow + xFlow) * 16.0F);
|
||||||
|
u4 = iconStill.getInterpolatedU(8.0F + (zFlow + xFlow) * 16.0F);
|
||||||
|
v4 = iconStill.getInterpolatedV(8.0F + (zFlow - xFlow) * 16.0F);
|
||||||
|
u3 = iconStill.getInterpolatedU(8.0F + (zFlow - xFlow) * 16.0F);
|
||||||
|
v3 = iconStill.getInterpolatedV(8.0F + (-zFlow - xFlow) * 16.0F);
|
||||||
|
}
|
||||||
|
tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y, z));
|
||||||
|
tessellator.setColorOpaque_F(LIGHT_Y_POS * red, LIGHT_Y_POS * green, LIGHT_Y_POS * blue);
|
||||||
|
|
||||||
|
if (!rises) {
|
||||||
|
tessellator.addVertexWithUV(x + 0, y + heightNW, z + 0, u2, v2);
|
||||||
|
tessellator.addVertexWithUV(x + 0, y + heightSW, z + 1, u1, v1);
|
||||||
|
tessellator.addVertexWithUV(x + 1, y + heightSE, z + 1, u4, v4);
|
||||||
|
tessellator.addVertexWithUV(x + 1, y + heightNE, z + 0, u3, v3);
|
||||||
|
} else {
|
||||||
|
tessellator.addVertexWithUV(x + 1, y + 1 - heightNE, z + 0, u3, v3);
|
||||||
|
tessellator.addVertexWithUV(x + 1, y + 1 - heightSE, z + 1, u4, v4);
|
||||||
|
tessellator.addVertexWithUV(x + 0, y + 1 - heightSW, z + 1, u1, v1);
|
||||||
|
tessellator.addVertexWithUV(x + 0, y + 1 - heightNW, z + 0, u2, v2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (renderer.renderAllFaces || renderBottom) {
|
||||||
|
rendered = true;
|
||||||
|
|
||||||
|
tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y - 1, z));
|
||||||
|
|
||||||
|
if (!rises) {
|
||||||
|
tessellator.setColorOpaque_F(LIGHT_Y_NEG, LIGHT_Y_NEG, LIGHT_Y_NEG);
|
||||||
|
renderer.renderFaceYNeg(block, x, y + RENDER_OFFSET, z, block.getIcon(0, bMeta));
|
||||||
|
} else {
|
||||||
|
tessellator.setColorOpaque_F(LIGHT_Y_POS, LIGHT_Y_POS, LIGHT_Y_POS);
|
||||||
|
renderer.renderFaceYPos(block, x, y + RENDER_OFFSET, z, block.getIcon(1, bMeta));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int side = 0; side < 4; ++side) {
|
||||||
|
int x2 = x;
|
||||||
|
int z2 = z;
|
||||||
|
|
||||||
|
switch (side) {
|
||||||
|
case 0:
|
||||||
|
--z2;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
++z2;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
--x2;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
++x2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Icon iconFlow = block.getIcon(side + 2, bMeta);
|
||||||
|
|
||||||
|
if (renderer.renderAllFaces || renderSides[side]) {
|
||||||
|
rendered = true;
|
||||||
|
|
||||||
|
double ty1;
|
||||||
|
double tx1;
|
||||||
|
double ty2;
|
||||||
|
double tx2;
|
||||||
|
double tz1;
|
||||||
|
double tz2;
|
||||||
|
|
||||||
|
if (side == 0) {
|
||||||
|
ty1 = heightNW;
|
||||||
|
ty2 = heightNE;
|
||||||
|
tx1 = x;
|
||||||
|
tx2 = x + 1;
|
||||||
|
tz1 = z + RENDER_OFFSET;
|
||||||
|
tz2 = z + RENDER_OFFSET;
|
||||||
|
} else if (side == 1) {
|
||||||
|
ty1 = heightSE;
|
||||||
|
ty2 = heightSW;
|
||||||
|
tx1 = x + 1;
|
||||||
|
tx2 = x;
|
||||||
|
tz1 = z + 1 - RENDER_OFFSET;
|
||||||
|
tz2 = z + 1 - RENDER_OFFSET;
|
||||||
|
} else if (side == 2) {
|
||||||
|
ty1 = heightSW;
|
||||||
|
ty2 = heightNW;
|
||||||
|
tx1 = x + RENDER_OFFSET;
|
||||||
|
tx2 = x + RENDER_OFFSET;
|
||||||
|
tz1 = z + 1;
|
||||||
|
tz2 = z;
|
||||||
|
} else {
|
||||||
|
ty1 = heightNE;
|
||||||
|
ty2 = heightSE;
|
||||||
|
tx1 = x + 1 - RENDER_OFFSET;
|
||||||
|
tx2 = x + 1 - RENDER_OFFSET;
|
||||||
|
tz1 = z;
|
||||||
|
tz2 = z + 1;
|
||||||
|
}
|
||||||
|
float u1Flow = iconFlow.getInterpolatedU(0.0D);
|
||||||
|
float u2Flow = iconFlow.getInterpolatedU(8.0D);
|
||||||
|
float v1Flow = iconFlow.getInterpolatedV((1.0D - ty1) * 16.0D * 0.5D);
|
||||||
|
float v2Flow = iconFlow.getInterpolatedV((1.0D - ty2) * 16.0D * 0.5D);
|
||||||
|
float v3Flow = iconFlow.getInterpolatedV(8.0D);
|
||||||
|
tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x2, y, z2));
|
||||||
|
float sideLighting = 1.0F;
|
||||||
|
|
||||||
|
if (side < 2) {
|
||||||
|
sideLighting = LIGHT_XZ_NEG;
|
||||||
|
} else {
|
||||||
|
sideLighting = LIGHT_XZ_POS;
|
||||||
|
}
|
||||||
|
tessellator.setColorOpaque_F(LIGHT_Y_POS * sideLighting * red, LIGHT_Y_POS * sideLighting * green, LIGHT_Y_POS * sideLighting * blue);
|
||||||
|
|
||||||
|
if (!rises) {
|
||||||
|
tessellator.addVertexWithUV(tx1, y + ty1, tz1, u1Flow, v1Flow);
|
||||||
|
tessellator.addVertexWithUV(tx2, y + ty2, tz2, u2Flow, v2Flow);
|
||||||
|
tessellator.addVertexWithUV(tx2, y + 0, tz2, u2Flow, v3Flow);
|
||||||
|
tessellator.addVertexWithUV(tx1, y + 0, tz1, u1Flow, v3Flow);
|
||||||
|
} else {
|
||||||
|
tessellator.addVertexWithUV(tx1, y + 1 - 0, tz1, u1Flow, v3Flow);
|
||||||
|
tessellator.addVertexWithUV(tx2, y + 1 - 0, tz2, u2Flow, v3Flow);
|
||||||
|
tessellator.addVertexWithUV(tx2, y + 1 - ty2, tz2, u2Flow, v2Flow);
|
||||||
|
tessellator.addVertexWithUV(tx1, y + 1 - ty1, tz1, u1Flow, v1Flow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderer.renderMinY = 0;
|
||||||
|
renderer.renderMaxY = 1;
|
||||||
|
return rendered;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean shouldRender3DInInventory() {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRenderId() {
|
||||||
|
|
||||||
|
return FluidRegistry.renderIdFluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
72
common/net/minecraftforge/fluids/TileFluidHandler.java
Normal file
72
common/net/minecraftforge/fluids/TileFluidHandler.java
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
|
||||||
|
package net.minecraftforge.fluids;
|
||||||
|
|
||||||
|
import net.minecraft.nbt.NBTTagCompound;
|
||||||
|
import net.minecraft.tileentity.TileEntity;
|
||||||
|
import net.minecraftforge.common.ForgeDirection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference Tile Entity implementation of {@link IFluidHandler}. Use/extend this or write your own.
|
||||||
|
*
|
||||||
|
* @author King Lemming
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TileFluidHandler extends TileEntity implements IFluidHandler {
|
||||||
|
|
||||||
|
protected FluidTank tank = new FluidTank(FluidContainerRegistry.BUCKET_VOLUME);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void readFromNBT(NBTTagCompound tag) {
|
||||||
|
|
||||||
|
super.readFromNBT(tag);
|
||||||
|
tank.writeToNBT(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeToNBT(NBTTagCompound tag) {
|
||||||
|
|
||||||
|
super.writeToNBT(tag);
|
||||||
|
tank.readFromNBT(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* IFluidHandler */
|
||||||
|
@Override
|
||||||
|
public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
|
||||||
|
|
||||||
|
return tank.fill(resource, doFill);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
|
||||||
|
|
||||||
|
if (resource == null || !resource.isFluidEqual(tank.getFluid())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return tank.drain(resource.amount, doDrain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
|
||||||
|
|
||||||
|
return tank.drain(maxDrain, doDrain);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canFill(ForgeDirection from, Fluid fluid) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canDrain(ForgeDirection from, Fluid fluid) {
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FluidTankInfo[] getTankInfo(ForgeDirection from) {
|
||||||
|
|
||||||
|
return new FluidTankInfo[] { tank.getInfo() };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import net.minecraft.nbt.NBTTagCompound;
|
||||||
* @author cpw
|
* @author cpw
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public interface IBlockLiquid extends ILiquid {
|
public interface IBlockLiquid extends ILiquid {
|
||||||
/**
|
/**
|
||||||
* Controls the type of block that is generated by this IBlockLiquid
|
* Controls the type of block that is generated by this IBlockLiquid
|
||||||
|
|
|
@ -13,6 +13,7 @@ package net.minecraftforge.liquids;
|
||||||
* Liquids implement this interface
|
* Liquids implement this interface
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public interface ILiquid {
|
public interface ILiquid {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -5,6 +5,7 @@ package net.minecraftforge.liquids;
|
||||||
*
|
*
|
||||||
* @author cpw
|
* @author cpw
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public interface ILiquidTank {
|
public interface ILiquidTank {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package net.minecraftforge.liquids;
|
package net.minecraftforge.liquids;
|
||||||
|
|
||||||
import net.minecraftforge.common.ForgeDirection;
|
import net.minecraftforge.common.ForgeDirection;
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public interface ITankContainer {
|
public interface ITankContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,7 @@ package net.minecraftforge.liquids;
|
||||||
|
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public class LiquidContainerData {
|
public class LiquidContainerData {
|
||||||
|
|
||||||
public final LiquidStack stillLiquid;
|
public final LiquidStack stillLiquid;
|
||||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Set;
|
||||||
import net.minecraft.block.Block;
|
import net.minecraft.block.Block;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public class LiquidContainerRegistry
|
public class LiquidContainerRegistry
|
||||||
{
|
{
|
||||||
public static final int BUCKET_VOLUME = 1000;
|
public static final int BUCKET_VOLUME = 1000;
|
||||||
|
|
|
@ -16,6 +16,7 @@ import com.google.common.collect.ImmutableMap;
|
||||||
*
|
*
|
||||||
* @author CovertJaguar <railcraft.wikispaces.com>
|
* @author CovertJaguar <railcraft.wikispaces.com>
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public abstract class LiquidDictionary
|
public abstract class LiquidDictionary
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import net.minecraft.tileentity.TileEntity;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.Event;
|
import net.minecraftforge.event.Event;
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public class LiquidEvent extends Event {
|
public class LiquidEvent extends Event {
|
||||||
public final LiquidStack liquid;
|
public final LiquidStack liquid;
|
||||||
public final int x;
|
public final int x;
|
||||||
|
|
|
@ -22,6 +22,7 @@ import net.minecraft.util.Icon;
|
||||||
*
|
*
|
||||||
* @author SirSengir
|
* @author SirSengir
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public class LiquidStack
|
public class LiquidStack
|
||||||
{
|
{
|
||||||
public final int itemID;
|
public final int itemID;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import net.minecraft.tileentity.TileEntity;
|
||||||
/**
|
/**
|
||||||
* Reference implementation of ILiquidTank. Use this or implement your own.
|
* Reference implementation of ILiquidTank. Use this or implement your own.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated //See new net.minecraftforge.fluids
|
||||||
public class LiquidTank implements ILiquidTank {
|
public class LiquidTank implements ILiquidTank {
|
||||||
private LiquidStack liquid;
|
private LiquidStack liquid;
|
||||||
private int capacity;
|
private int capacity;
|
||||||
|
|
Loading…
Reference in a new issue