238 lines
10 KiB
Java
238 lines
10 KiB
Java
package net.minecraft.client.renderer;
|
|
|
|
import com.mojang.blaze3d.vertex.VertexConsumer;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import net.fabricmc.api.EnvType;
|
|
import net.fabricmc.api.Environment;
|
|
import net.minecraft.client.Camera;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.multiplayer.ClientLevel;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.SectionPos;
|
|
import net.minecraft.core.Direction.Axis;
|
|
import net.minecraft.core.particles.ParticleOptions;
|
|
import net.minecraft.core.particles.ParticleTypes;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.server.level.ParticleStatus;
|
|
import net.minecraft.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.tags.FluidTags;
|
|
import net.minecraft.util.ARGB;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.biome.Biome;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.CampfireBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.levelgen.Heightmap.Types;
|
|
import net.minecraft.world.level.material.FluidState;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
public class WeatherEffectRenderer {
|
|
private static final int RAIN_RADIUS = 10;
|
|
private static final int RAIN_DIAMETER = 21;
|
|
private static final ResourceLocation RAIN_LOCATION = ResourceLocation.withDefaultNamespace("textures/environment/rain.png");
|
|
private static final ResourceLocation SNOW_LOCATION = ResourceLocation.withDefaultNamespace("textures/environment/snow.png");
|
|
private static final int RAIN_TABLE_SIZE = 32;
|
|
private static final int HALF_RAIN_TABLE_SIZE = 16;
|
|
private int rainSoundTime;
|
|
private final float[] columnSizeX = new float[1024];
|
|
private final float[] columnSizeZ = new float[1024];
|
|
|
|
public WeatherEffectRenderer() {
|
|
for (int i = 0; i < 32; i++) {
|
|
for (int j = 0; j < 32; j++) {
|
|
float f = j - 16;
|
|
float g = i - 16;
|
|
float h = Mth.length(f, g);
|
|
this.columnSizeX[i * 32 + j] = -g / h;
|
|
this.columnSizeZ[i * 32 + j] = f / h;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void render(Level level, MultiBufferSource bufferSource, int ticks, float partialTick, Vec3 cameraPosition) {
|
|
float f = level.getRainLevel(partialTick);
|
|
if (!(f <= 0.0F)) {
|
|
int i = Minecraft.useFancyGraphics() ? 10 : 5;
|
|
List<WeatherEffectRenderer.ColumnInstance> list = new ArrayList();
|
|
List<WeatherEffectRenderer.ColumnInstance> list2 = new ArrayList();
|
|
this.collectColumnInstances(level, ticks, partialTick, cameraPosition, i, list, list2);
|
|
if (!list.isEmpty() || !list2.isEmpty()) {
|
|
this.render(bufferSource, cameraPosition, i, f, list, list2);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void collectColumnInstances(
|
|
Level level,
|
|
int ticks,
|
|
float partialTick,
|
|
Vec3 cameraPosition,
|
|
int radius,
|
|
List<WeatherEffectRenderer.ColumnInstance> rainColumnInstances,
|
|
List<WeatherEffectRenderer.ColumnInstance> snowColumnInstances
|
|
) {
|
|
int i = Mth.floor(cameraPosition.x);
|
|
int j = Mth.floor(cameraPosition.y);
|
|
int k = Mth.floor(cameraPosition.z);
|
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
RandomSource randomSource = RandomSource.create();
|
|
|
|
for (int l = k - radius; l <= k + radius; l++) {
|
|
for (int m = i - radius; m <= i + radius; m++) {
|
|
int n = level.getHeight(Types.MOTION_BLOCKING, m, l);
|
|
int o = Math.max(j - radius, n);
|
|
int p = Math.max(j + radius, n);
|
|
if (p - o != 0) {
|
|
Biome.Precipitation precipitation = this.getPrecipitationAt(level, mutableBlockPos.set(m, j, l));
|
|
if (precipitation != Biome.Precipitation.NONE) {
|
|
int q = m * m * 3121 + m * 45238971 ^ l * l * 418711 + l * 13761;
|
|
randomSource.setSeed(q);
|
|
int r = Math.max(j, n);
|
|
int s = LevelRenderer.getLightColor(level, mutableBlockPos.set(m, r, l));
|
|
if (precipitation == Biome.Precipitation.RAIN) {
|
|
rainColumnInstances.add(this.createRainColumnInstance(randomSource, ticks, m, o, p, l, s, partialTick));
|
|
} else if (precipitation == Biome.Precipitation.SNOW) {
|
|
snowColumnInstances.add(this.createSnowColumnInstance(randomSource, ticks, m, o, p, l, s, partialTick));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void render(
|
|
MultiBufferSource bufferSource,
|
|
Vec3 cameraPosition,
|
|
int radius,
|
|
float rainLevel,
|
|
List<WeatherEffectRenderer.ColumnInstance> rainColumnInstances,
|
|
List<WeatherEffectRenderer.ColumnInstance> snowColumnInstances
|
|
) {
|
|
if (!rainColumnInstances.isEmpty()) {
|
|
RenderType renderType = RenderType.weather(RAIN_LOCATION, Minecraft.useShaderTransparency());
|
|
this.renderInstances(bufferSource.getBuffer(renderType), rainColumnInstances, cameraPosition, 1.0F, radius, rainLevel);
|
|
}
|
|
|
|
if (!snowColumnInstances.isEmpty()) {
|
|
RenderType renderType = RenderType.weather(SNOW_LOCATION, Minecraft.useShaderTransparency());
|
|
this.renderInstances(bufferSource.getBuffer(renderType), snowColumnInstances, cameraPosition, 0.8F, radius, rainLevel);
|
|
}
|
|
}
|
|
|
|
private WeatherEffectRenderer.ColumnInstance createRainColumnInstance(
|
|
RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTick
|
|
) {
|
|
int i = ticks & 131071;
|
|
int j = x * x * 3121 + x * 45238971 + z * z * 418711 + z * 13761 & 0xFF;
|
|
float f = 3.0F + random.nextFloat();
|
|
float g = -(i + j + partialTick) / 32.0F * f;
|
|
float h = g % 32.0F;
|
|
return new WeatherEffectRenderer.ColumnInstance(x, z, bottomY, topY, 0.0F, h, lightCoords);
|
|
}
|
|
|
|
private WeatherEffectRenderer.ColumnInstance createSnowColumnInstance(
|
|
RandomSource random, int ticks, int x, int bottomY, int topY, int z, int lightCoords, float partialTick
|
|
) {
|
|
float f = ticks + partialTick;
|
|
float g = (float)(random.nextDouble() + f * 0.01F * (float)random.nextGaussian());
|
|
float h = (float)(random.nextDouble() + f * (float)random.nextGaussian() * 0.001F);
|
|
float i = -((ticks & 511) + partialTick) / 512.0F;
|
|
int j = LightTexture.pack((LightTexture.block(lightCoords) * 3 + 15) / 4, (LightTexture.sky(lightCoords) * 3 + 15) / 4);
|
|
return new WeatherEffectRenderer.ColumnInstance(x, z, bottomY, topY, g, i + h, j);
|
|
}
|
|
|
|
private void renderInstances(
|
|
VertexConsumer buffer, List<WeatherEffectRenderer.ColumnInstance> columnInstances, Vec3 cameraPosition, float amount, int radius, float rainLevel
|
|
) {
|
|
for (WeatherEffectRenderer.ColumnInstance columnInstance : columnInstances) {
|
|
float f = (float)(columnInstance.x + 0.5 - cameraPosition.x);
|
|
float g = (float)(columnInstance.z + 0.5 - cameraPosition.z);
|
|
float h = (float)Mth.lengthSquared(f, g);
|
|
float i = Mth.lerp(h / (radius * radius), amount, 0.5F) * rainLevel;
|
|
int j = ARGB.white(i);
|
|
int k = (columnInstance.z - Mth.floor(cameraPosition.z) + 16) * 32 + columnInstance.x - Mth.floor(cameraPosition.x) + 16;
|
|
float l = this.columnSizeX[k] / 2.0F;
|
|
float m = this.columnSizeZ[k] / 2.0F;
|
|
float n = f - l;
|
|
float o = f + l;
|
|
float p = (float)(columnInstance.topY - cameraPosition.y);
|
|
float q = (float)(columnInstance.bottomY - cameraPosition.y);
|
|
float r = g - m;
|
|
float s = g + m;
|
|
float t = columnInstance.uOffset + 0.0F;
|
|
float u = columnInstance.uOffset + 1.0F;
|
|
float v = columnInstance.bottomY * 0.25F + columnInstance.vOffset;
|
|
float w = columnInstance.topY * 0.25F + columnInstance.vOffset;
|
|
buffer.addVertex(n, p, r).setUv(t, v).setColor(j).setLight(columnInstance.lightCoords);
|
|
buffer.addVertex(o, p, s).setUv(u, v).setColor(j).setLight(columnInstance.lightCoords);
|
|
buffer.addVertex(o, q, s).setUv(u, w).setColor(j).setLight(columnInstance.lightCoords);
|
|
buffer.addVertex(n, q, r).setUv(t, w).setColor(j).setLight(columnInstance.lightCoords);
|
|
}
|
|
}
|
|
|
|
public void tickRainParticles(ClientLevel level, Camera camera, int ticks, ParticleStatus particleStatus) {
|
|
float f = level.getRainLevel(1.0F) / (Minecraft.useFancyGraphics() ? 1.0F : 2.0F);
|
|
if (!(f <= 0.0F)) {
|
|
RandomSource randomSource = RandomSource.create(ticks * 312987231L);
|
|
BlockPos blockPos = BlockPos.containing(camera.getPosition());
|
|
BlockPos blockPos2 = null;
|
|
int i = (int)(100.0F * f * f) / (particleStatus == ParticleStatus.DECREASED ? 2 : 1);
|
|
|
|
for (int j = 0; j < i; j++) {
|
|
int k = randomSource.nextInt(21) - 10;
|
|
int l = randomSource.nextInt(21) - 10;
|
|
BlockPos blockPos3 = level.getHeightmapPos(Types.MOTION_BLOCKING, blockPos.offset(k, 0, l));
|
|
if (blockPos3.getY() > level.getMinY()
|
|
&& blockPos3.getY() <= blockPos.getY() + 10
|
|
&& blockPos3.getY() >= blockPos.getY() - 10
|
|
&& this.getPrecipitationAt(level, blockPos3) == Biome.Precipitation.RAIN) {
|
|
blockPos2 = blockPos3.below();
|
|
if (particleStatus == ParticleStatus.MINIMAL) {
|
|
break;
|
|
}
|
|
|
|
double d = randomSource.nextDouble();
|
|
double e = randomSource.nextDouble();
|
|
BlockState blockState = level.getBlockState(blockPos2);
|
|
FluidState fluidState = level.getFluidState(blockPos2);
|
|
VoxelShape voxelShape = blockState.getCollisionShape(level, blockPos2);
|
|
double g = voxelShape.max(Axis.Y, d, e);
|
|
double h = fluidState.getHeight(level, blockPos2);
|
|
double m = Math.max(g, h);
|
|
ParticleOptions particleOptions = !fluidState.is(FluidTags.LAVA) && !blockState.is(Blocks.MAGMA_BLOCK) && !CampfireBlock.isLitCampfire(blockState)
|
|
? ParticleTypes.RAIN
|
|
: ParticleTypes.SMOKE;
|
|
level.addParticle(particleOptions, blockPos2.getX() + d, blockPos2.getY() + m, blockPos2.getZ() + e, 0.0, 0.0, 0.0);
|
|
}
|
|
}
|
|
|
|
if (blockPos2 != null && randomSource.nextInt(3) < this.rainSoundTime++) {
|
|
this.rainSoundTime = 0;
|
|
if (blockPos2.getY() > blockPos.getY() + 1 && level.getHeightmapPos(Types.MOTION_BLOCKING, blockPos).getY() > Mth.floor((float)blockPos.getY())) {
|
|
level.playLocalSound(blockPos2, SoundEvents.WEATHER_RAIN_ABOVE, SoundSource.WEATHER, 0.1F, 0.5F, false);
|
|
} else {
|
|
level.playLocalSound(blockPos2, SoundEvents.WEATHER_RAIN, SoundSource.WEATHER, 0.2F, 1.0F, false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private Biome.Precipitation getPrecipitationAt(Level level, BlockPos pos) {
|
|
if (!level.getChunkSource().hasChunk(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ()))) {
|
|
return Biome.Precipitation.NONE;
|
|
} else {
|
|
Biome biome = level.getBiome(pos).value();
|
|
return biome.getPrecipitationAt(pos, level.getSeaLevel());
|
|
}
|
|
}
|
|
|
|
@Environment(EnvType.CLIENT)
|
|
record ColumnInstance(int x, int z, int bottomY, int topY, float uOffset, float vOffset, int lightCoords) {
|
|
}
|
|
}
|