diff --git a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index 93819a3ff..bd24a5fe3 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -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; diff --git a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java index 858c3a062..ea00197f3 100644 --- a/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java +++ b/src/main/java/net/minecraftforge/client/model/BlockStateLoader.java @@ -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())); diff --git a/src/main/java/net/minecraftforge/client/model/ModelFluid.java b/src/main/java/net/minecraftforge/client/model/ModelFluid.java new file mode 100644 index 000000000..b367379f2 --- /dev/null +++ b/src/main/java/net/minecraftforge/client/model/ModelFluid.java @@ -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 getDependencies() + { + return Collections.emptySet(); + } + + public Collection getTextures() + { + return ImmutableSet.of(fluid.getStill(), fluid.getFlowing()); + } + + public IFlexibleBakedModel bake(IModelState state, VertexFormat format, Function 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 state; + private final EnumMap> faceQuads; + + public BakedFluid(TRSRTransformation transformation, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas) + { + this(transformation, format, color, still, flowing, gas, Optional.absent()); + } + + public BakedFluid(TRSRTransformation transformation, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas, Optional 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.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.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.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.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)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 getFaceQuads(EnumFacing side) + { + return faceQuads.get(side); + } + + public List 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 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)); + } +} diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoader.java b/src/main/java/net/minecraftforge/client/model/ModelLoader.java index da4b7dab2..04c6e785d 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoader.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoader.java @@ -116,7 +116,13 @@ public class ModelLoader extends ModelBakery } }); sprites.put(new ResourceLocation("missingno"), textureMap.getMissingSprite()); - Function textureGetter = Functions.forMap(sprites, textureMap.getMissingSprite()); + Function textureGetter = new Function() + { + 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 e : stateModels.entrySet()) { diff --git a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java index 3ee394811..f5264f1d4 100644 --- a/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java +++ b/src/main/java/net/minecraftforge/client/model/ModelLoaderRegistry.java @@ -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 loaders = new HashSet(); private static final Map cache = new HashMap(); + // Forge built-in loaders + static + { + registerLoader(B3DLoader.instance); + registerLoader(ModelFluid.FluidLoader.instance); + } + /* * Makes system aware of your loader. */ diff --git a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java index da9d3c0af..f19ea021c 100644 --- a/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java +++ b/src/main/java/net/minecraftforge/client/model/b3d/B3DLoader.java @@ -82,11 +82,6 @@ public class B3DLoader implements ICustomModelLoader private final Set enabledDomains = new HashSet(); private final Map cache = new HashMap(); - public B3DLoader() - { - ModelLoaderRegistry.registerLoader(this); - } - public void addDomain(String domain) { enabledDomains.add(domain.toLowerCase()); diff --git a/src/main/java/net/minecraftforge/common/property/PropertyFloat.java b/src/main/java/net/minecraftforge/common/property/PropertyFloat.java new file mode 100644 index 000000000..1315a8875 --- /dev/null +++ b/src/main/java/net/minecraftforge/common/property/PropertyFloat.java @@ -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 +{ + private final String name; + private final Predicate validator; + + public PropertyFloat(String name) + { + this(name, Predicates.alwaysTrue()); + } + + public PropertyFloat(String name, Predicate validator) + { + this.name = name; + this.validator = validator; + } + + public String getName() + { + return name; + } + + public boolean isValid(Float value) + { + return validator.apply(value); + } + + public Class getType() + { + return Float.class; + } + + public String valueToString(Float value) + { + return value.toString(); + } +} diff --git a/src/main/java/net/minecraftforge/fluids/BlockFluidBase.java b/src/main/java/net/minecraftforge/fluids/BlockFluidBase.java index a4d3fe2af..5580d72b9 100644 --- a/src/main/java/net/minecraftforge/fluids/BlockFluidBase.java +++ b/src/main/java/net/minecraftforge/fluids/BlockFluidBase.java @@ -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 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 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); diff --git a/src/main/java/net/minecraftforge/fluids/Fluid.java b/src/main/java/net/minecraftforge/fluids/Fluid.java index d82723800..faf675874 100644 --- a/src/main/java/net/minecraftforge/fluids/Fluid.java +++ b/src/main/java/net/minecraftforge/fluids/Fluid.java @@ -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(); } } diff --git a/src/main/java/net/minecraftforge/fluids/FluidRegistry.java b/src/main/java/net/minecraftforge/fluids/FluidRegistry.java index 6c351febc..6a096377b 100644 --- a/src/main/java/net/minecraftforge/fluids/FluidRegistry.java +++ b/src/main/java/net/minecraftforge/fluids/FluidRegistry.java @@ -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 defaultFluidName = HashBiMap.create(); static Map 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); + } + } + } } \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/fluids/RenderBlockFluid.java b/src/main/java/net/minecraftforge/fluids/RenderBlockFluid.java deleted file mode 100644 index f1b2ba988..000000000 --- a/src/main/java/net/minecraftforge/fluids/RenderBlockFluid.java +++ /dev/null @@ -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"); - } -} -*/ diff --git a/src/test/java/net/minecraftforge/debug/ModelFluidDebug.java b/src/test/java/net/minecraftforge/debug/ModelFluidDebug.java new file mode 100644 index 000000000..c3d285200 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/ModelFluidDebug.java @@ -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); + } + } +} diff --git a/src/test/resources/assets/forgedebugmodelfluid/blockstates/TestFluidBlock.json b/src/test/resources/assets/forgedebugmodelfluid/blockstates/TestFluidBlock.json new file mode 100644 index 000000000..7be998c4b --- /dev/null +++ b/src/test/resources/assets/forgedebugmodelfluid/blockstates/TestFluidBlock.json @@ -0,0 +1,13 @@ +{ + "forge_marker": 1, + "variants": { + "fluid": { + "model": "forge:fluid", + "custom": { "fluid": "testfluid" } + }, + "gas": { + "model": "forge:fluid", + "custom": { "fluid": "testgas" } + } + } +}