Update and clean up Forge fluid render model (#4763)
This commit is contained in:
parent
ab228832f2
commit
2786cd279c
14 changed files with 620 additions and 469 deletions
|
@ -221,7 +221,7 @@
|
|||
public SoundType func_185467_w()
|
||||
{
|
||||
return this.field_149762_H;
|
||||
@@ -934,6 +952,1345 @@
|
||||
@@ -934,6 +952,1361 @@
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1494,6 +1494,22 @@
|
|||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Used to determine the state 'viewed' by an entity (see
|
||||
+ * {@link net.minecraft.client.renderer.ActiveRenderInfo#getBlockStateAtEntityViewpoint(World, Entity, float)}).
|
||||
+ * Can be used by fluid blocks to determine if the viewpoint is within the fluid or not.
|
||||
+ *
|
||||
+ * @param state the state
|
||||
+ * @param world the world
|
||||
+ * @param pos the position
|
||||
+ * @param viewpoint the viewpoint
|
||||
+ * @return the block state that should be 'seen'
|
||||
+ */
|
||||
+ public IBlockState getStateAtViewpoint(IBlockState state, IBlockAccess world, BlockPos pos, Vec3d viewpoint)
|
||||
+ {
|
||||
+ return state;
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Gets the {@link IBlockState} to place
|
||||
+ * @param world The world the block is being placed in
|
||||
+ * @param pos The position the block is being placed at
|
||||
|
@ -1567,7 +1583,7 @@
|
|||
public static void func_149671_p()
|
||||
{
|
||||
func_176215_a(0, field_176230_a, (new BlockAir()).func_149663_c("air"));
|
||||
@@ -1105,7 +2462,7 @@
|
||||
@@ -1105,7 +2478,7 @@
|
||||
Block block11 = (new BlockQuartz()).func_149672_a(SoundType.field_185851_d).func_149711_c(0.8F).func_149663_c("quartzBlock");
|
||||
func_176219_a(155, "quartz_block", block11);
|
||||
func_176219_a(156, "quartz_stairs", (new BlockStairs(block11.func_176223_P().func_177226_a(BlockQuartz.field_176335_a, BlockQuartz.EnumType.DEFAULT))).func_149663_c("stairsQuartz"));
|
||||
|
@ -1576,7 +1592,7 @@
|
|||
func_176219_a(158, "dropper", (new BlockDropper()).func_149711_c(3.5F).func_149672_a(SoundType.field_185851_d).func_149663_c("dropper"));
|
||||
func_176219_a(159, "stained_hardened_clay", (new BlockStainedHardenedClay()).func_149711_c(1.25F).func_149752_b(7.0F).func_149672_a(SoundType.field_185851_d).func_149663_c("clayHardenedStained"));
|
||||
func_176219_a(160, "stained_glass_pane", (new BlockStainedGlassPane()).func_149711_c(0.3F).func_149672_a(SoundType.field_185853_f).func_149663_c("thinStainedGlass"));
|
||||
@@ -1230,31 +2587,6 @@
|
||||
@@ -1230,31 +2603,6 @@
|
||||
block15.field_149783_u = flag;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,15 @@
|
|||
GlStateManager.func_179111_a(2982, field_178812_b);
|
||||
GlStateManager.func_179111_a(2983, field_178813_c);
|
||||
GlStateManager.func_187445_a(2978, field_178814_a);
|
||||
@@ -81,7 +86,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
- return iblockstate;
|
||||
+ return iblockstate.func_177230_c().getStateAtViewpoint(iblockstate, p_186703_0_, blockpos, vec3d);
|
||||
}
|
||||
|
||||
public static float func_178808_b()
|
||||
@@ -108,4 +113,14 @@
|
||||
{
|
||||
return field_74596_h;
|
||||
|
|
|
@ -134,8 +134,8 @@ public final class ModelDynBucket implements IModel
|
|||
|
||||
ImmutableMap<TransformType, TRSRTransformation> transformMap = PerspectiveMapWrapper.getTransforms(state);
|
||||
|
||||
// if the fluid is a gas wi manipulate the initial state to be rotated 180° to turn it upside down
|
||||
if (flipGas && fluid != null && fluid.isGaseous())
|
||||
// if the fluid is lighter than air, will manipulate the initial state to be rotated 180° to turn it upside down
|
||||
if (flipGas && fluid != null && fluid.isLighterThanAir())
|
||||
{
|
||||
state = new ModelStateComposition(state, TRSRTransformation.blockCenterToCorner(new TRSRTransformation(null, new Quat4f(0, 0, 1, 0), null, null)));
|
||||
}
|
||||
|
@ -180,12 +180,12 @@ public final class ModelDynBucket implements IModel
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the liquid in the model.
|
||||
* "fluid" - Name of the fluid in the FluidRegistry
|
||||
* "flipGas" - If "true" the model will be flipped upside down if the liquid is a gas. If "false" it won't.
|
||||
* Sets the fluid in the model.
|
||||
* "fluid" - Name of the fluid in the fluid registry.
|
||||
* "flipGas" - If "true" the model will be flipped upside down if the fluid is lighter than air. If "false" it won't.
|
||||
* "applyTint" - If "true" the model will tint the fluid quads according to the fluid's base color.
|
||||
* <p/>
|
||||
* If the fluid can't be found, water is used
|
||||
* If the fluid can't be found, water is used.
|
||||
*/
|
||||
@Override
|
||||
public ModelDynBucket process(ImmutableMap<String, String> customData)
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
|
||||
package net.minecraftforge.client.model;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.vecmath.Matrix4f;
|
||||
|
@ -32,7 +34,6 @@ import net.minecraft.client.renderer.block.model.BakedQuad;
|
|||
import net.minecraft.client.renderer.block.model.IBakedModel;
|
||||
import net.minecraft.client.renderer.block.model.ItemCameraTransforms.TransformType;
|
||||
import net.minecraft.client.renderer.block.model.ItemOverrideList;
|
||||
import net.minecraft.client.renderer.block.model.ModelRotation;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.client.renderer.vertex.VertexFormat;
|
||||
import net.minecraft.client.resources.IResourceManager;
|
||||
|
@ -51,15 +52,12 @@ import net.minecraftforge.fml.common.FMLLog;
|
|||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.Optional;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
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;
|
||||
|
||||
|
@ -67,6 +65,7 @@ public final class ModelFluid implements IModel
|
|||
{
|
||||
public static final ModelFluid WATER = new ModelFluid(FluidRegistry.WATER);
|
||||
public static final ModelFluid LAVA = new ModelFluid(FluidRegistry.LAVA);
|
||||
|
||||
private final Fluid fluid;
|
||||
|
||||
public ModelFluid(Fluid fluid)
|
||||
|
@ -74,25 +73,31 @@ public final class ModelFluid implements IModel
|
|||
this.fluid = fluid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourceLocation> getTextures()
|
||||
{
|
||||
return ImmutableSet.of(fluid.getStill(), fluid.getFlowing());
|
||||
return fluid.getOverlay() != null
|
||||
? ImmutableSet.of(fluid.getStill(), fluid.getFlowing(), fluid.getOverlay())
|
||||
: ImmutableSet.of(fluid.getStill(), fluid.getFlowing());
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter)
|
||||
{
|
||||
ImmutableMap<TransformType, TRSRTransformation> map = PerspectiveMapWrapper.getTransforms(state);
|
||||
return new BakedFluid(state.apply(Optional.empty()), map, format, fluid.getColor(), bakedTextureGetter.apply(fluid.getStill()), bakedTextureGetter.apply(fluid.getFlowing()), fluid.isGaseous(), Optional.empty());
|
||||
return new CachingBakedFluid(
|
||||
state.apply(Optional.empty()),
|
||||
PerspectiveMapWrapper.getTransforms(state),
|
||||
format,
|
||||
fluid.getColor(),
|
||||
bakedTextureGetter.apply(fluid.getStill()),
|
||||
bakedTextureGetter.apply(fluid.getFlowing()),
|
||||
Optional.ofNullable(fluid.getOverlay()).map(bakedTextureGetter),
|
||||
fluid.isLighterThanAir(),
|
||||
Optional.empty()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IModelState getDefaultState()
|
||||
{
|
||||
return ModelRotation.X0_Y0;
|
||||
}
|
||||
|
||||
public static enum FluidLoader implements ICustomModelLoader
|
||||
public enum FluidLoader implements ICustomModelLoader
|
||||
{
|
||||
INSTANCE;
|
||||
|
||||
|
@ -115,72 +120,154 @@ public final class ModelFluid implements IModel
|
|||
}
|
||||
}
|
||||
|
||||
private static final class BakedFluid implements IBakedModel
|
||||
private static final class CachingBakedFluid extends BakedFluid
|
||||
{
|
||||
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 LoadingCache<Long, BakedFluid> modelCache = CacheBuilder.newBuilder().maximumSize(200).build(new CacheLoader<Long, BakedFluid>()
|
||||
{
|
||||
@Override
|
||||
public BakedFluid load(Long key) throws Exception
|
||||
public BakedFluid load(Long key)
|
||||
{
|
||||
boolean statePresent = (key & 1) != 0;
|
||||
key >>>= 1;
|
||||
int[] cornerRound = new int[4];
|
||||
for(int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
cornerRound[i] = (int)(key & 0x3FF);
|
||||
cornerRound[i] = (int) (key & 0x3FF);
|
||||
key >>>= 10;
|
||||
}
|
||||
int flowRound = (int)(key & 0x7FF) - 1024;
|
||||
return new BakedFluid(transformation, transforms, format, color, still, flowing, gas, statePresent, cornerRound, flowRound);
|
||||
int flowRound = (int) (key & 0x7FF) - 1024;
|
||||
key >>>= 11;
|
||||
boolean[] overlaySides = new boolean[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
overlaySides[i] = (key & 1) != 0;
|
||||
key >>>= 1;
|
||||
}
|
||||
return new BakedFluid(transformation, transforms, format, color, still, flowing, overlay, gas, statePresent, cornerRound, flowRound, overlaySides);
|
||||
}
|
||||
});
|
||||
|
||||
private final Optional<TRSRTransformation> transformation;
|
||||
private final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
private final VertexFormat format;
|
||||
private final int color;
|
||||
private final TextureAtlasSprite still, flowing;
|
||||
private final boolean gas;
|
||||
private final EnumMap<EnumFacing, List<BakedQuad>> faceQuads;
|
||||
|
||||
public BakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas, Optional<IExtendedBlockState> stateOption)
|
||||
public CachingBakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional<TextureAtlasSprite> overlay, boolean gas, Optional<IExtendedBlockState> stateOption)
|
||||
{
|
||||
this(transformation, transforms, format, color, still, flowing, gas, stateOption.isPresent(), getCorners(stateOption), getFlow(stateOption));
|
||||
super(transformation, transforms, format, color, still, flowing, overlay, gas, stateOption.isPresent(), getCorners(stateOption), getFlow(stateOption), getOverlay(stateOption));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quantized fluid levels for each corner.
|
||||
*
|
||||
* Each value is packed into 10 bits of the model key, so max range is [0,1024).
|
||||
* The value is currently stored/interpreted as the closest multiple of 1/864.
|
||||
* The divisor is chosen here to allows likely flow values to be exactly representable
|
||||
* while also providing good use of the available value range.
|
||||
* (For fluids with default quanta, this evenly divides the per-block intervals of 1/9 by 96)
|
||||
*/
|
||||
private static int[] getCorners(Optional<IExtendedBlockState> stateOption)
|
||||
{
|
||||
int[] cornerRound = new int[]{0, 0, 0, 0};
|
||||
if(stateOption.isPresent())
|
||||
int[] cornerRound = {0, 0, 0, 0};
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
IExtendedBlockState state = stateOption.get();
|
||||
for(int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Float level = state.getValue(BlockFluidBase.LEVEL_CORNERS[i]);
|
||||
cornerRound[i] = Math.round((level == null ? 7f / 8 : level) * 768);
|
||||
cornerRound[i] = Math.round((level == null ? 8f / 9f : level) * 864);
|
||||
}
|
||||
}
|
||||
return cornerRound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the quantized flow direction of the fluid.
|
||||
*
|
||||
* This value comprises 11 bits of the model key, and is signed, so the max range is [-1024,1024).
|
||||
* The value is currently stored as the angle rounded to the nearest degree.
|
||||
* A value of -1000 is used to signify no flow.
|
||||
*/
|
||||
private static int getFlow(Optional<IExtendedBlockState> stateOption)
|
||||
{
|
||||
Float flow = -1000f;
|
||||
if(stateOption.isPresent())
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
flow = stateOption.get().getValue(BlockFluidBase.FLOW_DIRECTION);
|
||||
if(flow == null) flow = -1000f;
|
||||
if (flow == null) flow = -1000f;
|
||||
}
|
||||
int flowRound = (int)Math.round(Math.toDegrees(flow));
|
||||
int flowRound = (int) Math.round(Math.toDegrees(flow));
|
||||
flowRound = MathHelper.clamp(flowRound, -1000, 1000);
|
||||
return flowRound;
|
||||
}
|
||||
|
||||
public BakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, boolean gas, boolean statePresent, int[] cornerRound, int flowRound)
|
||||
/**
|
||||
* Gets the overlay texture flag for each side.
|
||||
*
|
||||
* This value determines if the fluid "overlay" texture should be used for that side,
|
||||
* instead of the normal "flowing" texture (if applicable for that fluid).
|
||||
* The sides are stored here by their regular horizontal index.
|
||||
*/
|
||||
private static boolean[] getOverlay(Optional<IExtendedBlockState> stateOption)
|
||||
{
|
||||
boolean[] overlaySides = new boolean[4];
|
||||
if (stateOption.isPresent())
|
||||
{
|
||||
IExtendedBlockState state = stateOption.get();
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Boolean overlay = state.getValue(BlockFluidBase.SIDE_OVERLAYS[i]);
|
||||
if (overlay != null) overlaySides[i] = overlay;
|
||||
}
|
||||
}
|
||||
return overlaySides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
if (side != null && state instanceof IExtendedBlockState)
|
||||
{
|
||||
Optional<IExtendedBlockState> exState = Optional.of((IExtendedBlockState)state);
|
||||
|
||||
int[] cornerRound = getCorners(exState);
|
||||
int flowRound = getFlow(exState);
|
||||
boolean[] overlaySides = getOverlay(exState);
|
||||
|
||||
long key = 0L;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
key <<= 1;
|
||||
key |= overlaySides[i] ? 1 : 0;
|
||||
}
|
||||
key <<= 11;
|
||||
key |= flowRound + 1024;
|
||||
for (int i = 3; i >= 0; i--)
|
||||
{
|
||||
key <<= 10;
|
||||
key |= cornerRound[i];
|
||||
}
|
||||
key <<= 1;
|
||||
key |= 1;
|
||||
|
||||
return modelCache.getUnchecked(key).getQuads(state, side, rand);
|
||||
}
|
||||
|
||||
return super.getQuads(state, side, rand);
|
||||
}
|
||||
}
|
||||
|
||||
private static class BakedFluid implements IBakedModel
|
||||
{
|
||||
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;
|
||||
|
||||
protected final Optional<TRSRTransformation> transformation;
|
||||
protected final ImmutableMap<TransformType, TRSRTransformation> transforms;
|
||||
protected final VertexFormat format;
|
||||
protected final int color;
|
||||
protected final TextureAtlasSprite still, flowing;
|
||||
protected final Optional<TextureAtlasSprite> overlay;
|
||||
protected final boolean gas;
|
||||
protected final ImmutableMap<EnumFacing, ImmutableList<BakedQuad>> faceQuads;
|
||||
|
||||
public BakedFluid(Optional<TRSRTransformation> transformation, ImmutableMap<TransformType, TRSRTransformation> transforms, VertexFormat format, int color, TextureAtlasSprite still, TextureAtlasSprite flowing, Optional<TextureAtlasSprite> overlay, boolean gas, boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays)
|
||||
{
|
||||
this.transformation = transformation;
|
||||
this.transforms = transforms;
|
||||
|
@ -188,140 +275,150 @@ public final class ModelFluid implements IModel
|
|||
this.color = color;
|
||||
this.still = still;
|
||||
this.flowing = flowing;
|
||||
this.overlay = overlay;
|
||||
this.gas = gas;
|
||||
this.faceQuads = buildQuads(statePresent, cornerRound, flowRound, sideOverlays);
|
||||
}
|
||||
|
||||
faceQuads = Maps.newEnumMap(EnumFacing.class);
|
||||
for(EnumFacing side : EnumFacing.values())
|
||||
private ImmutableMap<EnumFacing, ImmutableList<BakedQuad>> buildQuads(boolean statePresent, int[] cornerRound, int flowRound, boolean[] sideOverlays)
|
||||
{
|
||||
EnumMap<EnumFacing, ImmutableList<BakedQuad>> faceQuads = new EnumMap<>(EnumFacing.class);
|
||||
for (EnumFacing side : EnumFacing.values())
|
||||
{
|
||||
faceQuads.put(side, ImmutableList.of());
|
||||
}
|
||||
|
||||
if(statePresent)
|
||||
if (statePresent)
|
||||
{
|
||||
// y levels
|
||||
float[] y = new float[4];
|
||||
for(int i = 0; i < 4; i++)
|
||||
boolean fullVolume = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if(gas)
|
||||
{
|
||||
y[i] = 1 - cornerRound[i] / 768f;
|
||||
}
|
||||
else
|
||||
{
|
||||
y[i] = cornerRound[i] / 768f;
|
||||
}
|
||||
float value = cornerRound[i] / 864f;
|
||||
if (value < 1f) fullVolume = false;
|
||||
y[i] = gas ? 1f - value : value;
|
||||
}
|
||||
|
||||
float flow = (float)Math.toRadians(flowRound);
|
||||
// flow
|
||||
boolean isFlowing = flowRound > -1000;
|
||||
|
||||
// top
|
||||
|
||||
TextureAtlasSprite topSprite = flowing;
|
||||
float scale = 4;
|
||||
if(flow < -17F)
|
||||
{
|
||||
flow = 0;
|
||||
scale = 8;
|
||||
topSprite = still;
|
||||
}
|
||||
float flow = isFlowing ? (float) Math.toRadians(flowRound) : 0f;
|
||||
TextureAtlasSprite topSprite = isFlowing ? flowing : still;
|
||||
float scale = isFlowing ? 4f : 8f;
|
||||
|
||||
float c = MathHelper.cos(flow) * scale;
|
||||
float s = MathHelper.sin(flow) * scale;
|
||||
|
||||
EnumFacing side = gas ? EnumFacing.DOWN : EnumFacing.UP;
|
||||
UnpackedBakedQuad.Builder builder;
|
||||
ImmutableList.Builder<BakedQuad> topFaceBuilder = ImmutableList.builder();
|
||||
for(int k = 0; k < 2; k++)
|
||||
// top
|
||||
EnumFacing top = gas ? EnumFacing.DOWN : EnumFacing.UP;
|
||||
|
||||
// base uv offset for flow direction
|
||||
VertexParameter uv = i -> c * (x[i] * 2 - 1) + s * (z[i] * 2 - 1);
|
||||
|
||||
VertexParameter topX = i -> x[i];
|
||||
VertexParameter topY = i -> y[i];
|
||||
VertexParameter topZ = i -> z[i];
|
||||
VertexParameter topU = i -> 8 + uv.get(i);
|
||||
VertexParameter topV = i -> 8 + uv.get((i + 1) % 4);
|
||||
|
||||
{
|
||||
builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(topSprite);
|
||||
builder.setQuadTint(0);
|
||||
for (int i = gas ? 3 : 0; i != (gas ? -1 : 4); i += (gas ? -1 : 1))
|
||||
{
|
||||
int l = (k * 3) + (1 - 2 * k) * i;
|
||||
putVertex(
|
||||
builder, side,
|
||||
x[l], y[l], z[l],
|
||||
topSprite.getInterpolatedU(8 + c * (x[l] * 2 - 1) + s * (z[l] * 2 - 1)),
|
||||
topSprite.getInterpolatedV(8 + c * (x[(l + 1) % 4] * 2 - 1) + s * (z[(l + 1) % 4] * 2 - 1)));
|
||||
}
|
||||
topFaceBuilder.add(builder.build());
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
builder.add(buildQuad(top, topSprite, gas, false, topX, topY, topZ, topU, topV));
|
||||
if (!fullVolume) builder.add(buildQuad(top, topSprite, !gas, true, topX, topY, topZ, topU, topV));
|
||||
|
||||
faceQuads.put(top, builder.build());
|
||||
}
|
||||
faceQuads.put(side, topFaceBuilder.build());
|
||||
|
||||
// bottom
|
||||
|
||||
side = side.getOpposite();
|
||||
builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(still);
|
||||
builder.setQuadTint(0);
|
||||
for(int i = gas ? 3 : 0; i != (gas ? -1 : 4); i+= (gas ? -1 : 1))
|
||||
{
|
||||
putVertex(
|
||||
builder, side,
|
||||
z[i], gas ? 1 : 0, x[i],
|
||||
still.getInterpolatedU(z[i] * 16),
|
||||
still.getInterpolatedV(x[i] * 16));
|
||||
}
|
||||
faceQuads.put(side, ImmutableList.of(builder.build()));
|
||||
EnumFacing bottom = top.getOpposite();
|
||||
faceQuads.put(bottom, ImmutableList.of(
|
||||
buildQuad(bottom, still, gas, false,
|
||||
i -> z[i],
|
||||
i -> gas ? 1 : 0,
|
||||
i -> x[i],
|
||||
i -> z[i] * 16,
|
||||
i -> x[i] * 16
|
||||
)
|
||||
));
|
||||
|
||||
// sides
|
||||
|
||||
for(int i = 0; i < 4; i++)
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
side = EnumFacing.getHorizontal((5 - i) % 4);
|
||||
BakedQuad q[] = new BakedQuad[2];
|
||||
EnumFacing side = EnumFacing.getHorizontal((5 - i) % 4); // [W, S, E, N]
|
||||
boolean useOverlay = overlay.isPresent() && sideOverlays[side.getHorizontalIndex()];
|
||||
int si = i; // local var for lambda capture
|
||||
|
||||
for(int k = 0; k < 2; k++)
|
||||
{
|
||||
builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(flowing);
|
||||
builder.setQuadTint(0);
|
||||
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(
|
||||
builder, side,
|
||||
x[(i + x[l]) % 4], yl, z[(i + x[l]) % 4],
|
||||
flowing.getInterpolatedU(x[l] * 8),
|
||||
flowing.getInterpolatedV((gas ? yl : 1 - yl) * 8));
|
||||
}
|
||||
q[k] = builder.build();
|
||||
}
|
||||
faceQuads.put(side, ImmutableList.of(q[0], q[1]));
|
||||
VertexParameter sideX = j -> x[(si + x[j]) % 4];
|
||||
VertexParameter sideY = j -> z[j] == 0 ? (gas ? 1 : 0) : y[(si + x[j]) % 4];
|
||||
VertexParameter sideZ = j -> z[(si + x[j]) % 4];
|
||||
VertexParameter sideU = j -> x[j] * 8;
|
||||
VertexParameter sideV = j -> (gas ? sideY.get(j) : 1 - sideY.get(j)) * 8;
|
||||
|
||||
ImmutableList.Builder<BakedQuad> builder = ImmutableList.builder();
|
||||
|
||||
if (!useOverlay) builder.add(buildQuad(side, flowing, gas, true, sideX, sideY, sideZ, sideU, sideV));
|
||||
builder.add(buildQuad(side, useOverlay ? overlay.get() : flowing, !gas, false, sideX, sideY, sideZ, sideU, sideV));
|
||||
|
||||
faceQuads.put(side, builder.build());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1 quad for inventory
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(EnumFacing.UP);
|
||||
builder.setTexture(still);
|
||||
builder.setQuadTint(0); //I dont know if we also need this in inventory, but now it should be possible to color it here as well
|
||||
for(int i = 0; i < 4; i++)
|
||||
{
|
||||
putVertex(
|
||||
builder, EnumFacing.UP,
|
||||
z[i], x[i], 0,
|
||||
still.getInterpolatedU(z[i] * 16),
|
||||
still.getInterpolatedV(x[i] * 16));
|
||||
}
|
||||
faceQuads.put(EnumFacing.SOUTH, ImmutableList.of(builder.build()));
|
||||
// inventory
|
||||
faceQuads.put(EnumFacing.SOUTH, ImmutableList.of(
|
||||
buildQuad(EnumFacing.UP, still, false, false,
|
||||
i -> z[i],
|
||||
i -> x[i],
|
||||
i -> 0,
|
||||
i -> z[i] * 16,
|
||||
i -> x[i] * 16
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
return ImmutableMap.copyOf(faceQuads);
|
||||
}
|
||||
|
||||
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing side, float x, float y, float z, float u, float v)
|
||||
// maps vertex index to parameter value
|
||||
private interface VertexParameter
|
||||
{
|
||||
float get(int index);
|
||||
}
|
||||
|
||||
private BakedQuad buildQuad(EnumFacing side, TextureAtlasSprite texture, boolean flip, boolean offset, VertexParameter x, VertexParameter y, VertexParameter z, VertexParameter u, VertexParameter v)
|
||||
{
|
||||
UnpackedBakedQuad.Builder builder = new UnpackedBakedQuad.Builder(format);
|
||||
builder.setQuadOrientation(side);
|
||||
builder.setTexture(texture);
|
||||
builder.setQuadTint(0);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
int vertex = flip ? 3 - i : i;
|
||||
putVertex(
|
||||
builder, side, offset,
|
||||
x.get(vertex), y.get(vertex), z.get(vertex),
|
||||
texture.getInterpolatedU(u.get(vertex)),
|
||||
texture.getInterpolatedV(v.get(vertex))
|
||||
);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private void putVertex(UnpackedBakedQuad.Builder builder, EnumFacing side, boolean offset, float x, float y, float z, float u, float v)
|
||||
{
|
||||
for(int e = 0; e < format.getElementCount(); e++)
|
||||
{
|
||||
switch(format.getElement(e).getUsage())
|
||||
{
|
||||
case POSITION:
|
||||
float[] data = new float[]{ x - side.getDirectionVec().getX() * eps, y, z - side.getDirectionVec().getZ() * eps, 1 };
|
||||
float dx = offset ? side.getDirectionVec().getX() * eps : 0f;
|
||||
float dy = offset ? side.getDirectionVec().getY() * eps : 0f;
|
||||
float dz = offset ? side.getDirectionVec().getZ() * eps : 0f;
|
||||
float[] data = { x - dx, y - dy, z - dz, 1f };
|
||||
if(transformation.isPresent() && !transformation.get().isIdentity())
|
||||
{
|
||||
Vector4f vec = new Vector4f(data);
|
||||
|
@ -379,24 +476,7 @@ public final class ModelFluid implements IModel
|
|||
@Override
|
||||
public List<BakedQuad> getQuads(@Nullable IBlockState state, @Nullable EnumFacing side, long rand)
|
||||
{
|
||||
BakedFluid model = this;
|
||||
if(state instanceof IExtendedBlockState)
|
||||
{
|
||||
IExtendedBlockState exState = (IExtendedBlockState)state;
|
||||
int[] cornerRound = getCorners(Optional.of(exState));
|
||||
int flowRound = getFlow(Optional.of(exState));
|
||||
long key = flowRound + 1024;
|
||||
for(int i = 3; i >= 0; i--)
|
||||
{
|
||||
key <<= 10;
|
||||
key |= cornerRound[i];
|
||||
}
|
||||
key <<= 1;
|
||||
key |= 1;
|
||||
model = modelCache.getUnchecked(key);
|
||||
}
|
||||
if(side == null) return ImmutableList.of();
|
||||
return model.faceQuads.get(side);
|
||||
return side == null ? ImmutableList.of() : faceQuads.get(side);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1034,18 +1034,16 @@ public class ForgeHooks
|
|||
}
|
||||
else if (block instanceof BlockLiquid)
|
||||
{
|
||||
filled = BlockLiquid.getLiquidHeightPercent(block.getMetaFromState(state));
|
||||
filled = 1.0 - (BlockLiquid.getLiquidHeightPercent(block.getMetaFromState(state)) - (1.0 / 9.0));
|
||||
}
|
||||
|
||||
if (filled < 0)
|
||||
{
|
||||
filled *= -1;
|
||||
//filled -= 0.11111111F; //Why this is needed.. not sure...
|
||||
return eyes > pos.getY() + 1 + (1 - filled);
|
||||
return eyes > pos.getY() + (filled + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
return eyes < pos.getY() + 1 + filled;
|
||||
return eyes < pos.getY() + filled;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ package net.minecraftforge.common.property;
|
|||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.collect.Range;
|
||||
|
||||
public class PropertyFloat implements IUnlistedProperty<Float>
|
||||
{
|
||||
|
@ -29,7 +30,12 @@ public class PropertyFloat implements IUnlistedProperty<Float>
|
|||
|
||||
public PropertyFloat(String name)
|
||||
{
|
||||
this(name, Predicates.<Float>alwaysTrue());
|
||||
this(name, Predicates.alwaysTrue());
|
||||
}
|
||||
|
||||
public PropertyFloat(String name, float min, float max)
|
||||
{
|
||||
this(name, Range.closed(min, max));
|
||||
}
|
||||
|
||||
public PropertyFloat(String name, Predicate<Float> validator)
|
||||
|
|
|
@ -23,18 +23,21 @@ import java.util.Map;
|
|||
import java.util.Random;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockLiquid;
|
||||
import net.minecraft.block.BlockStairs;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.properties.IProperty;
|
||||
import net.minecraft.block.properties.PropertyBool;
|
||||
import net.minecraft.block.properties.PropertyInteger;
|
||||
import net.minecraft.block.state.BlockFaceShape;
|
||||
import net.minecraft.block.state.BlockStateContainer;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.renderer.ActiveRenderInfo;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
|
@ -43,12 +46,13 @@ import net.minecraft.util.BlockRenderLayer;
|
|||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
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.Properties;
|
||||
import net.minecraftforge.common.property.PropertyFloat;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
@ -109,25 +113,38 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
}
|
||||
protected Map<Block, Boolean> displacements = Maps.newHashMap();
|
||||
|
||||
private static final class UnlistedPropertyBool extends Properties.PropertyAdapter<Boolean>
|
||||
{
|
||||
public UnlistedPropertyBool(String name)
|
||||
{
|
||||
super(PropertyBool.create(name));
|
||||
}
|
||||
}
|
||||
|
||||
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 ImmutableList<IUnlistedProperty<Float>> FLUID_RENDER_PROPS;
|
||||
public static final PropertyFloat FLOW_DIRECTION = new PropertyFloat("flow_direction", -1000f, 1000f);
|
||||
public static final UnlistedPropertyBool[] SIDE_OVERLAYS = new UnlistedPropertyBool[4];
|
||||
public static final ImmutableList<IUnlistedProperty<?>> FLUID_RENDER_PROPS;
|
||||
|
||||
static
|
||||
{
|
||||
ImmutableList.Builder<IUnlistedProperty<Float>> builder = ImmutableList.builder();
|
||||
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);
|
||||
LEVEL_CORNERS[i] = new PropertyFloat("level_corner_" + i, 0f, 1f);
|
||||
builder.add(LEVEL_CORNERS[i]);
|
||||
|
||||
SIDE_OVERLAYS[i] = new UnlistedPropertyBool("side_overlay_" + i);
|
||||
builder.add(SIDE_OVERLAYS[i]);
|
||||
}
|
||||
FLUID_RENDER_PROPS = builder.build();
|
||||
}
|
||||
|
||||
protected int quantaPerBlock = 8;
|
||||
protected float quantaPerBlockFloat = 8F;
|
||||
protected float quantaFraction = 8f / 9f;
|
||||
protected int density = 1;
|
||||
protected int densityDir = -1;
|
||||
protected int temperature = 295;
|
||||
|
@ -161,14 +178,17 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
|
||||
this.definedFluid = fluid;
|
||||
displacements.putAll(defaultDisplacements);
|
||||
this.setDefaultState(blockState.getBaseState().withProperty(LEVEL, 0));
|
||||
this.setDefaultState(blockState.getBaseState().withProperty(LEVEL, getMaxRenderHeightMeta()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
protected BlockStateContainer createBlockState()
|
||||
{
|
||||
return new ExtendedBlockState(this, new IProperty[] { LEVEL }, FLUID_RENDER_PROPS.toArray(new IUnlistedProperty<?>[0]));
|
||||
return new BlockStateContainer.Builder(this)
|
||||
.add(LEVEL)
|
||||
.add(FLUID_RENDER_PROPS.toArray(new IUnlistedProperty<?>[0]))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -189,6 +209,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
if (quantaPerBlock > 16 || quantaPerBlock < 1) quantaPerBlock = 8;
|
||||
this.quantaPerBlock = quantaPerBlock;
|
||||
this.quantaPerBlockFloat = quantaPerBlock;
|
||||
this.quantaFraction = quantaPerBlock / (quantaPerBlock + 1f);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -225,59 +246,29 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
return this;
|
||||
}
|
||||
|
||||
public final int getDensity()
|
||||
{
|
||||
return density;
|
||||
}
|
||||
|
||||
public final int getTemperature()
|
||||
{
|
||||
return temperature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the block at (pos) is displaceable. Does not displace the block.
|
||||
*/
|
||||
public boolean canDisplace(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
if (world.isAirBlock(pos)) return true;
|
||||
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
|
||||
if (state.getBlock() == this)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (displacements.containsKey(state.getBlock()))
|
||||
{
|
||||
return displacements.get(state.getBlock());
|
||||
}
|
||||
|
||||
Material material = state.getMaterial();
|
||||
if (material.blocksMovement() || material == Material.PORTAL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int density = getDensity(world, pos);
|
||||
if (density == Integer.MAX_VALUE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.density > density)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to displace the block at (pos), return true if it was displaced.
|
||||
*/
|
||||
public boolean displaceIfPossible(World world, BlockPos pos)
|
||||
{
|
||||
if (world.isAirBlock(pos))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block.isAir(state, world, pos))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (block == this)
|
||||
{
|
||||
return false;
|
||||
|
@ -285,17 +276,11 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
|
||||
if (displacements.containsKey(block))
|
||||
{
|
||||
if (displacements.get(block))
|
||||
{
|
||||
if (state.getBlock() != Blocks.SNOW_LAYER) //Forge: Vanilla has a 'bug' where snowballs don't drop like every other block. So special case because ewww...
|
||||
block.dropBlockAsItem(world, pos, state, 0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return displacements.get(block);
|
||||
}
|
||||
|
||||
Material material = state.getMaterial();
|
||||
if (material.blocksMovement() || material == Material.PORTAL)
|
||||
if (material.blocksMovement() || material == Material.PORTAL || material == Material.STRUCTURE_VOID)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -303,18 +288,30 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
int density = getDensity(world, pos);
|
||||
if (density == Integer.MAX_VALUE)
|
||||
{
|
||||
block.dropBlockAsItem(world, pos, state, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.density > density)
|
||||
return this.density > density;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to displace the block at (pos), return true if it was displaced.
|
||||
*/
|
||||
public boolean displaceIfPossible(World world, BlockPos pos)
|
||||
{
|
||||
boolean canDisplace = canDisplace(world, pos);
|
||||
if (canDisplace)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (!block.isAir(state, world, pos) && !isFluid(state))
|
||||
{
|
||||
// Forge: Vanilla has a 'bug' where snowballs don't drop like every other block. So special case because ewww...
|
||||
if (block != Blocks.SNOW_LAYER) block.dropBlockAsItem(world, pos, state, 0);
|
||||
}
|
||||
}
|
||||
return canDisplace;
|
||||
}
|
||||
|
||||
public abstract int getQuantaValue(IBlockAccess world, BlockPos pos);
|
||||
|
@ -373,12 +370,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
@Nonnull
|
||||
public Vec3d modifyAcceleration(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull Entity entity, @Nonnull Vec3d vec)
|
||||
{
|
||||
if (densityDir > 0) return vec;
|
||||
Vec3d vec_flow = this.getFlowVector(world, pos);
|
||||
return vec.addVector(
|
||||
vec_flow.x * (quantaPerBlock * 4),
|
||||
vec_flow.y * (quantaPerBlock * 4),
|
||||
vec_flow.z * (quantaPerBlock * 4));
|
||||
return densityDir > 0 ? vec : vec.add(getFlowVector(world, pos));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -388,8 +380,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
{
|
||||
return super.getLightValue(state, world, pos);
|
||||
}
|
||||
int data = state.getValue(LEVEL);
|
||||
return (int) (data / quantaPerBlockFloat * maxScaledLight);
|
||||
return (int) (getQuantaPercentage(world, pos) * maxScaledLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -404,16 +395,6 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
return false;
|
||||
}
|
||||
|
||||
/* Never used...?
|
||||
@Override
|
||||
public float getBlockBrightness(World world, BlockPos pos)
|
||||
{
|
||||
float lightThis = world.getLightBrightness(pos);
|
||||
float lightUp = world.getLightBrightness(x, y + 1, z);
|
||||
return lightThis > lightUp ? lightThis : lightUp;
|
||||
}
|
||||
*/
|
||||
|
||||
@Override
|
||||
public int getPackedLightmapCoords(@Nonnull IBlockState state, @Nonnull IBlockAccess world, @Nonnull BlockPos pos)
|
||||
{
|
||||
|
@ -450,33 +431,29 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
{
|
||||
return false;
|
||||
}
|
||||
if(densityDir == -1 && side == EnumFacing.UP)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if(densityDir == 1 && side == EnumFacing.DOWN)
|
||||
if (side == (densityDir < 0 ? EnumFacing.UP : EnumFacing.DOWN))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return super.shouldSideBeRendered(state, world, pos, side);
|
||||
}
|
||||
|
||||
private boolean isFluid(@Nonnull IBlockState blockstate)
|
||||
private static boolean isFluid(@Nonnull IBlockState blockstate)
|
||||
{
|
||||
return blockstate.getMaterial().isLiquid() || blockstate.getBlock() instanceof IFluidBlock;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public IBlockState getExtendedState(@Nonnull IBlockState oldState, @Nonnull IBlockAccess worldIn, @Nonnull BlockPos pos)
|
||||
public IBlockState getExtendedState(@Nonnull IBlockState oldState, @Nonnull IBlockAccess world, @Nonnull BlockPos pos)
|
||||
{
|
||||
IExtendedBlockState state = (IExtendedBlockState)oldState;
|
||||
state = state.withProperty(FLOW_DIRECTION, (float)getFlowDirection(worldIn, pos));
|
||||
state = state.withProperty(FLOW_DIRECTION, (float)getFlowDirection(world, pos));
|
||||
IBlockState[][] upBlockState = new IBlockState[3][3];
|
||||
float[][] height = new float[3][3];
|
||||
float[][] corner = new float[2][2];
|
||||
upBlockState[1][1] = worldIn.getBlockState(pos.down(densityDir));
|
||||
height[1][1] = getFluidHeightForRender(worldIn, pos, upBlockState[1][1]);
|
||||
upBlockState[1][1] = world.getBlockState(pos.down(densityDir));
|
||||
height[1][1] = getFluidHeightForRender(world, pos, upBlockState[1][1]);
|
||||
if (height[1][1] == 1)
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
|
@ -495,8 +472,8 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
{
|
||||
if (i != 1 || j != 1)
|
||||
{
|
||||
upBlockState[i][j] = worldIn.getBlockState(pos.add(i - 1, 0, j - 1).down(densityDir));
|
||||
height[i][j] = getFluidHeightForRender(worldIn, pos.add(i - 1, 0, j - 1), upBlockState[i][j]);
|
||||
upBlockState[i][j] = world.getBlockState(pos.add(i - 1, 0, j - 1).down(densityDir));
|
||||
height[i][j] = getFluidHeightForRender(world, pos.add(i - 1, 0, j - 1), upBlockState[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -534,6 +511,14 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
EnumFacing side = EnumFacing.getHorizontal(i);
|
||||
BlockPos offset = pos.offset(side);
|
||||
boolean useOverlay = world.getBlockState(offset).getBlockFaceShape(world, offset, side.getOpposite()) == BlockFaceShape.SOLID;
|
||||
state = state.withProperty(SIDE_OVERLAYS[i], useOverlay);
|
||||
}
|
||||
|
||||
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]);
|
||||
|
@ -542,24 +527,63 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
}
|
||||
|
||||
/* FLUID FUNCTIONS */
|
||||
public static final int getDensity(IBlockAccess world, BlockPos pos)
|
||||
public static int getDensity(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
Block block = world.getBlockState(pos).getBlock();
|
||||
if (!(block instanceof BlockFluidBase))
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block instanceof BlockFluidBase)
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
return ((BlockFluidBase)block).getDensity();
|
||||
}
|
||||
return ((BlockFluidBase)block).density;
|
||||
|
||||
Fluid fluid = getFluid(state);
|
||||
if (fluid != null)
|
||||
{
|
||||
return fluid.getDensity();
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public static final int getTemperature(IBlockAccess world, BlockPos pos)
|
||||
public static int getTemperature(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
Block block = world.getBlockState(pos).getBlock();
|
||||
if (!(block instanceof BlockFluidBase))
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block instanceof BlockFluidBase)
|
||||
{
|
||||
return Integer.MAX_VALUE;
|
||||
return ((BlockFluidBase)block).getTemperature();
|
||||
}
|
||||
return ((BlockFluidBase)block).temperature;
|
||||
|
||||
Fluid fluid = getFluid(state);
|
||||
if (fluid != null)
|
||||
{
|
||||
return fluid.getTemperature();
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Fluid getFluid(IBlockState state)
|
||||
{
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block instanceof IFluidBlock)
|
||||
{
|
||||
return ((IFluidBlock)block).getFluid();
|
||||
}
|
||||
if (block instanceof BlockLiquid)
|
||||
{
|
||||
if (state.getMaterial() == Material.WATER)
|
||||
{
|
||||
return FluidRegistry.WATER;
|
||||
}
|
||||
if (state.getMaterial() == Material.LAVA)
|
||||
{
|
||||
return FluidRegistry.LAVA;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static double getFlowDirection(IBlockAccess world, BlockPos pos)
|
||||
|
@ -570,7 +594,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
return -1000.0;
|
||||
}
|
||||
Vec3d vec = ((BlockFluidBase)state.getBlock()).getFlowVector(world, pos);
|
||||
return vec.x == 0.0D && vec.z == 0.0D ? -1000.0D : Math.atan2(vec.z, vec.x) - Math.PI / 2D;
|
||||
return vec.x == 0.0D && vec.z == 0.0D ? -1000.0D : MathHelper.atan2(vec.z, vec.x) - Math.PI / 2D;
|
||||
}
|
||||
|
||||
public final int getQuantaValueBelow(IBlockAccess world, BlockPos pos, int belowThis)
|
||||
|
@ -604,11 +628,9 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
float total = 0;
|
||||
int count = 0;
|
||||
|
||||
float end = 0;
|
||||
|
||||
for (int i = 0; i < flow.length; i++)
|
||||
{
|
||||
if (flow[i] >= 14f / 16)
|
||||
if (flow[i] >= quantaFraction)
|
||||
{
|
||||
total += flow[i] * 10;
|
||||
count += 10;
|
||||
|
@ -621,10 +643,7 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
}
|
||||
}
|
||||
|
||||
if (end == 0)
|
||||
end = total / count;
|
||||
|
||||
return end;
|
||||
return total / count;
|
||||
}
|
||||
|
||||
public float getFluidHeightForRender(IBlockAccess world, BlockPos pos, @Nonnull IBlockState up)
|
||||
|
@ -632,86 +651,89 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
IBlockState here = world.getBlockState(pos);
|
||||
if (here.getBlock() == this)
|
||||
{
|
||||
if (up.getMaterial().isLiquid() || up.getBlock() instanceof IFluidBlock)
|
||||
if (isFluid(up))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getMetaFromState(here) == getMaxRenderHeightMeta())
|
||||
{
|
||||
return 0.875F;
|
||||
return quantaFraction;
|
||||
}
|
||||
}
|
||||
if (here.getBlock() instanceof BlockLiquid)
|
||||
{
|
||||
return Math.min(1 - BlockLiquid.getLiquidHeightPercent(here.getValue(BlockLiquid.LEVEL)), 14f / 16);
|
||||
return Math.min(1 - BlockLiquid.getLiquidHeightPercent(here.getValue(BlockLiquid.LEVEL)), quantaFraction);
|
||||
}
|
||||
return !here.getMaterial().isSolid() && up.getBlock() == this ? 1 : this.getQuantaPercentage(world, pos) * 0.875F;
|
||||
return !here.getMaterial().isSolid() && up.getBlock() == this ? 1 : this.getQuantaPercentage(world, pos) * quantaFraction;
|
||||
}
|
||||
|
||||
public Vec3d getFlowVector(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
Vec3d vec = new Vec3d(0.0D, 0.0D, 0.0D);
|
||||
int decay = quantaPerBlock - getQuantaValue(world, pos);
|
||||
int decay = getFlowDecay(world, pos);
|
||||
|
||||
for (int side = 0; side < 4; ++side)
|
||||
for (EnumFacing side : EnumFacing.Plane.HORIZONTAL)
|
||||
{
|
||||
int x2 = pos.getX();
|
||||
int z2 = pos.getZ();
|
||||
|
||||
switch (side)
|
||||
{
|
||||
case 0: --x2; break;
|
||||
case 1: --z2; break;
|
||||
case 2: ++x2; break;
|
||||
case 3: ++z2; break;
|
||||
}
|
||||
|
||||
BlockPos pos2 = new BlockPos(x2, pos.getY(), z2);
|
||||
int otherDecay = quantaPerBlock - getQuantaValue(world, pos2);
|
||||
BlockPos offset = pos.offset(side);
|
||||
int otherDecay = getFlowDecay(world, offset);
|
||||
if (otherDecay >= quantaPerBlock)
|
||||
{
|
||||
if (!world.getBlockState(pos2).getMaterial().blocksMovement())
|
||||
if (!world.getBlockState(offset).getMaterial().blocksMovement())
|
||||
{
|
||||
otherDecay = quantaPerBlock - getQuantaValue(world, pos2.down());
|
||||
if (otherDecay >= 0)
|
||||
otherDecay = getFlowDecay(world, offset.up(densityDir));
|
||||
if (otherDecay < quantaPerBlock)
|
||||
{
|
||||
int power = otherDecay - (decay - quantaPerBlock);
|
||||
vec = vec.addVector((pos2.getX() - pos.getX()) * power, 0, (pos2.getZ() - pos.getZ()) * power);
|
||||
vec = vec.addVector(side.getFrontOffsetX() * power, 0, side.getFrontOffsetZ() * power);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (otherDecay >= 0)
|
||||
else
|
||||
{
|
||||
int power = otherDecay - decay;
|
||||
vec = vec.addVector((pos2.getX() - pos.getX()) * power, 0, (pos2.getZ() - pos.getZ()) * power);
|
||||
vec = vec.addVector(side.getFrontOffsetX() * power, 0, side.getFrontOffsetZ() * power);
|
||||
}
|
||||
}
|
||||
|
||||
if (world.getBlockState(pos.up()).getBlock() == this)
|
||||
if (hasVerticalFlow(world, pos))
|
||||
{
|
||||
boolean flag =
|
||||
isBlockSolid(world, pos.add( 0, 0, -1), EnumFacing.NORTH) ||
|
||||
isBlockSolid(world, pos.add( 0, 0, 1), EnumFacing.SOUTH) ||
|
||||
isBlockSolid(world, pos.add(-1, 0, 0), EnumFacing.WEST) ||
|
||||
isBlockSolid(world, pos.add( 1, 0, 0), EnumFacing.EAST) ||
|
||||
isBlockSolid(world, pos.add( 0, 1, -1), EnumFacing.NORTH) ||
|
||||
isBlockSolid(world, pos.add( 0, 1, 1), EnumFacing.SOUTH) ||
|
||||
isBlockSolid(world, pos.add(-1, 1, 0), EnumFacing.WEST) ||
|
||||
isBlockSolid(world, pos.add( 1, 1, 0), EnumFacing.EAST);
|
||||
|
||||
if (flag)
|
||||
for (EnumFacing side : EnumFacing.Plane.HORIZONTAL)
|
||||
{
|
||||
vec = vec.normalize().addVector(0.0D, -6.0D, 0.0D);
|
||||
BlockPos offset = pos.offset(side);
|
||||
if (causesDownwardCurrent(world, offset, side) || causesDownwardCurrent(world, offset.down(densityDir), side))
|
||||
{
|
||||
vec = vec.normalize().addVector(0.0, 6.0 * densityDir, 0.0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vec = vec.normalize();
|
||||
return vec;
|
||||
|
||||
return vec.normalize();
|
||||
}
|
||||
|
||||
private boolean isBlockSolid(IBlockAccess world, BlockPos pos, EnumFacing face)
|
||||
private int getFlowDecay(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
return world.getBlockState(pos).getBlockFaceShape(world, pos, face) == BlockFaceShape.SOLID;
|
||||
int quantaValue = getQuantaValue(world, pos);
|
||||
return quantaValue > 0 && hasVerticalFlow(world, pos) ? 0 : quantaPerBlock - quantaValue;
|
||||
}
|
||||
|
||||
private boolean hasVerticalFlow(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
return world.getBlockState(pos.down(densityDir)).getBlock() == this;
|
||||
}
|
||||
|
||||
protected boolean causesDownwardCurrent(IBlockAccess world, BlockPos pos, EnumFacing face)
|
||||
{
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
Block block = state.getBlock();
|
||||
|
||||
if (block == this) return false;
|
||||
if (face == (densityDir < 0 ? EnumFacing.UP : EnumFacing.DOWN)) return true;
|
||||
if (state.getMaterial() == Material.ICE) return false;
|
||||
|
||||
boolean flag = isExceptBlockForAttachWithPiston(block) || block instanceof BlockStairs;
|
||||
return !flag && state.getBlockFaceShape(world, pos, face) == BlockFaceShape.SOLID;
|
||||
}
|
||||
|
||||
/* IFluidBlock */
|
||||
|
@ -724,9 +746,13 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
@Override
|
||||
public float getFilledPercentage(World world, BlockPos pos)
|
||||
{
|
||||
int quantaRemaining = getQuantaValue(world, pos) + 1;
|
||||
float remaining = quantaRemaining / quantaPerBlockFloat;
|
||||
if (remaining > 1) remaining = 1.0f;
|
||||
return getFilledPercentage((IBlockAccess) world, pos);
|
||||
}
|
||||
|
||||
public float getFilledPercentage(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
int quantaRemaining = getQuantaValue(world, pos);
|
||||
float remaining = (quantaRemaining + 1f) / (quantaPerBlockFloat + 1f);
|
||||
return remaining * (density > 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
|
@ -740,6 +766,13 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
@SideOnly (Side.CLIENT)
|
||||
public Vec3d getFogColor(World world, BlockPos pos, IBlockState state, Entity entity, Vec3d originalColor, float partialTicks)
|
||||
{
|
||||
if (!isWithinFluid(world, pos, ActiveRenderInfo.projectViewFromEntity(entity, partialTicks)))
|
||||
{
|
||||
BlockPos otherPos = pos.down(densityDir);
|
||||
IBlockState otherState = world.getBlockState(otherPos);
|
||||
return otherState.getBlock().getFogColor(world, otherPos, otherState, entity, originalColor, partialTicks);
|
||||
}
|
||||
|
||||
if (getFluid() != null)
|
||||
{
|
||||
int color = getFluid().getColor();
|
||||
|
@ -748,9 +781,25 @@ public abstract class BlockFluidBase extends Block implements IFluidBlock
|
|||
float blue = (color & 0xFF) / 255.0F;
|
||||
return new Vec3d(red, green, blue);
|
||||
}
|
||||
else
|
||||
|
||||
return super.getFogColor(world, pos, state, entity, originalColor, partialTicks);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockState getStateAtViewpoint(IBlockState state, IBlockAccess world, BlockPos pos, Vec3d viewpoint)
|
||||
{
|
||||
if (!isWithinFluid(world, pos, viewpoint))
|
||||
{
|
||||
return super.getFogColor(world, pos, state, entity, originalColor, partialTicks);
|
||||
return world.getBlockState(pos.down(densityDir));
|
||||
}
|
||||
|
||||
return super.getStateAtViewpoint(state, world, pos, viewpoint);
|
||||
}
|
||||
|
||||
private boolean isWithinFluid(IBlockAccess world, BlockPos pos, Vec3d vec)
|
||||
{
|
||||
float filled = getFilledPercentage(world, pos);
|
||||
return filled < 0 ? vec.y > pos.getY() + filled + 1
|
||||
: vec.y < pos.getY() + filled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,16 @@
|
|||
|
||||
package net.minecraftforge.fluids;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import com.google.common.primitives.Ints;
|
||||
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
import net.minecraft.world.World;
|
||||
|
@ -40,10 +45,16 @@ import javax.annotation.Nullable;
|
|||
*/
|
||||
public class BlockFluidClassic extends BlockFluidBase
|
||||
{
|
||||
protected static final List<EnumFacing> SIDES = Collections.unmodifiableList(Arrays.asList(
|
||||
EnumFacing.WEST, EnumFacing.EAST, EnumFacing.NORTH, EnumFacing.SOUTH));
|
||||
|
||||
protected boolean[] isOptimalFlowDirection = new boolean[4];
|
||||
protected int[] flowCost = new int[4];
|
||||
|
||||
protected boolean canCreateSources = false;
|
||||
|
||||
protected FluidStack stack;
|
||||
|
||||
public BlockFluidClassic(Fluid fluid, Material material)
|
||||
{
|
||||
super(fluid, material);
|
||||
|
@ -66,7 +77,7 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
public int getQuantaValue(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
if (state.getBlock() == Blocks.AIR)
|
||||
if (state.getBlock().isAir(state, world, pos))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -76,8 +87,7 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
return -1;
|
||||
}
|
||||
|
||||
int quantaRemaining = quantaPerBlock - state.getValue(LEVEL);
|
||||
return quantaRemaining;
|
||||
return quantaPerBlock - state.getValue(LEVEL);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -92,53 +102,46 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightValue(@Nonnull IBlockState state, @Nonnull IBlockAccess world, @Nonnull BlockPos pos)
|
||||
{
|
||||
if (maxScaledLight == 0)
|
||||
{
|
||||
return super.getLightValue(state, world, pos);
|
||||
}
|
||||
int data = quantaPerBlock - state.getValue(LEVEL) - 1;
|
||||
return (int) (data / quantaPerBlockFloat * maxScaledLight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTick(@Nonnull World world, @Nonnull BlockPos pos, @Nonnull IBlockState state, @Nonnull Random rand)
|
||||
{
|
||||
if (!isSourceBlock(world, pos) && ForgeEventFactory.canCreateFluidSource(world, pos, state, false))
|
||||
{
|
||||
int adjacentSourceBlocks =
|
||||
(isSourceBlock(world, pos.north()) ? 1 : 0) +
|
||||
(isSourceBlock(world, pos.south()) ? 1 : 0) +
|
||||
(isSourceBlock(world, pos.east()) ? 1 : 0) +
|
||||
(isSourceBlock(world, pos.west()) ? 1 : 0);
|
||||
if (adjacentSourceBlocks >= 2 && (world.getBlockState(pos.up(densityDir)).getMaterial().isSolid() || isSourceBlock(world, pos.up(densityDir))))
|
||||
world.setBlockState(pos, state.withProperty(LEVEL, 0));
|
||||
}
|
||||
|
||||
int quantaRemaining = quantaPerBlock - state.getValue(LEVEL);
|
||||
int expQuanta = -101;
|
||||
|
||||
// check adjacent block levels if non-source
|
||||
if (quantaRemaining < quantaPerBlock)
|
||||
{
|
||||
if (world.getBlockState(pos.add( 0, -densityDir, 0)).getBlock() == this ||
|
||||
world.getBlockState(pos.add(-1, -densityDir, 0)).getBlock() == this ||
|
||||
world.getBlockState(pos.add( 1, -densityDir, 0)).getBlock() == this ||
|
||||
world.getBlockState(pos.add( 0, -densityDir, -1)).getBlock() == this ||
|
||||
world.getBlockState(pos.add( 0, -densityDir, 1)).getBlock() == this)
|
||||
int adjacentSourceBlocks = 0;
|
||||
|
||||
if (ForgeEventFactory.canCreateFluidSource(world, pos, state, canCreateSources))
|
||||
{
|
||||
for (EnumFacing side : EnumFacing.Plane.HORIZONTAL)
|
||||
{
|
||||
if (isSourceBlock(world, pos.offset(side))) adjacentSourceBlocks++;
|
||||
}
|
||||
}
|
||||
|
||||
// new source block
|
||||
if (adjacentSourceBlocks >= 2 && (world.getBlockState(pos.up(densityDir)).getMaterial().isSolid() || isSourceBlock(world, pos.up(densityDir))))
|
||||
{
|
||||
expQuanta = quantaPerBlock;
|
||||
}
|
||||
// unobstructed flow from 'above'
|
||||
else if (world.getBlockState(pos.down(densityDir)).getBlock() == this
|
||||
|| hasDownhillFlow(world, pos, EnumFacing.EAST)
|
||||
|| hasDownhillFlow(world, pos, EnumFacing.WEST)
|
||||
|| hasDownhillFlow(world, pos, EnumFacing.NORTH)
|
||||
|| hasDownhillFlow(world, pos, EnumFacing.SOUTH))
|
||||
{
|
||||
expQuanta = quantaPerBlock - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int maxQuanta = -100;
|
||||
maxQuanta = getLargerQuanta(world, pos.add(-1, 0, 0), maxQuanta);
|
||||
maxQuanta = getLargerQuanta(world, pos.add( 1, 0, 0), maxQuanta);
|
||||
maxQuanta = getLargerQuanta(world, pos.add( 0, 0, -1), maxQuanta);
|
||||
maxQuanta = getLargerQuanta(world, pos.add( 0, 0, 1), maxQuanta);
|
||||
|
||||
for (EnumFacing side : EnumFacing.Plane.HORIZONTAL)
|
||||
{
|
||||
maxQuanta = getLargerQuanta(world, pos.offset(side), maxQuanta);
|
||||
}
|
||||
expQuanta = maxQuanta - 1;
|
||||
}
|
||||
|
||||
|
@ -159,11 +162,6 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
}
|
||||
}
|
||||
}
|
||||
// This is a "source" block, set meta to zero, and send a server only update
|
||||
else if (quantaRemaining >= quantaPerBlock)
|
||||
{
|
||||
world.setBlockState(pos, this.getDefaultState(), 2);
|
||||
}
|
||||
|
||||
// Flow vertically if possible
|
||||
if (canDisplace(world, pos.up(densityDir)))
|
||||
|
@ -186,14 +184,20 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
flowMeta = 1;
|
||||
}
|
||||
boolean flowTo[] = getOptimalFlowDirections(world, pos);
|
||||
|
||||
if (flowTo[0]) flowIntoBlock(world, pos.add(-1, 0, 0), flowMeta);
|
||||
if (flowTo[1]) flowIntoBlock(world, pos.add( 1, 0, 0), flowMeta);
|
||||
if (flowTo[2]) flowIntoBlock(world, pos.add( 0, 0, -1), flowMeta);
|
||||
if (flowTo[3]) flowIntoBlock(world, pos.add( 0, 0, 1), flowMeta);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (flowTo[i]) flowIntoBlock(world, pos.offset(SIDES.get(i)), flowMeta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected final boolean hasDownhillFlow(IBlockAccess world, BlockPos pos, EnumFacing direction)
|
||||
{
|
||||
return world.getBlockState(pos.offset(direction).down(densityDir)).getBlock() == this
|
||||
&& (canFlowInto(world, pos.offset(direction))
|
||||
|| canFlowInto(world, pos.down(densityDir)));
|
||||
}
|
||||
|
||||
public boolean isFlowingVertically(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
return world.getBlockState(pos.up(densityDir)).getBlock() == this ||
|
||||
|
@ -212,22 +216,14 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
{
|
||||
flowCost[side] = 1000;
|
||||
|
||||
BlockPos pos2 = pos;
|
||||
|
||||
switch (side)
|
||||
{
|
||||
case 0: pos2 = pos2.add(-1, 0, 0); break;
|
||||
case 1: pos2 = pos2.add( 1, 0, 0); break;
|
||||
case 2: pos2 = pos2.add( 0, 0, -1); break;
|
||||
case 3: pos2 = pos2.add( 0, 0, 1); break;
|
||||
}
|
||||
BlockPos pos2 = pos.offset(SIDES.get(side));
|
||||
|
||||
if (!canFlowInto(world, pos2) || isSourceBlock(world, pos2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (canFlowInto(world, pos2.add(0, densityDir, 0)))
|
||||
if (canFlowInto(world, pos2.up(densityDir)))
|
||||
{
|
||||
flowCost[side] = 0;
|
||||
}
|
||||
|
@ -237,14 +233,7 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
}
|
||||
}
|
||||
|
||||
int min = flowCost[0];
|
||||
for (int side = 1; side < 4; side++)
|
||||
{
|
||||
if (flowCost[side] < min)
|
||||
{
|
||||
min = flowCost[side];
|
||||
}
|
||||
}
|
||||
int min = Ints.min(flowCost);
|
||||
for (int side = 0; side < 4; side++)
|
||||
{
|
||||
isOptimalFlowDirection[side] = flowCost[side] == min;
|
||||
|
@ -257,44 +246,29 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
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))
|
||||
if (SIDES.get(adjSide) == SIDES.get(side).getOpposite())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BlockPos pos2 = pos;
|
||||
|
||||
switch (adjSide)
|
||||
{
|
||||
case 0: pos2 = pos2.add(-1, 0, 0); break;
|
||||
case 1: pos2 = pos2.add( 1, 0, 0); break;
|
||||
case 2: pos2 = pos2.add( 0, 0, -1); break;
|
||||
case 3: pos2 = pos2.add( 0, 0, 1); break;
|
||||
}
|
||||
BlockPos pos2 = pos.offset(SIDES.get(adjSide));
|
||||
|
||||
if (!canFlowInto(world, pos2) || isSourceBlock(world, pos2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (canFlowInto(world, pos2.add(0, densityDir, 0)))
|
||||
if (canFlowInto(world, pos2.up(densityDir)))
|
||||
{
|
||||
return recurseDepth;
|
||||
}
|
||||
|
||||
if (recurseDepth >= 4)
|
||||
if (recurseDepth >= quantaPerBlock / 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int min = calculateFlowCost(world, pos2, recurseDepth + 1, adjSide);
|
||||
if (min < cost)
|
||||
{
|
||||
cost = min;
|
||||
}
|
||||
cost = Math.min(cost, calculateFlowCost(world, pos2, recurseDepth + 1, adjSide));
|
||||
}
|
||||
return cost;
|
||||
}
|
||||
|
@ -304,48 +278,13 @@ public class BlockFluidClassic extends BlockFluidBase
|
|||
if (meta < 0) return;
|
||||
if (displaceIfPossible(world, pos))
|
||||
{
|
||||
world.setBlockState(pos, this.getBlockState().getBaseState().withProperty(LEVEL, meta), 3);
|
||||
world.setBlockState(pos, this.getDefaultState().withProperty(LEVEL, meta), 3);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean canFlowInto(IBlockAccess world, BlockPos pos)
|
||||
{
|
||||
if (world.isAirBlock(pos)) return true;
|
||||
|
||||
IBlockState state = world.getBlockState(pos);
|
||||
if (state.getBlock() == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (displacements.containsKey(state.getBlock()))
|
||||
{
|
||||
return displacements.get(state.getBlock());
|
||||
}
|
||||
|
||||
Material material = state.getMaterial();
|
||||
if (material.blocksMovement() ||
|
||||
material == Material.WATER ||
|
||||
material == Material.LAVA ||
|
||||
material == Material.PORTAL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int density = getDensity(world, pos);
|
||||
if (density == Integer.MAX_VALUE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.density > density)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return world.getBlockState(pos).getBlock() == this || canDisplace(world, pos);
|
||||
}
|
||||
|
||||
protected int getLargerQuanta(IBlockAccess world, BlockPos pos, int compare)
|
||||
|
|
|
@ -67,6 +67,9 @@ public class Fluid
|
|||
protected final ResourceLocation still;
|
||||
protected final ResourceLocation flowing;
|
||||
|
||||
@Nullable
|
||||
protected final ResourceLocation overlay;
|
||||
|
||||
private SoundEvent fillSound;
|
||||
private SoundEvent emptySound;
|
||||
|
||||
|
@ -108,8 +111,6 @@ public class Fluid
|
|||
/**
|
||||
* 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;
|
||||
|
@ -140,22 +141,38 @@ public class Fluid
|
|||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, Color color)
|
||||
{
|
||||
this(fluidName, still, flowing);
|
||||
this(fluidName, still, flowing, null, color);
|
||||
}
|
||||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, @Nullable ResourceLocation overlay, Color color)
|
||||
{
|
||||
this(fluidName, still, flowing, overlay);
|
||||
this.setColor(color);
|
||||
}
|
||||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, int color)
|
||||
{
|
||||
this(fluidName, still, flowing);
|
||||
this(fluidName, still, flowing, null, color);
|
||||
}
|
||||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, @Nullable ResourceLocation overlay, int color)
|
||||
{
|
||||
this(fluidName, still, flowing, overlay);
|
||||
this.setColor(color);
|
||||
}
|
||||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing)
|
||||
{
|
||||
this(fluidName, still, flowing, (ResourceLocation) null);
|
||||
}
|
||||
|
||||
public Fluid(String fluidName, ResourceLocation still, ResourceLocation flowing, @Nullable ResourceLocation overlay)
|
||||
{
|
||||
this.fluidName = fluidName.toLowerCase(Locale.ENGLISH);
|
||||
this.unlocalizedName = fluidName;
|
||||
this.still = still;
|
||||
this.flowing = flowing;
|
||||
this.overlay = overlay;
|
||||
}
|
||||
|
||||
public Fluid setUnlocalizedName(String unlocalizedName)
|
||||
|
@ -253,6 +270,16 @@ public class Fluid
|
|||
return block != null;
|
||||
}
|
||||
|
||||
public final boolean isLighterThanAir()
|
||||
{
|
||||
int density = this.density;
|
||||
if (block instanceof BlockFluidBase)
|
||||
{
|
||||
density = ((BlockFluidBase) block).getDensity();
|
||||
}
|
||||
return density <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this fluid should vaporize in dimensions where water vaporizes when placed.
|
||||
* To preserve the intentions of vanilla, fluids that can turn lava into obsidian should vaporize.
|
||||
|
@ -360,6 +387,12 @@ public class Fluid
|
|||
return flowing;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public ResourceLocation getOverlay()
|
||||
{
|
||||
return overlay;
|
||||
}
|
||||
|
||||
public SoundEvent getFillSound()
|
||||
{
|
||||
if(fillSound == null)
|
||||
|
|
|
@ -71,7 +71,7 @@ public abstract class FluidRegistry
|
|||
static boolean universalBucketEnabled = false;
|
||||
static Set<Fluid> bucketFluids = Sets.newHashSet();
|
||||
|
||||
public static final Fluid WATER = new Fluid("water", new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow")) {
|
||||
public static final Fluid WATER = new Fluid("water", new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"), new ResourceLocation("blocks/water_overlay")) {
|
||||
@Override
|
||||
public String getLocalizedName(FluidStack fs) {
|
||||
return I18n.translateToLocal("tile.water.name");
|
||||
|
|
|
@ -65,7 +65,7 @@ public class MaterialFogColorTest
|
|||
}
|
||||
}
|
||||
|
||||
public static final Fluid SLIME = new Fluid("slime", new ResourceLocation(MODID, "slime_still"), new ResourceLocation(MODID, "slime_flow")) {
|
||||
public static final Fluid SLIME = new Fluid("slime", new ResourceLocation(MODID, "slime_still"), new ResourceLocation(MODID, "slime_flow"), new ResourceLocation(MODID, "slime_overlay")) {
|
||||
@Override
|
||||
public int getColor()
|
||||
{
|
||||
|
@ -99,7 +99,7 @@ public class MaterialFogColorTest
|
|||
if (ENABLED)
|
||||
{
|
||||
event.getRegistry().register((new BlockFluidClassic(SLIME, Material.WATER)).setRegistryName(RES_LOC).setUnlocalizedName(RES_LOC.toString()));
|
||||
Fluid fluid = new Fluid("fog_test", Blocks.WATER.getRegistryName(), Blocks.FLOWING_WATER.getRegistryName());
|
||||
Fluid fluid = new Fluid("fog_test", new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"), new ResourceLocation("blocks/water_overlay"));
|
||||
FluidRegistry.registerFluid(fluid);
|
||||
Block fluidBlock = new BlockFluidClassic(fluid, Material.WATER)
|
||||
{
|
||||
|
|
|
@ -150,7 +150,7 @@ public class ModelFluidTest
|
|||
|
||||
private TestFluid()
|
||||
{
|
||||
super(name, new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"));
|
||||
super(name, new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"), new ResourceLocation("blocks/water_overlay"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -52,7 +52,7 @@ public class ColoredFluidTest
|
|||
FluidRegistry.enableUniversalBucket();
|
||||
}
|
||||
}
|
||||
public static final Fluid SLIME = new Fluid("slime", new ResourceLocation(MODID, "slime_still"), new ResourceLocation(MODID, "slime_flow")).setColor(COLOR);
|
||||
public static final Fluid SLIME = new Fluid("slime", new ResourceLocation(MODID, "slime_still"), new ResourceLocation(MODID, "slime_flow"), new ResourceLocation(MODID, "slime_overlay")).setColor(COLOR);
|
||||
@ObjectHolder("slime")
|
||||
public static final BlockFluidBase SLIME_BLOCK = null;
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ import net.minecraftforge.common.MinecraftForge;
|
|||
import net.minecraftforge.common.capabilities.ICapabilityProvider;
|
||||
import net.minecraftforge.debug.client.model.ModelFluidTest;
|
||||
import net.minecraftforge.event.RegistryEvent;
|
||||
import net.minecraftforge.fluids.BlockFluidBase;
|
||||
import net.minecraftforge.fluids.BlockFluidFinite;
|
||||
import net.minecraftforge.fluids.Fluid;
|
||||
import net.minecraftforge.fluids.FluidRegistry;
|
||||
|
@ -92,7 +93,7 @@ public class FluidPlacementTest
|
|||
event.getRegistry().registerAll(
|
||||
EmptyFluidContainer.instance,
|
||||
FluidContainer.instance,
|
||||
new ItemBlock(FiniteFluidBlock.instance).setRegistryName(FiniteFluidBlock.instance.getRegistryName())
|
||||
new FluidItemBlock(FiniteFluidBlock.instance).setRegistryName(FiniteFluidBlock.instance.getRegistryName())
|
||||
);
|
||||
MinecraftForge.EVENT_BUS.register(FluidContainer.instance);
|
||||
}
|
||||
|
@ -132,7 +133,7 @@ public class FluidPlacementTest
|
|||
|
||||
private FiniteFluid()
|
||||
{
|
||||
super(name, new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"));
|
||||
super(name, new ResourceLocation("blocks/water_still"), new ResourceLocation("blocks/water_flow"), new ResourceLocation("blocks/water_overlay"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -162,6 +163,26 @@ public class FluidPlacementTest
|
|||
}
|
||||
}
|
||||
|
||||
public static final class FluidItemBlock extends ItemBlock
|
||||
{
|
||||
FluidItemBlock(BlockFluidBase block)
|
||||
{
|
||||
super(block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockFluidBase getBlock()
|
||||
{
|
||||
return (BlockFluidBase) super.getBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetadata(int damage)
|
||||
{
|
||||
return getBlock().getMaxRenderHeightMeta();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class EmptyFluidContainer extends ItemBucket
|
||||
{
|
||||
public static final EmptyFluidContainer instance = new EmptyFluidContainer();
|
||||
|
|
Loading…
Reference in a new issue