Added fluid renderer.

This commit is contained in:
RainWarrior 2015-06-18 14:14:46 +03:00
parent f59b0a2932
commit 07038f8342
13 changed files with 773 additions and 387 deletions

View File

@ -285,14 +285,12 @@ public class ForgeHooksClient
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Pre(map));
ModelLoader.White.instance.register(map);
FluidRegistry.onTextureStitchedPre(map);
}
public static void onTextureStitchedPost(TextureMap map)
{
MinecraftForge.EVENT_BUS.post(new TextureStitchEvent.Post(map));
FluidRegistry.WATER.setIcons(map.getAtlasSprite("minecraft:blocks/water_still"), map.getAtlasSprite("minecraft:blocks/water_flow"));
FluidRegistry.LAVA.setIcons(map.getAtlasSprite("minecraft:blocks/lava_still"), map.getAtlasSprite("minecraft:blocks/lava_flow"));
}
static int renderPass = -1;

View File

@ -70,7 +70,7 @@ public class BlockStateLoader
boolean uvLock = var.getUvLock().or(false);
int weight = var.getWeight().or(1);
if (var.getModel() != null && var.getSubmodels().size() == 0 && var.getTextures().size() == 0)
if (var.getModel() != null && var.getSubmodels().size() == 0 && var.getTextures().size() == 0 && var.getCustomData().size() == 0)
mcVars.add(new ModelBlockDefinition.Variant(var.getModel(), rot, uvLock, weight));
else
mcVars.add(new ForgeVariant(var.getModel(), rot, uvLock, weight, var.getTextures(), var.getOnlyPartsVariant(), var.getCustomData()));

View File

@ -0,0 +1,354 @@
package net.minecraftforge.client.model;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.block.model.ItemCameraTransforms;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.client.renderer.vertex.VertexFormatElement;
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.model.IBakedModel;
import net.minecraft.client.resources.model.ModelRotation;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.MathHelper;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.fluids.BlockFluidBase;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.FMLLog;
import org.lwjgl.BufferUtils;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
public class ModelFluid implements IModelCustomData
{
public static final ModelFluid waterModel = new ModelFluid(FluidRegistry.WATER);
public static final ModelFluid lavaModel = new ModelFluid(FluidRegistry.LAVA);
private final Fluid fluid;
public ModelFluid(Fluid fluid)
{
this.fluid = fluid;
}
public Collection<ResourceLocation> getDependencies()
{
return Collections.emptySet();
}
public Collection<ResourceLocation> getTextures()
{
return ImmutableSet.of(fluid.getStill(), fluid.getFlowing());
}
public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
{
return new BakedFluid(state.apply(this), format, fluid.getColor(), bakedTextureGetter.apply(fluid.getStill()), bakedTextureGetter.apply(fluid.getFlowing()), fluid.isGaseous());
}
public IModelState getDefaultState()
{
return ModelRotation.X0_Y0;
}
public static enum FluidLoader implements ICustomModelLoader
{
instance;
public void onResourceManagerReload(IResourceManager resourceManager) {}
public boolean accepts(ResourceLocation modelLocation)
{
return modelLocation.getResourceDomain().equals("forge") && (
modelLocation.getResourcePath().equals("fluid") ||
modelLocation.getResourcePath().equals("models/block/fluid") ||
modelLocation.getResourcePath().equals("models/item/fluid"));
}
public IModel loadModel(ResourceLocation modelLocation)
{
return waterModel;
}
}
public static class BakedFluid implements IFlexibleBakedModel, ISmartBlockModel
{
private static final int x[] = { 0, 0, 1, 1 };
private static final int z[] = { 0, 1, 1, 0 };
private static final float eps = 1e-3f;
private final TRSRTransformation transformation;
private final VertexFormat format;
private final int color;
private final TextureAtlasSprite still, flowing;
private final boolean gas;
private final Optional<IExtendedBlockState> state;
private final EnumMap<EnumFacing, List<BakedQuad>> faceQuads;
public BakedFluid(TRSRTransformation transformation, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas)
{
this(transformation, format, color, still, flowing, gas, Optional.<IExtendedBlockState>absent());
}
public BakedFluid(TRSRTransformation transformation, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas, Optional<IExtendedBlockState> stateOption)
{
this.transformation = transformation;
this.format = format;
this.color = color;
this.still = still;
this.flowing = flowing;
this.gas = gas;
this.state = stateOption;
ByteBuffer buf = BufferUtils.createByteBuffer(4 * format.getNextOffset());
int[] data;
faceQuads = Maps.newEnumMap(EnumFacing.class);
for(EnumFacing side : EnumFacing.values())
{
faceQuads.put(side, ImmutableList.<BakedQuad>of());
}
if(state.isPresent())
{
IExtendedBlockState state = this.state.get();
float[] y = new float[4];
for(int i = 0; i < 4; i++)
{
if(gas)
{
y[i] = 1 - state.getValue(BlockFluidBase.LEVEL_CORNERS[i]);
}
else
{
y[i] = state.getValue(BlockFluidBase.LEVEL_CORNERS[i]);
}
}
float flow = state.getValue(BlockFluidBase.FLOW_DIRECTION);
// top
TextureAtlasSprite topSprite = flowing;
float scale = 4;
if(flow < -999F)
{
flow = 0;
scale = 8;
topSprite = still;
}
float c = MathHelper.cos(flow) * scale;
float s = MathHelper.sin(flow) * scale;
EnumFacing side = gas ? EnumFacing.DOWN : EnumFacing.UP;
buf.clear();
for(int i = gas ? 3 : 0; i != (gas ? -1 : 4); i+= (gas ? -1 : 1))
{
putVertex(
buf, side,
x[i], y[i], z[i],
topSprite.getInterpolatedU(8 + c * (x[i] * 2 - 1) + s * (z[i] * 2 - 1)),
topSprite.getInterpolatedV(8 + c * (x[(i + 1) % 4] * 2 - 1) + s * (z[(i + 1) % 4] * 2 - 1)));
}
buf.flip();
data = new int[4 * format.getNextOffset() / 4];
buf.asIntBuffer().get(data);
faceQuads.put(side, ImmutableList.<BakedQuad>of(new IColoredBakedQuad.ColoredBakedQuad(data, -1, side)));
// bottom
side = side.getOpposite();
buf.clear();
for(int i = gas ? 3 : 0; i != (gas ? -1 : 4); i+= (gas ? -1 : 1))
{
putVertex(
buf, side,
z[i], gas ? 1 : 0, x[i],
still.getInterpolatedU(z[i] * 16),
still.getInterpolatedV(x[i] * 16));
}
buf.flip();
data = new int[4 * format.getNextOffset() / 4];
buf.asIntBuffer().get(data);
faceQuads.put(side, ImmutableList.<BakedQuad>of(new IColoredBakedQuad.ColoredBakedQuad(data, -1, side)));
// sides
for(int i = 0; i < 4; i++)
{
side = EnumFacing.getHorizontal((5 - i) % 4);
BakedQuad q[] = new BakedQuad[2];
for(int k = 0; k < 2; k++)
{
buf.clear();
for(int j = 0; j < 4; j++)
{
int l = (k * 3) + (1 - 2 * k) * j;
float yl = z[l] * y[(i + x[l]) % 4];
if(gas && z[l] == 0) yl = 1;
putVertex(
buf, side,
x[(i + x[l]) % 4], yl, z[(i + x[l]) % 4],
flowing.getInterpolatedU(x[l] * 8),
flowing.getInterpolatedV((gas ? yl : 1 - yl) * 8));
}
buf.flip();
data = new int[4 * format.getNextOffset() / 4];
buf.asIntBuffer().get(data);
q[k] = new IColoredBakedQuad.ColoredBakedQuad(data, -1, side);
}
faceQuads.put(side, ImmutableList.of(q[0], q[1]));
}
}
else
{
// 1 quad for inventory
buf.clear();
for(int i = 0; i < 4; i++)
{
putVertex(
buf, EnumFacing.UP,
z[i], x[i], 0,
still.getInterpolatedU(x[i] * 16),
still.getInterpolatedV(z[i] * 16));
}
buf.flip();
data = new int[4 * format.getNextOffset() / 4];
buf.asIntBuffer().get(data);
faceQuads.put(EnumFacing.SOUTH, ImmutableList.<BakedQuad>of(new IColoredBakedQuad.ColoredBakedQuad(data, -1, EnumFacing.UP)));
}
}
private void put(ByteBuffer buf, VertexFormatElement e, Float... fs)
{
Attributes.put(buf, e, true, 0f, fs);
}
private float diffuse(EnumFacing side)
{
switch(side)
{
case DOWN:
return .5f;
case UP:
return 1f;
case NORTH:
case SOUTH:
return .8f;
default:
return .6f;
}
}
private void putVertex(ByteBuffer buf, EnumFacing side, float x, float y, float z, float u, float v)
{
for(VertexFormatElement e : (List<VertexFormatElement>)format.getElements())
{
// TODO transformation
switch(e.getUsage())
{
case POSITION:
put(buf, e, x - side.getDirectionVec().getX() * eps, y, z - side.getDirectionVec().getZ() * eps, 1f);
break;
case COLOR:
// temporarily add diffuse lighting
float d = diffuse(side);
put(buf, e,
d * ((color >> 16) & 0xFF) / 255f,
d * ((color >> 8) & 0xFF) / 255f,
d * (color & 0xFF) / 255f,
((color >> 24) & 0xFF) / 255f);
break;
case UV:
put(buf, e, u, v, 0f, 1f);
break;
case NORMAL:
put(buf, e, (float)side.getFrontOffsetX(), (float)side.getFrontOffsetX(), (float)side.getFrontOffsetX(), 0f);
break;
default:
put(buf, e);
break;
}
}
}
public boolean isAmbientOcclusion()
{
return false; // FIXME
}
public boolean isGui3d()
{
return false;
}
public boolean isBuiltInRenderer()
{
return false;
}
public TextureAtlasSprite getTexture()
{
return still;
}
public ItemCameraTransforms getItemCameraTransforms()
{
return ItemCameraTransforms.DEFAULT;
}
public List<BakedQuad> getFaceQuads(EnumFacing side)
{
return faceQuads.get(side);
}
public List<BakedQuad> getGeneralQuads()
{
return ImmutableList.of();
}
public VertexFormat getFormat()
{
return format;
}
public IBakedModel handleBlockState(IBlockState state)
{
return new BakedFluid(transformation, format, color, still, flowing, gas, Optional.of((IExtendedBlockState)state));
}
}
@Override
public IModel process(ImmutableMap<String, String> customData)
{
if(!customData.containsKey("fluid")) return this;
String fluidStr = customData.get("fluid");
JsonElement e = new JsonParser().parse(fluidStr);
String fluid = e.getAsString();
if(!FluidRegistry.isFluidRegistered(fluid))
{
FMLLog.severe("fluid '%s' not found", fluid);
return waterModel;
}
return new ModelFluid(FluidRegistry.getFluid(fluid));
}
}

View File

@ -116,7 +116,13 @@ public class ModelLoader extends ModelBakery
}
});
sprites.put(new ResourceLocation("missingno"), textureMap.getMissingSprite());
Function<ResourceLocation, TextureAtlasSprite> textureGetter = Functions.forMap(sprites, textureMap.getMissingSprite());
Function<ResourceLocation, TextureAtlasSprite> textureGetter = new Function<ResourceLocation, TextureAtlasSprite>()
{
public TextureAtlasSprite apply(ResourceLocation location)
{
return Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite(location.toString());
}
};
IFlexibleBakedModel missingBaked = missingModel.bake(missingModel.getDefaultState(), Attributes.DEFAULT_BAKED_FORMAT, textureGetter);
for (Entry<ModelResourceLocation, IModel> e : stateModels.entrySet())
{

View File

@ -13,6 +13,7 @@ import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader.VanillaLoader;
import net.minecraftforge.client.model.b3d.B3DLoader;
import net.minecraftforge.fml.common.FMLLog;
import org.apache.logging.log4j.Level;
@ -27,6 +28,13 @@ public class ModelLoaderRegistry
private static final Set<ICustomModelLoader> loaders = new HashSet<ICustomModelLoader>();
private static final Map<ResourceLocation, IModel> cache = new HashMap<ResourceLocation, IModel>();
// Forge built-in loaders
static
{
registerLoader(B3DLoader.instance);
registerLoader(ModelFluid.FluidLoader.instance);
}
/*
* Makes system aware of your loader.
*/

View File

@ -82,11 +82,6 @@ public class B3DLoader implements ICustomModelLoader
private final Set<String> enabledDomains = new HashSet<String>();
private final Map<ResourceLocation, B3DModel> cache = new HashMap<ResourceLocation, B3DModel>();
public B3DLoader()
{
ModelLoaderRegistry.registerLoader(this);
}
public void addDomain(String domain)
{
enabledDomains.add(domain.toLowerCase());

View File

@ -0,0 +1,41 @@
package net.minecraftforge.common.property;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
public class PropertyFloat implements IUnlistedProperty<Float>
{
private final String name;
private final Predicate<Float> validator;
public PropertyFloat(String name)
{
this(name, Predicates.<Float>alwaysTrue());
}
public PropertyFloat(String name, Predicate<Float> validator)
{
this.name = name;
this.validator = validator;
}
public String getName()
{
return name;
}
public boolean isValid(Float value)
{
return validator.apply(value);
}
public Class<Float> getType()
{
return Float.class;
}
public String valueToString(Float value)
{
return value.toString();
}
}

View File

@ -1,11 +1,8 @@
package net.minecraftforge.fluids;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import com.google.common.collect.Maps;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
@ -22,9 +19,16 @@ import net.minecraft.util.EnumWorldBlockLayer;
import net.minecraft.util.Vec3;
import net.minecraft.world.IBlockAccess;
import net.minecraft.world.World;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.common.property.IExtendedBlockState;
import net.minecraftforge.common.property.IUnlistedProperty;
import net.minecraftforge.common.property.PropertyFloat;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
/**
* This is a base implementation for Fluid blocks.
*
@ -84,6 +88,22 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
protected Map<Block, Boolean> displacements = Maps.newHashMap();
public static final PropertyInteger LEVEL = PropertyInteger.create("level", 0, 15);
public static final PropertyFloat[] LEVEL_CORNERS = new PropertyFloat[4];
public static final PropertyFloat FLOW_DIRECTION = new PropertyFloat("flow_direction");
public static final IUnlistedProperty[] FLUID_RENDER_PROPS;
static
{
ImmutableList.Builder<IUnlistedProperty> builder = ImmutableList.builder();
builder.add(FLOW_DIRECTION);
for(int i = 0; i < 4; i++)
{
LEVEL_CORNERS[i] = new PropertyFloat("level_corner_" + i);
builder.add(LEVEL_CORNERS[i]);
}
FLUID_RENDER_PROPS = builder.build().toArray(new IUnlistedProperty[0]);
}
protected int quantaPerBlock = 8;
protected float quantaPerBlockFloat = 8F;
protected int density = 1;
@ -126,7 +146,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
@Override
protected BlockState createBlockState()
{
return new BlockState(this, LEVEL);
return new ExtendedBlockState(this, new IProperty[] { LEVEL }, FLUID_RENDER_PROPS);
}
@Override
@ -345,12 +365,6 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
return (int) (data / quantaPerBlockFloat * maxScaledLight);
}
@Override
public int getRenderType()
{
return FluidRegistry.renderIdFluid;
}
@Override
public boolean isOpaqueCube()
{
@ -397,11 +411,64 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
public boolean shouldSideBeRendered(IBlockAccess world, BlockPos pos, EnumFacing side)
{
Block block = world.getBlockState(pos).getBlock();
if (block != this)
if (block.getMaterial() == this.blockMaterial)
{
return !block.isOpaqueCube();
return false;
}
return block.getMaterial() == this.getMaterial() ? false : super.shouldSideBeRendered(world, pos, side);
if(densityDir == -1 && side == EnumFacing.UP)
{
return true;
}
if(densityDir == 1 && side == EnumFacing.DOWN)
{
return true;
}
return super.shouldSideBeRendered(world, pos, side);
}
@Override
public IBlockState getExtendedState(IBlockState oldState, IBlockAccess worldIn, BlockPos pos)
{
IExtendedBlockState state = (IExtendedBlockState)oldState;
state = state.withProperty(FLOW_DIRECTION, (float)getFlowDirection(worldIn, pos));
float[][] height = new float[3][3];
float[][] corner = new float[2][2];
height[1][1] = getFluidHeightForRender(worldIn, pos);
if(height[1][1] == 1)
{
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
corner[i][j] = 1;
}
}
}
else
{
for(int i = 0; i < 3; i++)
{
for(int j = 0; j < 3; j++)
{
if(i != 1 || j != 1)
{
height[i][j] = getFluidHeightForRender(worldIn, pos.add(i - 1, 0, j - 1));
}
}
}
for(int i = 0; i < 2; i++)
{
for(int j = 0; j < 2; j++)
{
corner[i][j] = getFluidHeightAverage(height[i][j], height[i][j + 1], height[i + 1][j], height[i + 1][j + 1]);
}
}
}
state = state.withProperty(LEVEL_CORNERS[0], corner[0][0]);
state = state.withProperty(LEVEL_CORNERS[1], corner[0][1]);
state = state.withProperty(LEVEL_CORNERS[2], corner[1][1]);
state = state.withProperty(LEVEL_CORNERS[3], corner[1][0]);
return state;
}
/* FLUID FUNCTIONS */
@ -462,6 +529,52 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
return quantaRemaining / quantaPerBlockFloat;
}
public float getFluidHeightAverage(float... flow)
{
float total = 0;
int count = 0;
float end = 0;
for (int i = 0; i < flow.length; i++)
{
if (flow[i] >= 0.875F && end != 1F)
{
end = flow[i];
}
if (flow[i] >= 0)
{
total += flow[i];
count++;
}
}
if (end == 0)
end = total / count;
return end;
}
public float getFluidHeightForRender(IBlockAccess world, BlockPos pos)
{
IBlockState here = world.getBlockState(pos);
IBlockState up = world.getBlockState(pos.down(densityDir));
if (here.getBlock() == this)
{
if (up.getBlock().getMaterial().isLiquid() || up.getBlock() instanceof IFluidBlock)
{
return 1;
}
if (getMetaFromState(here) == getMaxRenderHeightMeta())
{
return 0.875F;
}
}
return !here.getBlock().getMaterial().isSolid() && up.getBlock() == this ? 1 : this.getQuantaPercentage(world, pos) * 0.875F;
}
public Vec3 getFlowVector(IBlockAccess world, BlockPos pos)
{
Vec3 vec = new Vec3(0.0D, 0.0D, 0.0D);

View File

@ -8,6 +8,7 @@ import com.google.common.collect.Maps;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.util.BlockPos;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeModContainer;
@ -41,10 +42,18 @@ public class Fluid
/** The unlocalized name of this fluid. */
protected String unlocalizedName;
/** The Icons for this fluid. */
/**
* The Icons for this fluid.
* @deprecated use ResourceLocation-based ones instead.
*/
@Deprecated
protected TextureAtlasSprite stillIcon;
@Deprecated
protected TextureAtlasSprite flowingIcon;
protected final ResourceLocation still;
protected final ResourceLocation flowing;
/**
* The light level emitted by this fluid.
*
@ -103,10 +112,21 @@ public class Fluid
*/
protected Block block = null;
/**
* @deprecated use the constructor with texture locations.
*/
@Deprecated
public Fluid(String fluidName)
{
this(fluidName, null, null);
}
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing)
{
this.fluidName = fluidName.toLowerCase(Locale.ENGLISH);
this.unlocalizedName = fluidName;
this.still = still;
this.flowing = flowing;
}
public Fluid setUnlocalizedName(String unlocalizedName)
@ -260,39 +280,55 @@ public class Fluid
public int getColor()
{
return 0xFFFFFF;
return 0xFFFFFFFF;
}
public ResourceLocation getStill()
{
return still;
}
public ResourceLocation getFlowing()
{
return flowing;
}
@Deprecated
public final Fluid setStillIcon(TextureAtlasSprite stillIcon)
{
this.stillIcon = stillIcon;
return this;
}
@Deprecated
public final Fluid setFlowingIcon(TextureAtlasSprite flowingIcon)
{
this.flowingIcon = flowingIcon;
return this;
}
@Deprecated
public final Fluid setIcons(TextureAtlasSprite stillIcon, TextureAtlasSprite flowingIcon)
{
return this.setStillIcon(stillIcon).setFlowingIcon(flowingIcon);
}
@Deprecated
public final Fluid setIcons(TextureAtlasSprite commonIcon)
{
return this.setStillIcon(commonIcon).setFlowingIcon(commonIcon);
}
@Deprecated
public TextureAtlasSprite getIcon(){ return getStillIcon(); }
@Deprecated
public TextureAtlasSprite getStillIcon()
{
return this.stillIcon;
}
@Deprecated
public TextureAtlasSprite getFlowingIcon()
{
return this.flowingIcon;
@ -306,7 +342,11 @@ public class Fluid
public boolean isGaseous(FluidStack stack){ return isGaseous(); }
public EnumRarity getRarity(FluidStack stack){ return getRarity(); }
public int getColor(FluidStack stack){ return getColor(); }
@Deprecated
public TextureAtlasSprite getIcon(FluidStack stack){ return getIcon(); }
public ResourceLocation getStill(FluidStack stack) { return getStill(); }
public ResourceLocation getFlowing(FluidStack stack) { return getFlowing(); }
/* World-based Accessors */
public int getLuminosity(World world, BlockPos pos){ return getLuminosity(); }
public int getDensity(World world, BlockPos pos){ return getDensity(); }
@ -315,6 +355,9 @@ public class Fluid
public boolean isGaseous(World world, BlockPos pos){ return isGaseous(); }
public EnumRarity getRarity(World world, BlockPos pos){ return getRarity(); }
public int getColor(World world, BlockPos pos){ return getColor(); }
@Deprecated
public TextureAtlasSprite getIcon(World world, BlockPos pos){ return getIcon(); }
public ResourceLocation getStill(World world, BlockPos pos) { return getStill(); }
public ResourceLocation getFlowing(World world, BlockPos pos) { return getFlowing(); }
}

View File

@ -7,10 +7,13 @@ import java.util.Set;
import org.apache.logging.log4j.Level;
import net.minecraft.block.Block;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.nbt.NBTTagString;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import net.minecraftforge.common.MinecraftForge;
@ -47,14 +50,14 @@ public abstract class FluidRegistry
static BiMap<String,String> defaultFluidName = HashBiMap.create();
static Map<Fluid,FluidDelegate> delegates = Maps.newHashMap();
public static final Fluid WATER = new Fluid("water") {
public static final Fluid WATER = new Fluid("water", new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow")) {
@Override
public String getLocalizedName() {
return StatCollector.translateToLocal("tile.water.name");
}
}.setBlock(Blocks.water).setUnlocalizedName(Blocks.water.getUnlocalizedName());
public static final Fluid LAVA = new Fluid("lava") {
public static final Fluid LAVA = new Fluid("lava", new ResourceLocation("blocks/lava_still"), new ResourceLocation("blocks/lava_flow")) {
@Override
public String getLocalizedName() {
return StatCollector.translateToLocal("tile.lava.name");
@ -393,4 +396,21 @@ public abstract class FluidRegistry
fluid = fluids.get(name);
}
}
public static void onTextureStitchedPre(TextureMap map)
{
for(Fluid fluid : fluids.values())
{
if(fluid.getStill() != null)
{
TextureAtlasSprite still = map.registerSprite(fluid.getStill());
fluid.setStillIcon(still);
}
if(fluid.getFlowing() != null)
{
TextureAtlasSprite flowing = map.registerSprite(fluid.getFlowing());
fluid.setStillIcon(flowing);
}
}
}
}

View File

@ -1,360 +0,0 @@
package net.minecraftforge.fluids;
//TODO: Get some test liquids and test this out -.-
/*
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.RenderBlocks;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraft.util.IIcon;
import net.minecraft.util.MathHelper;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.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;
float end = 0;
for (int i = 0; i < flow.length; i++)
{
if (flow[i] >= 0.875F && end != 1F)
{
end = flow[i];
}
if (flow[i] >= 0)
{
total += flow[i];
count++;
}
}
if (end == 0)
end = total / count;
return end;
}
public float getFluidHeightForRender(IBlockAccess world, int x, int y, int z, BlockFluidBase block)
{
if (world.getBlock(x, y, z) == block)
{
Block verticalOrigin = world.getBlock(x, y - block.densityDir, z);
if (verticalOrigin.getMaterial().isLiquid() || verticalOrigin instanceof IFluidBlock)
{
return 1;
}
if (world.getBlockMetadata(x, y, z) == block.getMaxRenderHeightMeta())
{
return 0.875F;
}
}
return !world.getBlock(x, y, z).getMaterial().isSolid() && world.getBlock(x, y - block.densityDir, z) == block ? 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.getBlock(x, y - theFluid.densityDir, z) != theFluid;
boolean renderBottom = block.shouldSideBeRendered(world, x, y + theFluid.densityDir, z, 0) && world.getBlock(x, y + theFluid.densityDir, z) != theFluid;
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;
IIcon iconStill = getIcon(block.getIcon(1, bMeta));
float flowDir = (float) BlockFluidBase.getFlowDirection(world, x, y, z);
if (flowDir > -999.0F)
{
iconStill = getIcon(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);
tessellator.addVertexWithUV(x + 0, y + heightNW, z + 0, u2, v2);
tessellator.addVertexWithUV(x + 1, y + heightNE, z + 0, u3, v3);
tessellator.addVertexWithUV(x + 1, y + heightSE, z + 1, u4, v4);
tessellator.addVertexWithUV(x + 0, y + heightSW, z + 1, u1, v1);
}
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);
tessellator.addVertexWithUV(x + 1, y + 1 - heightNE, z + 0, u3, v3);
tessellator.addVertexWithUV(x + 0, y + 1 - heightNW, z + 0, u2, v2);
tessellator.addVertexWithUV(x + 0, y + 1 - heightSW, z + 1, u1, v1);
tessellator.addVertexWithUV(x + 1, y + 1 - heightSE, z + 1, u4, v4);
}
}
if (renderer.renderAllFaces || renderBottom)
{
rendered = true;
tessellator.setBrightness(block.getMixedBrightnessForBlock(world, x, y - 1, z));
if (!rises)
{
tessellator.setColorOpaque_F(LIGHT_Y_NEG * red, LIGHT_Y_NEG * green, LIGHT_Y_NEG * blue);
renderer.renderFaceYNeg(block, x, y + RENDER_OFFSET, z, getIcon(block.getIcon(0, bMeta)));
}
else
{
tessellator.setColorOpaque_F(LIGHT_Y_POS * red, LIGHT_Y_POS * green, LIGHT_Y_POS * blue);
renderer.renderFaceYPos(block, x, y + RENDER_OFFSET, z, getIcon(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;
}
IIcon iconFlow = getIcon(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);
tessellator.addVertexWithUV(tx1, y + ty1, tz1, u1Flow, v1Flow);
tessellator.addVertexWithUV(tx1, y + 0, tz1, u1Flow, v3Flow);
tessellator.addVertexWithUV(tx2, y + 0, tz2, u2Flow, v3Flow);
tessellator.addVertexWithUV(tx2, y + ty2, tz2, u2Flow, v2Flow);
}
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);
tessellator.addVertexWithUV(tx1, y + 1 - 0, tz1, u1Flow, v3Flow);
tessellator.addVertexWithUV(tx1, y + 1 - ty1, tz1, u1Flow, v1Flow);
tessellator.addVertexWithUV(tx2, y + 1 - ty2, tz2, u2Flow, v2Flow);
tessellator.addVertexWithUV(tx2, y + 1 - 0, tz2, u2Flow, v3Flow);
}
}
}
renderer.renderMinY = 0;
renderer.renderMaxY = 1;
return rendered;
}
}
@Override
public boolean shouldRender3DInInventory(int modelId){ return false; }
@Override
public int getRenderId()
{
return FluidRegistry.renderIdFluid;
}
private IIcon getIcon(IIcon icon)
{
if (icon != null) return icon;
return ((TextureMap)Minecraft.getMinecraft().getTextureManager().getTexture(TextureMap.locationBlocksTexture)).getAtlasSprite("missingno");
}
}
*/

View File

@ -0,0 +1,155 @@
package net.minecraftforge.debug;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.BlockState;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.statemap.StateMapperBase;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.client.resources.model.ModelResourceLocation;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelFluid;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.common.property.ExtendedBlockState;
import net.minecraftforge.fluids.BlockFluidClassic;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.SidedProxy;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.registry.GameRegistry;
@Mod(modid = ModelFluidDebug.MODID, version = ModelFluidDebug.VERSION)
public class ModelFluidDebug
{
public static final String MODID = "ForgeDebugModelFluid";
public static final String VERSION = "1.0";
@SidedProxy(serverSide = "net.minecraftforge.debug.ModelFluidDebug$CommonProxy", clientSide = "net.minecraftforge.debug.ModelFluidDebug$ClientProxy")
public static CommonProxy proxy;
@EventHandler
public void preInit(FMLPreInitializationEvent event) { proxy.preInit(event); }
public static class CommonProxy
{
public void preInit(FMLPreInitializationEvent event)
{
FluidRegistry.registerFluid(TestFluid.instance);
FluidRegistry.registerFluid(TestGas.instance);
GameRegistry.registerBlock(TestFluidBlock.instance, TestFluidBlock.name);
GameRegistry.registerBlock(TestGasBlock.instance, TestGasBlock.name);
}
}
public static class ClientProxy extends CommonProxy
{
private static ModelResourceLocation fluidLocation = new ModelResourceLocation(MODID.toLowerCase() + ":" + TestFluidBlock.name, "fluid");
private static ModelResourceLocation gasLocation = new ModelResourceLocation(MODID.toLowerCase() + ":" + TestFluidBlock.name, "gas");
@Override
public void preInit(FMLPreInitializationEvent event)
{
super.preInit(event);
Item fluid = Item.getItemFromBlock(TestFluidBlock.instance);
Item gas = Item.getItemFromBlock(TestGasBlock.instance);
ModelBakery.addVariantName(fluid);
ModelBakery.addVariantName(gas);
ModelLoader.setCustomMeshDefinition(fluid, new ItemMeshDefinition()
{
public ModelResourceLocation getModelLocation(ItemStack stack)
{
return fluidLocation;
}
});
ModelLoader.setCustomMeshDefinition(gas, new ItemMeshDefinition()
{
public ModelResourceLocation getModelLocation(ItemStack stack)
{
return gasLocation;
}
});
ModelLoader.setCustomStateMapper(TestFluidBlock.instance, new StateMapperBase()
{
protected ModelResourceLocation getModelResourceLocation(IBlockState state)
{
return fluidLocation;
}
});
ModelLoader.setCustomStateMapper(TestGasBlock.instance, new StateMapperBase()
{
protected ModelResourceLocation getModelResourceLocation(IBlockState state)
{
return gasLocation;
}
});
}
}
public static final class TestFluid extends Fluid
{
public static final String name = "testfluid";
public static final TestFluid instance = new TestFluid();
private TestFluid()
{
super(name, new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"));
}
@Override
public int getColor()
{
return 0xFF00FF00;
}
}
public static final class TestGas extends Fluid
{
public static final String name = "testgas";
public static final TestGas instance = new TestGas();
private TestGas()
{
super(name, new ResourceLocation("blocks/lava_still"), new ResourceLocation("blocks/lava_flow"));
density = -1000;
isGaseous = true;
}
@Override
public int getColor()
{
return 0xFFFF0000;
}
}
public static final class TestFluidBlock extends BlockFluidClassic
{
public static final TestFluidBlock instance = new TestFluidBlock();
public static final String name = "TestFluidBlock";
private TestFluidBlock()
{
super(TestFluid.instance, Material.water);
setCreativeTab(CreativeTabs.tabBlock);
setUnlocalizedName(MODID + ":" + name);
}
}
public static final class TestGasBlock extends BlockFluidClassic
{
public static final TestGasBlock instance = new TestGasBlock();
public static final String name = "TestGasBlock";
private TestGasBlock()
{
super(TestGas.instance, Material.lava);
setCreativeTab(CreativeTabs.tabBlock);
setUnlocalizedName(MODID + ":" + name);
}
}
}

View File

@ -0,0 +1,13 @@
{
"forge_marker": 1,
"variants": {
"fluid": {
"model": "forge:fluid",
"custom": { "fluid": "testfluid" }
},
"gas": {
"model": "forge:fluid",
"custom": { "fluid": "testgas" }
}
}
}