minecraft-src/net/minecraft/client/renderer/LevelRenderer.java
2025-07-04 03:45:38 +03:00

1421 lines
57 KiB
Java

package net.minecraft.client.renderer;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder;
import com.mojang.blaze3d.framegraph.FramePass;
import com.mojang.blaze3d.framegraph.FrameGraphBuilder.Inspector;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.pipeline.RenderTarget;
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.Lighting;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.resource.RenderTargetDescriptor;
import com.mojang.blaze3d.resource.ResourceHandle;
import com.mojang.blaze3d.systems.RenderPass;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.textures.GpuTexture;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.SheetedDecalTextureGenerator;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.blaze3d.vertex.VertexFormat;
import com.mojang.blaze3d.vertex.VertexMultiConsumer;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.ObjectListIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.OptionalDouble;
import java.util.OptionalInt;
import java.util.Set;
import java.util.SortedSet;
import java.util.function.Supplier;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.CrashReport;
import net.minecraft.CrashReportCategory;
import net.minecraft.CrashReportDetail;
import net.minecraft.ReportedException;
import net.minecraft.Util;
import net.minecraft.client.Camera;
import net.minecraft.client.CloudStatus;
import net.minecraft.client.DeltaTracker;
import net.minecraft.client.GraphicsStatus;
import net.minecraft.client.Minecraft;
import net.minecraft.client.PrioritizeChunkUpdates;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.client.renderer.DimensionSpecialEffects.SkyType;
import net.minecraft.client.renderer.FogRenderer.FogMode;
import net.minecraft.client.renderer.MultiBufferSource.BufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher;
import net.minecraft.client.renderer.chunk.RenderRegionCache;
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
import net.minecraft.client.renderer.culling.Frustum;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.resources.model.ModelBakery;
import net.minecraft.core.BlockPos;
import net.minecraft.core.SectionPos;
import net.minecraft.core.particles.ParticleOptions;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.NbtOps;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.BlockDestructionProgress;
import net.minecraft.server.level.ParticleStatus;
import net.minecraft.server.packs.resources.ResourceManager;
import net.minecraft.server.packs.resources.ResourceManagerReloadListener;
import net.minecraft.util.ARGB;
import net.minecraft.util.Brightness;
import net.minecraft.util.Mth;
import net.minecraft.util.VisibleForDebug;
import net.minecraft.util.profiling.Profiler;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.util.profiling.Zone;
import net.minecraft.world.TickRateManager;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.FogType;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.HitResult.Type;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.jetbrains.annotations.Nullable;
import org.joml.Matrix4f;
import org.joml.Matrix4fStack;
import org.joml.Vector4f;
import org.slf4j.Logger;
@Environment(EnvType.CLIENT)
public class LevelRenderer implements ResourceManagerReloadListener, AutoCloseable {
private static final Logger LOGGER = LogUtils.getLogger();
private static final ResourceLocation TRANSPARENCY_POST_CHAIN_ID = ResourceLocation.withDefaultNamespace("transparency");
private static final ResourceLocation ENTITY_OUTLINE_POST_CHAIN_ID = ResourceLocation.withDefaultNamespace("entity_outline");
public static final int SECTION_SIZE = 16;
public static final int HALF_SECTION_SIZE = 8;
public static final int NEARBY_SECTION_DISTANCE_IN_BLOCKS = 32;
private static final int MINIMUM_TRANSPARENT_SORT_COUNT = 15;
private final Minecraft minecraft;
private final EntityRenderDispatcher entityRenderDispatcher;
private final BlockEntityRenderDispatcher blockEntityRenderDispatcher;
private final RenderBuffers renderBuffers;
private final SkyRenderer skyRenderer = new SkyRenderer();
private final CloudRenderer cloudRenderer = new CloudRenderer();
private final WorldBorderRenderer worldBorderRenderer = new WorldBorderRenderer();
private final WeatherEffectRenderer weatherEffectRenderer = new WeatherEffectRenderer();
@Nullable
private ClientLevel level;
private final SectionOcclusionGraph sectionOcclusionGraph = new SectionOcclusionGraph();
private final ObjectArrayList<SectionRenderDispatcher.RenderSection> visibleSections = new ObjectArrayList<>(10000);
private final ObjectArrayList<SectionRenderDispatcher.RenderSection> nearbyVisibleSections = new ObjectArrayList<>(50);
/**
* Global block entities; these are always rendered, even if off-screen.
* Any block entity is added to this if {@link net.minecraft.client.renderer.blockentity.BlockEntityRenderer#shouldRenderOffScreen(net.minecraft.world.level.block.entity.BlockEntity)} returns {@code true}.
*/
private final Set<BlockEntity> globalBlockEntities = Sets.<BlockEntity>newHashSet();
@Nullable
private ViewArea viewArea;
private int ticks;
private final Int2ObjectMap<BlockDestructionProgress> destroyingBlocks = new Int2ObjectOpenHashMap<>();
private final Long2ObjectMap<SortedSet<BlockDestructionProgress>> destructionProgress = new Long2ObjectOpenHashMap<>();
@Nullable
private RenderTarget entityOutlineTarget;
private final LevelTargetBundle targets = new LevelTargetBundle();
private int lastCameraSectionX = Integer.MIN_VALUE;
private int lastCameraSectionY = Integer.MIN_VALUE;
private int lastCameraSectionZ = Integer.MIN_VALUE;
private double prevCamX = Double.MIN_VALUE;
private double prevCamY = Double.MIN_VALUE;
private double prevCamZ = Double.MIN_VALUE;
private double prevCamRotX = Double.MIN_VALUE;
private double prevCamRotY = Double.MIN_VALUE;
@Nullable
private SectionRenderDispatcher sectionRenderDispatcher;
private int lastViewDistance = -1;
private final List<Entity> visibleEntities = new ArrayList();
private int visibleEntityCount;
private Frustum cullingFrustum;
private boolean captureFrustum;
@Nullable
private Frustum capturedFrustum;
@Nullable
private BlockPos lastTranslucentSortBlockPos;
private int translucencyResortIterationIndex;
public LevelRenderer(
Minecraft minecraft, EntityRenderDispatcher entityRenderDispatcher, BlockEntityRenderDispatcher blockEntityRenderDispatcher, RenderBuffers renderBuffers
) {
this.minecraft = minecraft;
this.entityRenderDispatcher = entityRenderDispatcher;
this.blockEntityRenderDispatcher = blockEntityRenderDispatcher;
this.renderBuffers = renderBuffers;
}
public void tickParticles(Camera camera) {
this.weatherEffectRenderer.tickRainParticles(this.minecraft.level, camera, this.ticks, this.minecraft.options.particles().get());
}
public void close() {
if (this.entityOutlineTarget != null) {
this.entityOutlineTarget.destroyBuffers();
}
this.skyRenderer.close();
this.cloudRenderer.close();
}
@Override
public void onResourceManagerReload(ResourceManager resourceManager) {
this.initOutline();
}
public void initOutline() {
if (this.entityOutlineTarget != null) {
this.entityOutlineTarget.destroyBuffers();
}
this.entityOutlineTarget = new TextureTarget("Entity Outline", this.minecraft.getWindow().getWidth(), this.minecraft.getWindow().getHeight(), true);
}
@Nullable
private PostChain getTransparencyChain() {
if (!Minecraft.useShaderTransparency()) {
return null;
} else {
PostChain postChain = this.minecraft.getShaderManager().getPostChain(TRANSPARENCY_POST_CHAIN_ID, LevelTargetBundle.SORTING_TARGETS);
if (postChain == null) {
this.minecraft.options.graphicsMode().set(GraphicsStatus.FANCY);
this.minecraft.options.save();
}
return postChain;
}
}
public void doEntityOutline() {
if (this.shouldShowEntityOutlines()) {
this.entityOutlineTarget.blitAndBlendToTexture(this.minecraft.getMainRenderTarget().getColorTexture());
}
}
protected boolean shouldShowEntityOutlines() {
return !this.minecraft.gameRenderer.isPanoramicMode() && this.entityOutlineTarget != null && this.minecraft.player != null;
}
/**
* @param level the level to set, or {@code null} to clear
*/
public void setLevel(@Nullable ClientLevel level) {
this.lastCameraSectionX = Integer.MIN_VALUE;
this.lastCameraSectionY = Integer.MIN_VALUE;
this.lastCameraSectionZ = Integer.MIN_VALUE;
this.entityRenderDispatcher.setLevel(level);
this.level = level;
if (level != null) {
this.allChanged();
} else {
if (this.viewArea != null) {
this.viewArea.releaseAllBuffers();
this.viewArea = null;
}
if (this.sectionRenderDispatcher != null) {
this.sectionRenderDispatcher.dispose();
}
this.sectionRenderDispatcher = null;
this.globalBlockEntities.clear();
this.sectionOcclusionGraph.waitAndReset(null);
this.clearVisibleSections();
}
}
private void clearVisibleSections() {
this.visibleSections.clear();
this.nearbyVisibleSections.clear();
}
/**
* Loads all renderers and sets up the basic options usage.
*/
public void allChanged() {
if (this.level != null) {
this.level.clearTintCaches();
if (this.sectionRenderDispatcher == null) {
this.sectionRenderDispatcher = new SectionRenderDispatcher(
this.level, this, Util.backgroundExecutor(), this.renderBuffers, this.minecraft.getBlockRenderer(), this.minecraft.getBlockEntityRenderDispatcher()
);
} else {
this.sectionRenderDispatcher.setLevel(this.level);
}
this.cloudRenderer.markForRebuild();
ItemBlockRenderTypes.setFancy(Minecraft.useFancyGraphics());
this.lastViewDistance = this.minecraft.options.getEffectiveRenderDistance();
if (this.viewArea != null) {
this.viewArea.releaseAllBuffers();
}
this.sectionRenderDispatcher.blockUntilClear();
synchronized (this.globalBlockEntities) {
this.globalBlockEntities.clear();
}
this.viewArea = new ViewArea(this.sectionRenderDispatcher, this.level, this.minecraft.options.getEffectiveRenderDistance(), this);
this.sectionOcclusionGraph.waitAndReset(this.viewArea);
this.clearVisibleSections();
Camera camera = this.minecraft.gameRenderer.getMainCamera();
this.viewArea.repositionCamera(SectionPos.of(camera.getPosition()));
}
}
public void resize(int width, int height) {
this.needsUpdate();
if (this.entityOutlineTarget != null) {
this.entityOutlineTarget.resize(width, height);
}
}
public String getSectionStatistics() {
int i = this.viewArea.sections.length;
int j = this.countRenderedSections();
return String.format(
Locale.ROOT,
"C: %d/%d %sD: %d, %s",
j,
i,
this.minecraft.smartCull ? "(s) " : "",
this.lastViewDistance,
this.sectionRenderDispatcher == null ? "null" : this.sectionRenderDispatcher.getStats()
);
}
public SectionRenderDispatcher getSectionRenderDispatcher() {
return this.sectionRenderDispatcher;
}
public double getTotalSections() {
return this.viewArea.sections.length;
}
public double getLastViewDistance() {
return this.lastViewDistance;
}
public int countRenderedSections() {
int i = 0;
for (SectionRenderDispatcher.RenderSection renderSection : this.visibleSections) {
if (renderSection.getCompiled().hasRenderableLayers()) {
i++;
}
}
return i;
}
/**
* @return entity rendering statistics to display on the {@linkplain net.minecraft.client.gui.components.DebugScreenOverlay debug overlay}
*/
public String getEntityStatistics() {
return "E: " + this.visibleEntityCount + "/" + this.level.getEntityCount() + ", SD: " + this.level.getServerSimulationDistance();
}
private void setupRender(Camera camera, Frustum frustum, boolean hasCapturedFrustum, boolean isSpectator) {
Vec3 vec3 = camera.getPosition();
if (this.minecraft.options.getEffectiveRenderDistance() != this.lastViewDistance) {
this.allChanged();
}
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("camera");
int i = SectionPos.posToSectionCoord(vec3.x());
int j = SectionPos.posToSectionCoord(vec3.y());
int k = SectionPos.posToSectionCoord(vec3.z());
if (this.lastCameraSectionX != i || this.lastCameraSectionY != j || this.lastCameraSectionZ != k) {
this.lastCameraSectionX = i;
this.lastCameraSectionY = j;
this.lastCameraSectionZ = k;
this.viewArea.repositionCamera(SectionPos.of(vec3));
this.worldBorderRenderer.invalidate();
}
this.sectionRenderDispatcher.setCamera(vec3);
profilerFiller.popPush("cull");
double d = Math.floor(vec3.x / 8.0);
double e = Math.floor(vec3.y / 8.0);
double f = Math.floor(vec3.z / 8.0);
if (d != this.prevCamX || e != this.prevCamY || f != this.prevCamZ) {
this.sectionOcclusionGraph.invalidate();
}
this.prevCamX = d;
this.prevCamY = e;
this.prevCamZ = f;
profilerFiller.popPush("update");
if (!hasCapturedFrustum) {
boolean bl = this.minecraft.smartCull;
if (isSpectator && this.level.getBlockState(camera.getBlockPosition()).isSolidRender()) {
bl = false;
}
profilerFiller.push("section_occlusion_graph");
this.sectionOcclusionGraph.update(bl, camera, frustum, this.visibleSections, this.level.getChunkSource().getLoadedEmptySections());
profilerFiller.pop();
double g = Math.floor(camera.getXRot() / 2.0F);
double h = Math.floor(camera.getYRot() / 2.0F);
if (this.sectionOcclusionGraph.consumeFrustumUpdate() || g != this.prevCamRotX || h != this.prevCamRotY) {
this.applyFrustum(offsetFrustum(frustum));
this.prevCamRotX = g;
this.prevCamRotY = h;
}
}
profilerFiller.pop();
}
public static Frustum offsetFrustum(Frustum frustum) {
return new Frustum(frustum).offsetToFullyIncludeCameraCube(8);
}
private void applyFrustum(Frustum frustum) {
if (!Minecraft.getInstance().isSameThread()) {
throw new IllegalStateException("applyFrustum called from wrong thread: " + Thread.currentThread().getName());
} else {
Profiler.get().push("apply_frustum");
this.clearVisibleSections();
this.sectionOcclusionGraph.addSectionsInFrustum(frustum, this.visibleSections, this.nearbyVisibleSections);
Profiler.get().pop();
}
}
public void addRecentlyCompiledSection(SectionRenderDispatcher.RenderSection renderSection) {
this.sectionOcclusionGraph.schedulePropagationFrom(renderSection);
}
public void prepareCullFrustum(Vec3 cameraPosition, Matrix4f frustumMatrix, Matrix4f projectionMatrix) {
this.cullingFrustum = new Frustum(frustumMatrix, projectionMatrix);
this.cullingFrustum.prepare(cameraPosition.x(), cameraPosition.y(), cameraPosition.z());
}
public void renderLevel(
GraphicsResourceAllocator graphicsResourceAllocator,
DeltaTracker deltaTracker,
boolean renderBlockOutline,
Camera camera,
GameRenderer gameRenderer,
Matrix4f frustumMatrix,
Matrix4f projectionMatrix
) {
float f = deltaTracker.getGameTimeDeltaPartialTick(false);
RenderSystem.setShaderGameTime(this.level.getGameTime(), f);
this.blockEntityRenderDispatcher.prepare(this.level, camera, this.minecraft.hitResult);
this.entityRenderDispatcher.prepare(this.level, camera, this.minecraft.crosshairPickEntity);
final ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.popPush("light_update_queue");
this.level.pollLightUpdates();
profilerFiller.popPush("light_updates");
this.level.getChunkSource().getLightEngine().runLightUpdates();
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double g = vec3.z();
profilerFiller.popPush("culling");
boolean bl = this.capturedFrustum != null;
Frustum frustum = bl ? this.capturedFrustum : this.cullingFrustum;
Profiler.get().popPush("captureFrustum");
if (this.captureFrustum) {
this.capturedFrustum = bl ? new Frustum(frustumMatrix, projectionMatrix) : frustum;
this.capturedFrustum.prepare(d, e, g);
this.captureFrustum = false;
}
profilerFiller.popPush("fog");
float h = gameRenderer.getRenderDistance();
boolean bl2 = this.minecraft.level.effects().isFoggyAt(Mth.floor(d), Mth.floor(e)) || this.minecraft.gui.getBossOverlay().shouldCreateWorldFog();
Vector4f vector4f = FogRenderer.computeFogColor(
camera, f, this.minecraft.level, this.minecraft.options.getEffectiveRenderDistance(), gameRenderer.getDarkenWorldAmount(f)
);
FogParameters fogParameters = FogRenderer.setupFog(camera, FogMode.FOG_TERRAIN, vector4f, h, bl2, f);
FogParameters fogParameters2 = FogRenderer.setupFog(camera, FogMode.FOG_SKY, vector4f, h, bl2, f);
profilerFiller.popPush("cullEntities");
boolean bl3 = this.collectVisibleEntities(camera, frustum, this.visibleEntities);
this.visibleEntityCount = this.visibleEntities.size();
profilerFiller.popPush("terrain_setup");
this.setupRender(camera, frustum, bl, this.minecraft.player.isSpectator());
profilerFiller.popPush("compile_sections");
this.compileSections(camera);
Matrix4fStack matrix4fStack = RenderSystem.getModelViewStack();
matrix4fStack.pushMatrix();
matrix4fStack.mul(frustumMatrix);
FrameGraphBuilder frameGraphBuilder = new FrameGraphBuilder();
this.targets.main = frameGraphBuilder.importExternal("main", this.minecraft.getMainRenderTarget());
int i = this.minecraft.getMainRenderTarget().width;
int j = this.minecraft.getMainRenderTarget().height;
RenderTargetDescriptor renderTargetDescriptor = new RenderTargetDescriptor(i, j, true, 0);
PostChain postChain = this.getTransparencyChain();
if (postChain != null) {
this.targets.translucent = frameGraphBuilder.createInternal("translucent", renderTargetDescriptor);
this.targets.itemEntity = frameGraphBuilder.createInternal("item_entity", renderTargetDescriptor);
this.targets.particles = frameGraphBuilder.createInternal("particles", renderTargetDescriptor);
this.targets.weather = frameGraphBuilder.createInternal("weather", renderTargetDescriptor);
this.targets.clouds = frameGraphBuilder.createInternal("clouds", renderTargetDescriptor);
}
if (this.entityOutlineTarget != null) {
this.targets.entityOutline = frameGraphBuilder.importExternal("entity_outline", this.entityOutlineTarget);
}
FramePass framePass = frameGraphBuilder.addPass("clear");
this.targets.main = framePass.readsAndWrites(this.targets.main);
framePass.executes(
() -> {
RenderTarget renderTarget = this.minecraft.getMainRenderTarget();
RenderSystem.getDevice()
.createCommandEncoder()
.clearColorAndDepthTextures(
renderTarget.getColorTexture(), ARGB.colorFromFloat(0.0F, vector4f.x, vector4f.y, vector4f.z), renderTarget.getDepthTexture(), 1.0
);
}
);
if (!bl2) {
this.addSkyPass(frameGraphBuilder, camera, f, fogParameters2);
}
this.addMainPass(frameGraphBuilder, frustum, camera, frustumMatrix, projectionMatrix, fogParameters, renderBlockOutline, bl3, deltaTracker, profilerFiller);
PostChain postChain2 = this.minecraft.getShaderManager().getPostChain(ENTITY_OUTLINE_POST_CHAIN_ID, LevelTargetBundle.OUTLINE_TARGETS);
if (bl3 && postChain2 != null) {
postChain2.addToFrame(frameGraphBuilder, i, j, this.targets, null);
}
this.addParticlesPass(frameGraphBuilder, camera, f, fogParameters);
CloudStatus cloudStatus = this.minecraft.options.getCloudsType();
if (cloudStatus != CloudStatus.OFF) {
float k = this.level.effects().getCloudHeight();
if (!Float.isNaN(k)) {
float l = this.ticks + f;
int m = this.level.getCloudColor(f);
this.addCloudsPass(frameGraphBuilder, cloudStatus, camera.getPosition(), l, m, k + 0.33F);
}
}
this.addWeatherPass(frameGraphBuilder, camera.getPosition(), f, fogParameters);
if (postChain != null) {
postChain.addToFrame(frameGraphBuilder, i, j, this.targets, null);
}
this.addLateDebugPass(frameGraphBuilder, vec3, fogParameters);
profilerFiller.popPush("framegraph");
frameGraphBuilder.execute(graphicsResourceAllocator, new Inspector() {
@Override
public void beforeExecutePass(String name) {
profilerFiller.push(name);
}
@Override
public void afterExecutePass(String name) {
profilerFiller.pop();
}
});
this.visibleEntities.clear();
this.targets.clear();
matrix4fStack.popMatrix();
RenderSystem.setShaderFog(FogParameters.NO_FOG);
}
private void addMainPass(
FrameGraphBuilder frameGraphBuilder,
Frustum frustum,
Camera camera,
Matrix4f frustumMatrix,
Matrix4f projectionMatrix,
FogParameters fogParameters,
boolean renderBlockOutline,
boolean renderEntityOutline,
DeltaTracker deltaTracker,
ProfilerFiller profiler
) {
FramePass framePass = frameGraphBuilder.addPass("main");
this.targets.main = framePass.readsAndWrites(this.targets.main);
if (this.targets.translucent != null) {
this.targets.translucent = framePass.readsAndWrites(this.targets.translucent);
}
if (this.targets.itemEntity != null) {
this.targets.itemEntity = framePass.readsAndWrites(this.targets.itemEntity);
}
if (this.targets.weather != null) {
this.targets.weather = framePass.readsAndWrites(this.targets.weather);
}
if (renderEntityOutline && this.targets.entityOutline != null) {
this.targets.entityOutline = framePass.readsAndWrites(this.targets.entityOutline);
}
ResourceHandle<RenderTarget> resourceHandle = this.targets.main;
ResourceHandle<RenderTarget> resourceHandle2 = this.targets.translucent;
ResourceHandle<RenderTarget> resourceHandle3 = this.targets.itemEntity;
ResourceHandle<RenderTarget> resourceHandle4 = this.targets.entityOutline;
framePass.executes(() -> {
RenderSystem.setShaderFog(fogParameters);
float f = deltaTracker.getGameTimeDeltaPartialTick(false);
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double g = vec3.z();
profiler.push("terrain");
this.renderSectionLayer(RenderType.solid(), d, e, g, frustumMatrix, projectionMatrix);
this.renderSectionLayer(RenderType.cutoutMipped(), d, e, g, frustumMatrix, projectionMatrix);
this.renderSectionLayer(RenderType.cutout(), d, e, g, frustumMatrix, projectionMatrix);
if (this.level.effects().constantAmbientLight()) {
Lighting.setupNetherLevel();
} else {
Lighting.setupLevel();
}
if (resourceHandle3 != null) {
resourceHandle3.get().copyDepthFrom(this.minecraft.getMainRenderTarget());
}
if (this.shouldShowEntityOutlines() && resourceHandle4 != null) {
RenderTarget renderTarget = resourceHandle4.get();
RenderSystem.getDevice().createCommandEncoder().clearColorAndDepthTextures(renderTarget.getColorTexture(), 0, renderTarget.getDepthTexture(), 1.0);
}
PoseStack poseStack = new PoseStack();
BufferSource bufferSource = this.renderBuffers.bufferSource();
BufferSource bufferSource2 = this.renderBuffers.crumblingBufferSource();
profiler.popPush("entities");
this.renderEntities(poseStack, bufferSource, camera, deltaTracker, this.visibleEntities);
bufferSource.endLastBatch();
this.checkPoseStack(poseStack);
profiler.popPush("blockentities");
this.renderBlockEntities(poseStack, bufferSource, bufferSource2, camera, f);
bufferSource.endLastBatch();
this.checkPoseStack(poseStack);
bufferSource.endBatch(RenderType.solid());
bufferSource.endBatch(RenderType.endPortal());
bufferSource.endBatch(RenderType.endGateway());
bufferSource.endBatch(Sheets.solidBlockSheet());
bufferSource.endBatch(Sheets.cutoutBlockSheet());
bufferSource.endBatch(Sheets.bedSheet());
bufferSource.endBatch(Sheets.shulkerBoxSheet());
bufferSource.endBatch(Sheets.signSheet());
bufferSource.endBatch(Sheets.hangingSignSheet());
bufferSource.endBatch(Sheets.chestSheet());
this.renderBuffers.outlineBufferSource().endOutlineBatch();
if (renderBlockOutline) {
this.renderBlockOutline(camera, bufferSource, poseStack, false);
}
profiler.popPush("debug");
this.minecraft.debugRenderer.render(poseStack, frustum, bufferSource, d, e, g);
bufferSource.endLastBatch();
this.checkPoseStack(poseStack);
bufferSource.endBatch(Sheets.translucentItemSheet());
bufferSource.endBatch(Sheets.bannerSheet());
bufferSource.endBatch(Sheets.shieldSheet());
bufferSource.endBatch(RenderType.armorEntityGlint());
bufferSource.endBatch(RenderType.glint());
bufferSource.endBatch(RenderType.glintTranslucent());
bufferSource.endBatch(RenderType.entityGlint());
profiler.popPush("destroyProgress");
this.renderBlockDestroyAnimation(poseStack, camera, bufferSource2);
bufferSource2.endBatch();
this.checkPoseStack(poseStack);
bufferSource.endBatch(RenderType.waterMask());
bufferSource.endBatch();
if (resourceHandle2 != null) {
resourceHandle2.get().copyDepthFrom(resourceHandle.get());
}
profiler.popPush("translucent");
this.renderSectionLayer(RenderType.translucent(), d, e, g, frustumMatrix, projectionMatrix);
profiler.popPush("string");
this.renderSectionLayer(RenderType.tripwire(), d, e, g, frustumMatrix, projectionMatrix);
if (renderBlockOutline) {
this.renderBlockOutline(camera, bufferSource, poseStack, true);
}
bufferSource.endBatch();
profiler.pop();
});
}
private void addParticlesPass(FrameGraphBuilder frameGraphBuilder, Camera camera, float partialTick, FogParameters fog) {
FramePass framePass = frameGraphBuilder.addPass("particles");
if (this.targets.particles != null) {
this.targets.particles = framePass.readsAndWrites(this.targets.particles);
framePass.reads(this.targets.main);
} else {
this.targets.main = framePass.readsAndWrites(this.targets.main);
}
ResourceHandle<RenderTarget> resourceHandle = this.targets.main;
ResourceHandle<RenderTarget> resourceHandle2 = this.targets.particles;
framePass.executes(() -> {
RenderSystem.setShaderFog(fog);
if (resourceHandle2 != null) {
resourceHandle2.get().copyDepthFrom(resourceHandle.get());
}
this.minecraft.particleEngine.render(camera, partialTick, this.renderBuffers.bufferSource());
});
}
private void addCloudsPass(FrameGraphBuilder frameGraphBuilder, CloudStatus cloudStatus, Vec3 cameraPosition, float ticks, int cloudColor, float cloudHeight) {
FramePass framePass = frameGraphBuilder.addPass("clouds");
if (this.targets.clouds != null) {
this.targets.clouds = framePass.readsAndWrites(this.targets.clouds);
} else {
this.targets.main = framePass.readsAndWrites(this.targets.main);
}
framePass.executes(() -> this.cloudRenderer.render(cloudColor, cloudStatus, cloudHeight, cameraPosition, ticks));
}
private void addWeatherPass(FrameGraphBuilder frameGraphBuilder, Vec3 cameraPosition, float partialTick, FogParameters fog) {
int i = this.minecraft.options.getEffectiveRenderDistance() * 16;
float f = this.minecraft.gameRenderer.getDepthFar();
FramePass framePass = frameGraphBuilder.addPass("weather");
if (this.targets.weather != null) {
this.targets.weather = framePass.readsAndWrites(this.targets.weather);
} else {
this.targets.main = framePass.readsAndWrites(this.targets.main);
}
framePass.executes(() -> {
RenderSystem.setShaderFog(fog);
BufferSource bufferSource = this.renderBuffers.bufferSource();
this.weatherEffectRenderer.render(this.minecraft.level, bufferSource, this.ticks, partialTick, cameraPosition);
this.worldBorderRenderer.render(this.level.getWorldBorder(), cameraPosition, i, f);
bufferSource.endBatch();
});
}
private void addLateDebugPass(FrameGraphBuilder frameGraphBuilder, Vec3 cameraPosition, FogParameters fog) {
FramePass framePass = frameGraphBuilder.addPass("late_debug");
this.targets.main = framePass.readsAndWrites(this.targets.main);
if (this.targets.itemEntity != null) {
this.targets.itemEntity = framePass.readsAndWrites(this.targets.itemEntity);
}
ResourceHandle<RenderTarget> resourceHandle = this.targets.main;
framePass.executes(() -> {
RenderSystem.setShaderFog(fog);
PoseStack poseStack = new PoseStack();
BufferSource bufferSource = this.renderBuffers.bufferSource();
this.minecraft.debugRenderer.renderAfterTranslucents(poseStack, bufferSource, cameraPosition.x, cameraPosition.y, cameraPosition.z);
bufferSource.endLastBatch();
this.checkPoseStack(poseStack);
});
}
private boolean collectVisibleEntities(Camera camera, Frustum frustum, List<Entity> output) {
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double f = vec3.z();
boolean bl = false;
boolean bl2 = this.shouldShowEntityOutlines();
Entity.setViewScale(Mth.clamp(this.minecraft.options.getEffectiveRenderDistance() / 8.0, 1.0, 2.5) * this.minecraft.options.entityDistanceScaling().get());
for (Entity entity : this.level.entitiesForRendering()) {
if (this.entityRenderDispatcher.shouldRender(entity, frustum, d, e, f) || entity.hasIndirectPassenger(this.minecraft.player)) {
BlockPos blockPos = entity.blockPosition();
if ((this.level.isOutsideBuildHeight(blockPos.getY()) || this.isSectionCompiled(blockPos))
&& (entity != camera.getEntity() || camera.isDetached() || camera.getEntity() instanceof LivingEntity && ((LivingEntity)camera.getEntity()).isSleeping())
&& (!(entity instanceof LocalPlayer) || camera.getEntity() == entity)) {
output.add(entity);
if (bl2 && this.minecraft.shouldEntityAppearGlowing(entity)) {
bl = true;
}
}
}
}
return bl;
}
private void renderEntities(PoseStack poseStack, BufferSource bufferSource, Camera camera, DeltaTracker deltaTracker, List<Entity> entities) {
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double f = vec3.z();
TickRateManager tickRateManager = this.minecraft.level.tickRateManager();
boolean bl = this.shouldShowEntityOutlines();
for (Entity entity : entities) {
if (entity.tickCount == 0) {
entity.xOld = entity.getX();
entity.yOld = entity.getY();
entity.zOld = entity.getZ();
}
MultiBufferSource multiBufferSource;
if (bl && this.minecraft.shouldEntityAppearGlowing(entity)) {
OutlineBufferSource outlineBufferSource = this.renderBuffers.outlineBufferSource();
multiBufferSource = outlineBufferSource;
int i = entity.getTeamColor();
outlineBufferSource.setColor(ARGB.red(i), ARGB.green(i), ARGB.blue(i), 255);
} else {
multiBufferSource = bufferSource;
}
float g = deltaTracker.getGameTimeDeltaPartialTick(!tickRateManager.isEntityFrozen(entity));
this.renderEntity(entity, d, e, f, g, poseStack, multiBufferSource);
}
}
private void renderBlockEntities(PoseStack poseStack, BufferSource bufferSource, BufferSource crumblingBufferSource, Camera camera, float partialTick) {
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double f = vec3.z();
for (SectionRenderDispatcher.RenderSection renderSection : this.visibleSections) {
List<BlockEntity> list = renderSection.getCompiled().getRenderableBlockEntities();
if (!list.isEmpty()) {
for (BlockEntity blockEntity : list) {
BlockPos blockPos = blockEntity.getBlockPos();
MultiBufferSource multiBufferSource = bufferSource;
poseStack.pushPose();
poseStack.translate(blockPos.getX() - d, blockPos.getY() - e, blockPos.getZ() - f);
SortedSet<BlockDestructionProgress> sortedSet = this.destructionProgress.get(blockPos.asLong());
if (sortedSet != null && !sortedSet.isEmpty()) {
int i = ((BlockDestructionProgress)sortedSet.last()).getProgress();
if (i >= 0) {
PoseStack.Pose pose = poseStack.last();
VertexConsumer vertexConsumer = new SheetedDecalTextureGenerator(
crumblingBufferSource.getBuffer((RenderType)ModelBakery.DESTROY_TYPES.get(i)), pose, 1.0F
);
multiBufferSource = renderType -> {
VertexConsumer vertexConsumer2 = bufferSource.getBuffer(renderType);
return renderType.affectsCrumbling() ? VertexMultiConsumer.create(vertexConsumer, vertexConsumer2) : vertexConsumer2;
};
}
}
this.blockEntityRenderDispatcher.render(blockEntity, partialTick, poseStack, multiBufferSource);
poseStack.popPose();
}
}
}
synchronized (this.globalBlockEntities) {
for (BlockEntity blockEntity2 : this.globalBlockEntities) {
BlockPos blockPos2 = blockEntity2.getBlockPos();
poseStack.pushPose();
poseStack.translate(blockPos2.getX() - d, blockPos2.getY() - e, blockPos2.getZ() - f);
this.blockEntityRenderDispatcher.render(blockEntity2, partialTick, poseStack, bufferSource);
poseStack.popPose();
}
}
}
private void renderBlockDestroyAnimation(PoseStack poseStack, Camera camera, BufferSource bufferSource) {
Vec3 vec3 = camera.getPosition();
double d = vec3.x();
double e = vec3.y();
double f = vec3.z();
for (Entry<SortedSet<BlockDestructionProgress>> entry : this.destructionProgress.long2ObjectEntrySet()) {
BlockPos blockPos = BlockPos.of(entry.getLongKey());
if (!(blockPos.distToCenterSqr(d, e, f) > 1024.0)) {
SortedSet<BlockDestructionProgress> sortedSet = (SortedSet<BlockDestructionProgress>)entry.getValue();
if (sortedSet != null && !sortedSet.isEmpty()) {
int i = ((BlockDestructionProgress)sortedSet.last()).getProgress();
poseStack.pushPose();
poseStack.translate(blockPos.getX() - d, blockPos.getY() - e, blockPos.getZ() - f);
PoseStack.Pose pose = poseStack.last();
VertexConsumer vertexConsumer = new SheetedDecalTextureGenerator(bufferSource.getBuffer((RenderType)ModelBakery.DESTROY_TYPES.get(i)), pose, 1.0F);
this.minecraft.getBlockRenderer().renderBreakingTexture(this.level.getBlockState(blockPos), blockPos, this.level, poseStack, vertexConsumer);
poseStack.popPose();
}
}
}
}
private void renderBlockOutline(Camera camera, BufferSource bufferSource, PoseStack poseStack, boolean sort) {
if (this.minecraft.hitResult instanceof BlockHitResult blockHitResult) {
if (blockHitResult.getType() != Type.MISS) {
BlockPos blockPos = blockHitResult.getBlockPos();
BlockState blockState = this.level.getBlockState(blockPos);
if (!blockState.isAir() && this.level.getWorldBorder().isWithinBounds(blockPos)) {
boolean bl = ItemBlockRenderTypes.getChunkRenderType(blockState).sortOnUpload();
if (bl != sort) {
return;
}
Vec3 vec3 = camera.getPosition();
Boolean boolean_ = this.minecraft.options.highContrastBlockOutline().get();
if (boolean_) {
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.secondaryBlockOutline());
this.renderHitOutline(poseStack, vertexConsumer, camera.getEntity(), vec3.x, vec3.y, vec3.z, blockPos, blockState, -16777216);
}
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.lines());
int i = boolean_ ? -11010079 : ARGB.color(102, -16777216);
this.renderHitOutline(poseStack, vertexConsumer, camera.getEntity(), vec3.x, vec3.y, vec3.z, blockPos, blockState, i);
bufferSource.endLastBatch();
}
}
}
}
/**
* Asserts that the specified {@code poseStack} is {@linkplain com.mojang.blaze3d.vertex.PoseStack#clear() clear}.
* @throws java.lang.IllegalStateException if the specified {@code poseStack} is not clear
*/
private void checkPoseStack(PoseStack poseStack) {
if (!poseStack.isEmpty()) {
throw new IllegalStateException("Pose stack not empty");
}
}
private void renderEntity(Entity entity, double camX, double camY, double camZ, float partialTick, PoseStack poseStack, MultiBufferSource bufferSource) {
double d = Mth.lerp((double)partialTick, entity.xOld, entity.getX());
double e = Mth.lerp((double)partialTick, entity.yOld, entity.getY());
double f = Mth.lerp((double)partialTick, entity.zOld, entity.getZ());
this.entityRenderDispatcher
.render(entity, d - camX, e - camY, f - camZ, partialTick, poseStack, bufferSource, this.entityRenderDispatcher.getPackedLightCoords(entity, partialTick));
}
private void scheduleTranslucentSectionResort(Vec3 cameraPosition) {
if (!this.visibleSections.isEmpty()) {
BlockPos blockPos = BlockPos.containing(cameraPosition);
boolean bl = !blockPos.equals(this.lastTranslucentSortBlockPos);
Profiler.get().push("translucent_sort");
SectionRenderDispatcher.TranslucencyPointOfView translucencyPointOfView = new SectionRenderDispatcher.TranslucencyPointOfView();
for (SectionRenderDispatcher.RenderSection renderSection : this.nearbyVisibleSections) {
this.scheduleResort(renderSection, translucencyPointOfView, cameraPosition, bl, true);
}
this.translucencyResortIterationIndex = this.translucencyResortIterationIndex % this.visibleSections.size();
int i = Math.max(this.visibleSections.size() / 8, 15);
while (i-- > 0) {
int j = this.translucencyResortIterationIndex++ % this.visibleSections.size();
this.scheduleResort(this.visibleSections.get(j), translucencyPointOfView, cameraPosition, bl, false);
}
this.lastTranslucentSortBlockPos = blockPos;
Profiler.get().pop();
}
}
/**
* @param force If {@code true}, will schedule a resort even if the point of view hasn't changed
*/
private void scheduleResort(
SectionRenderDispatcher.RenderSection section,
SectionRenderDispatcher.TranslucencyPointOfView pointOfView,
Vec3 cameraPosition,
boolean force,
boolean ignoreAxisAlignment
) {
pointOfView.set(cameraPosition, section.getSectionNode());
boolean bl = !pointOfView.equals(section.pointOfView.get());
boolean bl2 = force && (pointOfView.isAxisAligned() || ignoreAxisAlignment);
if ((bl2 || bl) && !section.transparencyResortingScheduled() && section.hasTranslucentGeometry()) {
section.resortTransparency(this.sectionRenderDispatcher);
}
}
private void renderSectionLayer(RenderType renderType, double x, double y, double z, Matrix4f frustrumMatrix, Matrix4f projectionMatrix) {
RenderSystem.assertOnRenderThread();
Zone zone = Profiler.get().zone((Supplier<String>)(() -> "render_" + renderType.name));
zone.addText(renderType::toString);
boolean bl = renderType != RenderType.translucent();
ObjectListIterator<SectionRenderDispatcher.RenderSection> objectListIterator = this.visibleSections.listIterator(bl ? 0 : this.visibleSections.size());
renderType.setupRenderState();
RenderPipeline renderPipeline = renderType.getRenderPipeline();
ArrayList<RenderPass.Draw> arrayList = new ArrayList();
RenderSystem.AutoStorageIndexBuffer autoStorageIndexBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
int i = 0;
while (bl ? objectListIterator.hasNext() : objectListIterator.hasPrevious()) {
SectionRenderDispatcher.RenderSection renderSection = bl ? (SectionRenderDispatcher.RenderSection)objectListIterator.next() : objectListIterator.previous();
SectionRenderDispatcher.SectionBuffers sectionBuffers = renderSection.getBuffers(renderType);
if (!renderSection.getCompiled().isEmpty(renderType) && sectionBuffers != null) {
GpuBuffer gpuBuffer;
VertexFormat.IndexType indexType;
if (sectionBuffers.getIndexBuffer() == null) {
if (sectionBuffers.getIndexCount() > i) {
i = sectionBuffers.getIndexCount();
}
gpuBuffer = null;
indexType = null;
} else {
gpuBuffer = sectionBuffers.getIndexBuffer();
indexType = sectionBuffers.getIndexType();
}
BlockPos blockPos = renderSection.getRenderOrigin();
arrayList.add(
new RenderPass.Draw(
0,
sectionBuffers.getVertexBuffer(),
gpuBuffer,
indexType,
0,
sectionBuffers.getIndexCount(),
uniformUploader -> uniformUploader.upload("ModelOffset", (float)(blockPos.getX() - x), (float)(blockPos.getY() - y), (float)(blockPos.getZ() - z))
)
);
}
}
GpuBuffer gpuBuffer2 = i == 0 ? null : autoStorageIndexBuffer.getBuffer(i);
VertexFormat.IndexType indexType2 = i == 0 ? null : autoStorageIndexBuffer.type();
try (RenderPass renderPass = RenderSystem.getDevice()
.createCommandEncoder()
.createRenderPass(
renderType.getRenderTarget().getColorTexture(), OptionalInt.empty(), renderType.getRenderTarget().getDepthTexture(), OptionalDouble.empty()
)) {
renderPass.setPipeline(renderPipeline);
for (int j = 0; j < 12; j++) {
GpuTexture gpuTexture = RenderSystem.getShaderTexture(j);
if (gpuTexture != null) {
renderPass.bindSampler("Sampler" + j, gpuTexture);
}
}
renderPass.drawMultipleIndexed(arrayList, gpuBuffer2, indexType2);
}
zone.close();
renderType.clearRenderState();
}
public void captureFrustum() {
this.captureFrustum = true;
}
public void killFrustum() {
this.capturedFrustum = null;
}
public void tick() {
if (this.level.tickRateManager().runsNormally()) {
this.ticks++;
}
if (this.ticks % 20 == 0) {
Iterator<BlockDestructionProgress> iterator = this.destroyingBlocks.values().iterator();
while (iterator.hasNext()) {
BlockDestructionProgress blockDestructionProgress = (BlockDestructionProgress)iterator.next();
int i = blockDestructionProgress.getUpdatedRenderTick();
if (this.ticks - i > 400) {
iterator.remove();
this.removeProgress(blockDestructionProgress);
}
}
}
}
private void removeProgress(BlockDestructionProgress progress) {
long l = progress.getPos().asLong();
Set<BlockDestructionProgress> set = (Set<BlockDestructionProgress>)this.destructionProgress.get(l);
set.remove(progress);
if (set.isEmpty()) {
this.destructionProgress.remove(l);
}
}
private void addSkyPass(FrameGraphBuilder frameGraphBuilder, Camera camera, float partialTick, FogParameters fog) {
FogType fogType = camera.getFluidInCamera();
if (fogType != FogType.POWDER_SNOW && fogType != FogType.LAVA && !this.doesMobEffectBlockSky(camera)) {
DimensionSpecialEffects dimensionSpecialEffects = this.level.effects();
SkyType skyType = dimensionSpecialEffects.skyType();
if (skyType != SkyType.NONE) {
FramePass framePass = frameGraphBuilder.addPass("sky");
this.targets.main = framePass.readsAndWrites(this.targets.main);
framePass.executes(() -> {
RenderSystem.setShaderFog(fog);
if (skyType == SkyType.END) {
this.skyRenderer.renderEndSky();
} else {
PoseStack poseStack = new PoseStack();
float g = this.level.getSunAngle(partialTick);
float h = this.level.getTimeOfDay(partialTick);
float i = 1.0F - this.level.getRainLevel(partialTick);
float j = this.level.getStarBrightness(partialTick) * i;
int k = dimensionSpecialEffects.getSunriseOrSunsetColor(h);
int l = this.level.getMoonPhase();
int m = this.level.getSkyColor(this.minecraft.gameRenderer.getMainCamera().getPosition(), partialTick);
float n = ARGB.redFloat(m);
float o = ARGB.greenFloat(m);
float p = ARGB.blueFloat(m);
this.skyRenderer.renderSkyDisc(n, o, p);
BufferSource bufferSource = this.renderBuffers.bufferSource();
if (dimensionSpecialEffects.isSunriseOrSunset(h)) {
this.skyRenderer.renderSunriseAndSunset(poseStack, bufferSource, g, k);
}
this.skyRenderer.renderSunMoonAndStars(poseStack, bufferSource, h, l, i, j, fog);
bufferSource.endBatch();
if (this.shouldRenderDarkDisc(partialTick)) {
this.skyRenderer.renderDarkDisc();
}
}
});
}
}
}
private boolean shouldRenderDarkDisc(float partialTick) {
return this.minecraft.player.getEyePosition(partialTick).y - this.level.getLevelData().getHorizonHeight(this.level) < 0.0;
}
private boolean doesMobEffectBlockSky(Camera camera) {
return !(camera.getEntity() instanceof LivingEntity livingEntity)
? false
: livingEntity.hasEffect(MobEffects.BLINDNESS) || livingEntity.hasEffect(MobEffects.DARKNESS);
}
private void compileSections(Camera camera) {
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("populate_sections_to_compile");
RenderRegionCache renderRegionCache = new RenderRegionCache();
BlockPos blockPos = camera.getBlockPosition();
List<SectionRenderDispatcher.RenderSection> list = Lists.<SectionRenderDispatcher.RenderSection>newArrayList();
for (SectionRenderDispatcher.RenderSection renderSection : this.visibleSections) {
if (renderSection.isDirty() && renderSection.hasAllNeighbors()) {
boolean bl = false;
if (this.minecraft.options.prioritizeChunkUpdates().get() == PrioritizeChunkUpdates.NEARBY) {
BlockPos blockPos2 = SectionPos.of(renderSection.getSectionNode()).center();
bl = blockPos2.distSqr(blockPos) < 768.0 || renderSection.isDirtyFromPlayer();
} else if (this.minecraft.options.prioritizeChunkUpdates().get() == PrioritizeChunkUpdates.PLAYER_AFFECTED) {
bl = renderSection.isDirtyFromPlayer();
}
if (bl) {
profilerFiller.push("build_near_sync");
this.sectionRenderDispatcher.rebuildSectionSync(renderSection, renderRegionCache);
renderSection.setNotDirty();
profilerFiller.pop();
} else {
list.add(renderSection);
}
}
}
profilerFiller.popPush("upload");
this.sectionRenderDispatcher.uploadAllPendingUploads();
profilerFiller.popPush("schedule_async_compile");
for (SectionRenderDispatcher.RenderSection renderSectionx : list) {
renderSectionx.rebuildSectionAsync(this.sectionRenderDispatcher, renderRegionCache);
renderSectionx.setNotDirty();
}
profilerFiller.pop();
this.scheduleTranslucentSectionResort(camera.getPosition());
}
private void renderHitOutline(
PoseStack poseStack, VertexConsumer buffer, Entity entity, double camX, double camY, double camZ, BlockPos pos, BlockState state, int color
) {
ShapeRenderer.renderShape(
poseStack, buffer, state.getShape(this.level, pos, CollisionContext.of(entity)), pos.getX() - camX, pos.getY() - camY, pos.getZ() - camZ, color
);
}
public void blockChanged(BlockGetter level, BlockPos pos, BlockState oldState, BlockState newState, int flags) {
this.setBlockDirty(pos, (flags & 8) != 0);
}
private void setBlockDirty(BlockPos pos, boolean reRenderOnMainThread) {
for (int i = pos.getZ() - 1; i <= pos.getZ() + 1; i++) {
for (int j = pos.getX() - 1; j <= pos.getX() + 1; j++) {
for (int k = pos.getY() - 1; k <= pos.getY() + 1; k++) {
this.setSectionDirty(SectionPos.blockToSectionCoord(j), SectionPos.blockToSectionCoord(k), SectionPos.blockToSectionCoord(i), reRenderOnMainThread);
}
}
}
}
/**
* Re-renders all blocks in the specified range.
*/
public void setBlocksDirty(int minX, int minY, int minZ, int maxX, int maxY, int maxZ) {
for (int i = minZ - 1; i <= maxZ + 1; i++) {
for (int j = minX - 1; j <= maxX + 1; j++) {
for (int k = minY - 1; k <= maxY + 1; k++) {
this.setSectionDirty(SectionPos.blockToSectionCoord(j), SectionPos.blockToSectionCoord(k), SectionPos.blockToSectionCoord(i));
}
}
}
}
public void setBlockDirty(BlockPos pos, BlockState oldState, BlockState newState) {
if (this.minecraft.getModelManager().requiresRender(oldState, newState)) {
this.setBlocksDirty(pos.getX(), pos.getY(), pos.getZ(), pos.getX(), pos.getY(), pos.getZ());
}
}
public void setSectionDirtyWithNeighbors(int sectionX, int sectionY, int sectionZ) {
this.setSectionRangeDirty(sectionX - 1, sectionY - 1, sectionZ - 1, sectionX + 1, sectionY + 1, sectionZ + 1);
}
public void setSectionRangeDirty(int minY, int minX, int minZ, int maxY, int maxX, int maxZ) {
for (int i = minZ; i <= maxZ; i++) {
for (int j = minY; j <= maxY; j++) {
for (int k = minX; k <= maxX; k++) {
this.setSectionDirty(j, k, i);
}
}
}
}
public void setSectionDirty(int sectionX, int sectionY, int sectionZ) {
this.setSectionDirty(sectionX, sectionY, sectionZ, false);
}
private void setSectionDirty(int sectionX, int sectionY, int sectionZ, boolean reRenderOnMainThread) {
this.viewArea.setDirty(sectionX, sectionY, sectionZ, reRenderOnMainThread);
}
public void onSectionBecomingNonEmpty(long sectionPos) {
SectionRenderDispatcher.RenderSection renderSection = this.viewArea.getRenderSection(sectionPos);
if (renderSection != null) {
this.sectionOcclusionGraph.schedulePropagationFrom(renderSection);
}
}
/**
* @param force if {@code true}, the particle will be created regardless of its distance from the camera and the {@linkplain #calculateParticleLevel(boolean) calculated particle level}
*/
public void addParticle(ParticleOptions options, boolean force, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
this.addParticle(options, force, false, x, y, z, xSpeed, ySpeed, zSpeed);
}
/**
* @param force if {@code true}, the particle will be created regardless of its distance from the camera and the {@linkplain #calculateParticleLevel(boolean) calculated particle level}
* @param decreased if {@code true}, and the {@linkplain net.minecraft.client.Options#particles particles option} is set to minimal, attempts to spawn the particle at a decreased level
*/
public void addParticle(ParticleOptions options, boolean force, boolean decreased, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
try {
this.addParticleInternal(options, force, decreased, x, y, z, xSpeed, ySpeed, zSpeed);
} catch (Throwable var19) {
CrashReport crashReport = CrashReport.forThrowable(var19, "Exception while adding particle");
CrashReportCategory crashReportCategory = crashReport.addCategory("Particle being added");
crashReportCategory.setDetail("ID", BuiltInRegistries.PARTICLE_TYPE.getKey(options.getType()));
crashReportCategory.setDetail(
"Parameters",
(CrashReportDetail<String>)(() -> ParticleTypes.CODEC
.encodeStart(this.level.registryAccess().createSerializationContext(NbtOps.INSTANCE), options)
.toString())
);
crashReportCategory.setDetail("Position", (CrashReportDetail<String>)(() -> CrashReportCategory.formatLocation(this.level, x, y, z)));
throw new ReportedException(crashReport);
}
}
public <T extends ParticleOptions> void addParticle(T options, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
this.addParticle(options, options.getType().getOverrideLimiter(), x, y, z, xSpeed, ySpeed, zSpeed);
}
/**
* @param force if {@code true}, the particle will be created regardless of its distance from the camera and the {@linkplain #calculateParticleLevel(boolean) calculated particle level}
*/
@Nullable
Particle addParticleInternal(ParticleOptions options, boolean force, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed) {
return this.addParticleInternal(options, force, false, x, y, z, xSpeed, ySpeed, zSpeed);
}
/**
* @param force if {@code true}, the particle will be created regardless of its distance from the camera and the {@linkplain #calculateParticleLevel(boolean) calculated particle level}
* @param decreased if {@code true}, and the {@linkplain net.minecraft.client.Options#particles particles option} is set to minimal, attempts to spawn the particle at a decreased level
*/
@Nullable
private Particle addParticleInternal(
ParticleOptions options, boolean force, boolean decreased, double x, double y, double z, double xSpeed, double ySpeed, double zSpeed
) {
Camera camera = this.minecraft.gameRenderer.getMainCamera();
ParticleStatus particleStatus = this.calculateParticleLevel(decreased);
if (force) {
return this.minecraft.particleEngine.createParticle(options, x, y, z, xSpeed, ySpeed, zSpeed);
} else if (camera.getPosition().distanceToSqr(x, y, z) > 1024.0) {
return null;
} else {
return particleStatus == ParticleStatus.MINIMAL ? null : this.minecraft.particleEngine.createParticle(options, x, y, z, xSpeed, ySpeed, zSpeed);
}
}
private ParticleStatus calculateParticleLevel(boolean decreased) {
ParticleStatus particleStatus = this.minecraft.options.particles().get();
if (decreased && particleStatus == ParticleStatus.MINIMAL && this.level.random.nextInt(10) == 0) {
particleStatus = ParticleStatus.DECREASED;
}
if (particleStatus == ParticleStatus.DECREASED && this.level.random.nextInt(3) == 0) {
particleStatus = ParticleStatus.MINIMAL;
}
return particleStatus;
}
public void destroyBlockProgress(int breakerId, BlockPos pos, int progress) {
if (progress >= 0 && progress < 10) {
BlockDestructionProgress blockDestructionProgress = this.destroyingBlocks.get(breakerId);
if (blockDestructionProgress != null) {
this.removeProgress(blockDestructionProgress);
}
if (blockDestructionProgress == null
|| blockDestructionProgress.getPos().getX() != pos.getX()
|| blockDestructionProgress.getPos().getY() != pos.getY()
|| blockDestructionProgress.getPos().getZ() != pos.getZ()) {
blockDestructionProgress = new BlockDestructionProgress(breakerId, pos);
this.destroyingBlocks.put(breakerId, blockDestructionProgress);
}
blockDestructionProgress.setProgress(progress);
blockDestructionProgress.updateTick(this.ticks);
this.destructionProgress
.computeIfAbsent(
blockDestructionProgress.getPos().asLong(),
(Long2ObjectFunction<? extends SortedSet<BlockDestructionProgress>>)(l -> Sets.<BlockDestructionProgress>newTreeSet())
)
.add(blockDestructionProgress);
} else {
BlockDestructionProgress blockDestructionProgressx = this.destroyingBlocks.remove(breakerId);
if (blockDestructionProgressx != null) {
this.removeProgress(blockDestructionProgressx);
}
}
}
public boolean hasRenderedAllSections() {
return this.sectionRenderDispatcher.isQueueEmpty();
}
public void onChunkReadyToRender(ChunkPos chunkPos) {
this.sectionOcclusionGraph.onChunkReadyToRender(chunkPos);
}
public void needsUpdate() {
this.sectionOcclusionGraph.invalidate();
this.cloudRenderer.markForRebuild();
}
public void updateGlobalBlockEntities(Collection<BlockEntity> blockEntitiesToRemove, Collection<BlockEntity> blockEntitiesToAdd) {
synchronized (this.globalBlockEntities) {
this.globalBlockEntities.removeAll(blockEntitiesToRemove);
this.globalBlockEntities.addAll(blockEntitiesToAdd);
}
}
public static int getLightColor(BlockAndTintGetter level, BlockPos pos) {
return getLightColor(LevelRenderer.BrightnessGetter.DEFAULT, level, level.getBlockState(pos), pos);
}
public static int getLightColor(LevelRenderer.BrightnessGetter brightnessGetter, BlockAndTintGetter level, BlockState state, BlockPos pos) {
if (state.emissiveRendering(level, pos)) {
return 15728880;
} else {
int i = brightnessGetter.packedBrightness(level, pos);
int j = LightTexture.block(i);
int k = state.getLightEmission();
if (j < k) {
int l = LightTexture.sky(i);
return LightTexture.pack(k, l);
} else {
return i;
}
}
}
public boolean isSectionCompiled(BlockPos pos) {
SectionRenderDispatcher.RenderSection renderSection = this.viewArea.getRenderSectionAt(pos);
return renderSection != null && renderSection.compiled.get() != SectionRenderDispatcher.CompiledSection.UNCOMPILED;
}
@Nullable
public RenderTarget entityOutlineTarget() {
return this.targets.entityOutline != null ? this.targets.entityOutline.get() : null;
}
@Nullable
public RenderTarget getTranslucentTarget() {
return this.targets.translucent != null ? this.targets.translucent.get() : null;
}
@Nullable
public RenderTarget getItemEntityTarget() {
return this.targets.itemEntity != null ? this.targets.itemEntity.get() : null;
}
@Nullable
public RenderTarget getParticlesTarget() {
return this.targets.particles != null ? this.targets.particles.get() : null;
}
@Nullable
public RenderTarget getWeatherTarget() {
return this.targets.weather != null ? this.targets.weather.get() : null;
}
@Nullable
public RenderTarget getCloudsTarget() {
return this.targets.clouds != null ? this.targets.clouds.get() : null;
}
@VisibleForDebug
public ObjectArrayList<SectionRenderDispatcher.RenderSection> getVisibleSections() {
return this.visibleSections;
}
@VisibleForDebug
public SectionOcclusionGraph getSectionOcclusionGraph() {
return this.sectionOcclusionGraph;
}
@Nullable
public Frustum getCapturedFrustum() {
return this.capturedFrustum;
}
public CloudRenderer getCloudRenderer() {
return this.cloudRenderer;
}
@FunctionalInterface
@Environment(EnvType.CLIENT)
public interface BrightnessGetter {
LevelRenderer.BrightnessGetter DEFAULT = (blockAndTintGetter, blockPos) -> {
int i = blockAndTintGetter.getBrightness(LightLayer.SKY, blockPos);
int j = blockAndTintGetter.getBrightness(LightLayer.BLOCK, blockPos);
return Brightness.pack(j, i);
};
int packedBrightness(BlockAndTintGetter blockAndTintGetter, BlockPos blockPos);
}
}