312 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			312 lines
		
	
	
	
		
			13 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.client.renderer.debug;
 | |
| 
 | |
| import com.mojang.blaze3d.vertex.PoseStack;
 | |
| import com.mojang.blaze3d.vertex.VertexConsumer;
 | |
| import java.util.List;
 | |
| import java.util.Optional;
 | |
| import net.fabricmc.api.EnvType;
 | |
| import net.fabricmc.api.Environment;
 | |
| import net.minecraft.client.Camera;
 | |
| import net.minecraft.client.Minecraft;
 | |
| import net.minecraft.client.gui.Font;
 | |
| import net.minecraft.client.renderer.MultiBufferSource;
 | |
| import net.minecraft.client.renderer.RenderType;
 | |
| import net.minecraft.client.renderer.ShapeRenderer;
 | |
| import net.minecraft.client.renderer.culling.Frustum;
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.util.ARGB;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.world.entity.Entity;
 | |
| import net.minecraft.world.entity.EntitySelector;
 | |
| import net.minecraft.world.entity.projectile.ProjectileUtil;
 | |
| import net.minecraft.world.level.LightLayer;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import net.minecraft.world.phys.EntityHitResult;
 | |
| import net.minecraft.world.phys.Vec3;
 | |
| import net.minecraft.world.phys.shapes.Shapes;
 | |
| import net.minecraft.world.phys.shapes.VoxelShape;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| 
 | |
| @Environment(EnvType.CLIENT)
 | |
| public class DebugRenderer {
 | |
| 	public final PathfindingRenderer pathfindingRenderer = new PathfindingRenderer();
 | |
| 	public final DebugRenderer.SimpleDebugRenderer waterDebugRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer chunkBorderRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer heightMapRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer collisionBoxRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer supportBlockRenderer;
 | |
| 	public final NeighborsUpdateRenderer neighborsUpdateRenderer;
 | |
| 	public final RedstoneWireOrientationsRenderer redstoneWireOrientationsRenderer;
 | |
| 	public final StructureRenderer structureRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer lightDebugRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer worldGenAttemptRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer solidFaceRenderer;
 | |
| 	public final DebugRenderer.SimpleDebugRenderer chunkRenderer;
 | |
| 	public final BrainDebugRenderer brainDebugRenderer;
 | |
| 	public final VillageSectionsDebugRenderer villageSectionsDebugRenderer;
 | |
| 	public final BeeDebugRenderer beeDebugRenderer;
 | |
| 	public final RaidDebugRenderer raidDebugRenderer;
 | |
| 	public final GoalSelectorDebugRenderer goalSelectorRenderer;
 | |
| 	public final GameTestDebugRenderer gameTestDebugRenderer;
 | |
| 	public final GameEventListenerRenderer gameEventListenerRenderer;
 | |
| 	public final LightSectionDebugRenderer skyLightSectionDebugRenderer;
 | |
| 	public final BreezeDebugRenderer breezeDebugRenderer;
 | |
| 	public final ChunkCullingDebugRenderer chunkCullingDebugRenderer;
 | |
| 	public final OctreeDebugRenderer octreeDebugRenderer;
 | |
| 	private boolean renderChunkborder;
 | |
| 	private boolean renderOctree;
 | |
| 
 | |
| 	public DebugRenderer(Minecraft minecraft) {
 | |
| 		this.waterDebugRenderer = new WaterDebugRenderer(minecraft);
 | |
| 		this.chunkBorderRenderer = new ChunkBorderRenderer(minecraft);
 | |
| 		this.heightMapRenderer = new HeightMapRenderer(minecraft);
 | |
| 		this.collisionBoxRenderer = new CollisionBoxRenderer(minecraft);
 | |
| 		this.supportBlockRenderer = new SupportBlockRenderer(minecraft);
 | |
| 		this.neighborsUpdateRenderer = new NeighborsUpdateRenderer(minecraft);
 | |
| 		this.redstoneWireOrientationsRenderer = new RedstoneWireOrientationsRenderer(minecraft);
 | |
| 		this.structureRenderer = new StructureRenderer(minecraft);
 | |
| 		this.lightDebugRenderer = new LightDebugRenderer(minecraft);
 | |
| 		this.worldGenAttemptRenderer = new WorldGenAttemptRenderer();
 | |
| 		this.solidFaceRenderer = new SolidFaceRenderer(minecraft);
 | |
| 		this.chunkRenderer = new ChunkDebugRenderer(minecraft);
 | |
| 		this.brainDebugRenderer = new BrainDebugRenderer(minecraft);
 | |
| 		this.villageSectionsDebugRenderer = new VillageSectionsDebugRenderer();
 | |
| 		this.beeDebugRenderer = new BeeDebugRenderer(minecraft);
 | |
| 		this.raidDebugRenderer = new RaidDebugRenderer(minecraft);
 | |
| 		this.goalSelectorRenderer = new GoalSelectorDebugRenderer(minecraft);
 | |
| 		this.gameTestDebugRenderer = new GameTestDebugRenderer();
 | |
| 		this.gameEventListenerRenderer = new GameEventListenerRenderer(minecraft);
 | |
| 		this.skyLightSectionDebugRenderer = new LightSectionDebugRenderer(minecraft, LightLayer.SKY);
 | |
| 		this.breezeDebugRenderer = new BreezeDebugRenderer(minecraft);
 | |
| 		this.chunkCullingDebugRenderer = new ChunkCullingDebugRenderer(minecraft);
 | |
| 		this.octreeDebugRenderer = new OctreeDebugRenderer(minecraft);
 | |
| 	}
 | |
| 
 | |
| 	public void clear() {
 | |
| 		this.pathfindingRenderer.clear();
 | |
| 		this.waterDebugRenderer.clear();
 | |
| 		this.chunkBorderRenderer.clear();
 | |
| 		this.heightMapRenderer.clear();
 | |
| 		this.collisionBoxRenderer.clear();
 | |
| 		this.supportBlockRenderer.clear();
 | |
| 		this.neighborsUpdateRenderer.clear();
 | |
| 		this.structureRenderer.clear();
 | |
| 		this.lightDebugRenderer.clear();
 | |
| 		this.worldGenAttemptRenderer.clear();
 | |
| 		this.solidFaceRenderer.clear();
 | |
| 		this.chunkRenderer.clear();
 | |
| 		this.brainDebugRenderer.clear();
 | |
| 		this.villageSectionsDebugRenderer.clear();
 | |
| 		this.beeDebugRenderer.clear();
 | |
| 		this.raidDebugRenderer.clear();
 | |
| 		this.goalSelectorRenderer.clear();
 | |
| 		this.gameTestDebugRenderer.clear();
 | |
| 		this.gameEventListenerRenderer.clear();
 | |
| 		this.skyLightSectionDebugRenderer.clear();
 | |
| 		this.breezeDebugRenderer.clear();
 | |
| 		this.chunkCullingDebugRenderer.clear();
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Toggles the {@link #renderChunkborder} value, effectively toggling the {@link #chunkBorderRenderer} on or off.
 | |
| 	 * 
 | |
| 	 * @return the new, inverted value
 | |
| 	 */
 | |
| 	public boolean switchRenderChunkborder() {
 | |
| 		this.renderChunkborder = !this.renderChunkborder;
 | |
| 		return this.renderChunkborder;
 | |
| 	}
 | |
| 
 | |
| 	public boolean toggleRenderOctree() {
 | |
| 		return this.renderOctree = !this.renderOctree;
 | |
| 	}
 | |
| 
 | |
| 	public void render(PoseStack poseStack, Frustum frustum, MultiBufferSource.BufferSource bufferSource, double camX, double camY, double camZ) {
 | |
| 		if (this.renderChunkborder && !Minecraft.getInstance().showOnlyReducedInfo()) {
 | |
| 			this.chunkBorderRenderer.render(poseStack, bufferSource, camX, camY, camZ);
 | |
| 		}
 | |
| 
 | |
| 		if (this.renderOctree) {
 | |
| 			this.octreeDebugRenderer.render(poseStack, frustum, bufferSource, camX, camY, camZ);
 | |
| 		}
 | |
| 
 | |
| 		this.gameTestDebugRenderer.render(poseStack, bufferSource, camX, camY, camZ);
 | |
| 	}
 | |
| 
 | |
| 	public void renderAfterTranslucents(PoseStack poseStack, MultiBufferSource.BufferSource bufferSource, double camX, double camY, double camZ) {
 | |
| 		this.chunkCullingDebugRenderer.render(poseStack, bufferSource, camX, camY, camZ);
 | |
| 	}
 | |
| 
 | |
| 	public static Optional<Entity> getTargetedEntity(@Nullable Entity entity, int distance) {
 | |
| 		if (entity == null) {
 | |
| 			return Optional.empty();
 | |
| 		} else {
 | |
| 			Vec3 vec3 = entity.getEyePosition();
 | |
| 			Vec3 vec32 = entity.getViewVector(1.0F).scale(distance);
 | |
| 			Vec3 vec33 = vec3.add(vec32);
 | |
| 			AABB aABB = entity.getBoundingBox().expandTowards(vec32).inflate(1.0);
 | |
| 			int i = distance * distance;
 | |
| 			EntityHitResult entityHitResult = ProjectileUtil.getEntityHitResult(entity, vec3, vec33, aABB, EntitySelector.CAN_BE_PICKED, i);
 | |
| 			if (entityHitResult == null) {
 | |
| 				return Optional.empty();
 | |
| 			} else {
 | |
| 				return vec3.distanceToSqr(entityHitResult.getLocation()) > i ? Optional.empty() : Optional.of(entityHitResult.getEntity());
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFilledUnitCube(PoseStack poseStack, MultiBufferSource bufferSource, BlockPos pos, float red, float green, float blue, float alpha) {
 | |
| 		renderFilledBox(poseStack, bufferSource, pos, pos.offset(1, 1, 1), red, green, blue, alpha);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFilledBox(
 | |
| 		PoseStack poseStack, MultiBufferSource bufferSource, BlockPos startPos, BlockPos endPos, float red, float green, float blue, float alpha
 | |
| 	) {
 | |
| 		Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
 | |
| 		if (camera.isInitialized()) {
 | |
| 			Vec3 vec3 = camera.getPosition().reverse();
 | |
| 			AABB aABB = AABB.encapsulatingFullBlocks(startPos, endPos).move(vec3);
 | |
| 			renderFilledBox(poseStack, bufferSource, aABB, red, green, blue, alpha);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFilledBox(
 | |
| 		PoseStack poseStack, MultiBufferSource bufferSource, BlockPos pos, float scale, float red, float green, float blue, float alpha
 | |
| 	) {
 | |
| 		Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
 | |
| 		if (camera.isInitialized()) {
 | |
| 			Vec3 vec3 = camera.getPosition().reverse();
 | |
| 			AABB aABB = new AABB(pos).move(vec3).inflate(scale);
 | |
| 			renderFilledBox(poseStack, bufferSource, aABB, red, green, blue, alpha);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFilledBox(PoseStack poseStack, MultiBufferSource bufferSource, AABB boundingBox, float red, float green, float blue, float alpha) {
 | |
| 		renderFilledBox(
 | |
| 			poseStack, bufferSource, boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ, red, green, blue, alpha
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFilledBox(
 | |
| 		PoseStack poseStack,
 | |
| 		MultiBufferSource bufferSource,
 | |
| 		double minX,
 | |
| 		double minY,
 | |
| 		double minZ,
 | |
| 		double maxX,
 | |
| 		double maxY,
 | |
| 		double maxZ,
 | |
| 		float red,
 | |
| 		float green,
 | |
| 		float blue,
 | |
| 		float alpha
 | |
| 	) {
 | |
| 		VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.debugFilledBox());
 | |
| 		ShapeRenderer.addChainedFilledBoxVertices(poseStack, vertexConsumer, minX, minY, minZ, maxX, maxY, maxZ, red, green, blue, alpha);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFloatingText(PoseStack poseStack, MultiBufferSource bufferSource, String text, int x, int y, int z, int color) {
 | |
| 		renderFloatingText(poseStack, bufferSource, text, x + 0.5, y + 0.5, z + 0.5, color);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFloatingText(PoseStack poseStack, MultiBufferSource bufferSource, String text, double x, double y, double z, int color) {
 | |
| 		renderFloatingText(poseStack, bufferSource, text, x, y, z, color, 0.02F);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFloatingText(PoseStack poseStack, MultiBufferSource bufferSource, String text, double x, double y, double z, int color, float scale) {
 | |
| 		renderFloatingText(poseStack, bufferSource, text, x, y, z, color, scale, true, 0.0F, false);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderFloatingText(
 | |
| 		PoseStack poseStack,
 | |
| 		MultiBufferSource bufferSource,
 | |
| 		String text,
 | |
| 		double x,
 | |
| 		double y,
 | |
| 		double z,
 | |
| 		int color,
 | |
| 		float scale,
 | |
| 		boolean center,
 | |
| 		float xOffset,
 | |
| 		boolean transparent
 | |
| 	) {
 | |
| 		Minecraft minecraft = Minecraft.getInstance();
 | |
| 		Camera camera = minecraft.gameRenderer.getMainCamera();
 | |
| 		if (camera.isInitialized() && minecraft.getEntityRenderDispatcher().options != null) {
 | |
| 			Font font = minecraft.font;
 | |
| 			double d = camera.getPosition().x;
 | |
| 			double e = camera.getPosition().y;
 | |
| 			double f = camera.getPosition().z;
 | |
| 			poseStack.pushPose();
 | |
| 			poseStack.translate((float)(x - d), (float)(y - e) + 0.07F, (float)(z - f));
 | |
| 			poseStack.mulPose(camera.rotation());
 | |
| 			poseStack.scale(scale, -scale, scale);
 | |
| 			float g = center ? -font.width(text) / 2.0F : 0.0F;
 | |
| 			g -= xOffset / scale;
 | |
| 			font.drawInBatch(
 | |
| 				text, g, 0.0F, color, false, poseStack.last().pose(), bufferSource, transparent ? Font.DisplayMode.SEE_THROUGH : Font.DisplayMode.NORMAL, 0, 15728880
 | |
| 			);
 | |
| 			poseStack.popPose();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private static Vec3 mixColor(float shift) {
 | |
| 		float f = 5.99999F;
 | |
| 		int i = (int)(Mth.clamp(shift, 0.0F, 1.0F) * 5.99999F);
 | |
| 		float g = shift * 5.99999F - i;
 | |
| 
 | |
| 		return switch (i) {
 | |
| 			case 0 -> new Vec3(1.0, g, 0.0);
 | |
| 			case 1 -> new Vec3(1.0F - g, 1.0, 0.0);
 | |
| 			case 2 -> new Vec3(0.0, 1.0, g);
 | |
| 			case 3 -> new Vec3(0.0, 1.0 - g, 1.0);
 | |
| 			case 4 -> new Vec3(g, 0.0, 1.0);
 | |
| 			case 5 -> new Vec3(1.0, 0.0, 1.0 - g);
 | |
| 			default -> throw new IllegalStateException("Unexpected value: " + i);
 | |
| 		};
 | |
| 	}
 | |
| 
 | |
| 	private static Vec3 shiftHue(float red, float green, float blue, float shift) {
 | |
| 		Vec3 vec3 = mixColor(shift).scale(red);
 | |
| 		Vec3 vec32 = mixColor((shift + 0.33333334F) % 1.0F).scale(green);
 | |
| 		Vec3 vec33 = mixColor((shift + 0.6666667F) % 1.0F).scale(blue);
 | |
| 		Vec3 vec34 = vec3.add(vec32).add(vec33);
 | |
| 		double d = Math.max(Math.max(1.0, vec34.x), Math.max(vec34.y, vec34.z));
 | |
| 		return new Vec3(vec34.x / d, vec34.y / d, vec34.z / d);
 | |
| 	}
 | |
| 
 | |
| 	public static void renderVoxelShape(
 | |
| 		PoseStack poseStack,
 | |
| 		VertexConsumer buffer,
 | |
| 		VoxelShape shape,
 | |
| 		double x,
 | |
| 		double y,
 | |
| 		double z,
 | |
| 		float red,
 | |
| 		float green,
 | |
| 		float blue,
 | |
| 		float alpha,
 | |
| 		boolean lowerColorVariance
 | |
| 	) {
 | |
| 		List<AABB> list = shape.toAabbs();
 | |
| 		if (!list.isEmpty()) {
 | |
| 			int i = lowerColorVariance ? list.size() : list.size() * 8;
 | |
| 			ShapeRenderer.renderShape(poseStack, buffer, Shapes.create((AABB)list.get(0)), x, y, z, ARGB.colorFromFloat(alpha, red, green, blue));
 | |
| 
 | |
| 			for (int j = 1; j < list.size(); j++) {
 | |
| 				AABB aABB = (AABB)list.get(j);
 | |
| 				float f = (float)j / i;
 | |
| 				Vec3 vec3 = shiftHue(red, green, blue, f);
 | |
| 				ShapeRenderer.renderShape(poseStack, buffer, Shapes.create(aABB), x, y, z, ARGB.colorFromFloat(alpha, (float)vec3.x, (float)vec3.y, (float)vec3.z));
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Environment(EnvType.CLIENT)
 | |
| 	public interface SimpleDebugRenderer {
 | |
| 		void render(PoseStack poseStack, MultiBufferSource bufferSource, double camX, double camY, double camZ);
 | |
| 
 | |
| 		default void clear() {
 | |
| 		}
 | |
| 	}
 | |
| }
 |