319 lines
16 KiB
Java
319 lines
16 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* org.jspecify.annotations.Nullable
|
|
*/
|
|
package net.minecraft.client.renderer.entity;
|
|
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import java.util.ArrayList;
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.client.gui.Font;
|
|
import net.minecraft.client.renderer.LightTexture;
|
|
import net.minecraft.client.renderer.SubmitNodeCollector;
|
|
import net.minecraft.client.renderer.culling.Frustum;
|
|
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
|
|
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
|
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
|
import net.minecraft.client.renderer.state.CameraRenderState;
|
|
import net.minecraft.client.server.IntegratedServer;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Vec3i;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.util.ARGB;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityAttachment;
|
|
import net.minecraft.world.entity.Leashable;
|
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
|
import net.minecraft.world.entity.vehicle.NewMinecartBehavior;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.LightLayer;
|
|
import net.minecraft.world.level.block.RenderShape;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
public abstract class EntityRenderer<T extends Entity, S extends EntityRenderState> {
|
|
private static final float SHADOW_POWER_FALLOFF_Y = 0.5f;
|
|
private static final float MAX_SHADOW_RADIUS = 32.0f;
|
|
public static final float NAMETAG_SCALE = 0.025f;
|
|
protected final EntityRenderDispatcher entityRenderDispatcher;
|
|
private final Font font;
|
|
protected float shadowRadius;
|
|
protected float shadowStrength = 1.0f;
|
|
|
|
protected EntityRenderer(EntityRendererProvider.Context context) {
|
|
this.entityRenderDispatcher = context.getEntityRenderDispatcher();
|
|
this.font = context.getFont();
|
|
}
|
|
|
|
public final int getPackedLightCoords(T entity, float partialTickTime) {
|
|
BlockPos blockPos = BlockPos.containing(((Entity)entity).getLightProbePosition(partialTickTime));
|
|
return LightTexture.pack(this.getBlockLightLevel(entity, blockPos), this.getSkyLightLevel(entity, blockPos));
|
|
}
|
|
|
|
protected int getSkyLightLevel(T entity, BlockPos blockPos) {
|
|
return ((Entity)entity).level().getBrightness(LightLayer.SKY, blockPos);
|
|
}
|
|
|
|
protected int getBlockLightLevel(T entity, BlockPos blockPos) {
|
|
if (((Entity)entity).isOnFire()) {
|
|
return 15;
|
|
}
|
|
return ((Entity)entity).level().getBrightness(LightLayer.BLOCK, blockPos);
|
|
}
|
|
|
|
public boolean shouldRender(T entity, Frustum culler, double camX, double camY, double camZ) {
|
|
Leashable leashable;
|
|
Entity leashHolder;
|
|
if (!((Entity)entity).shouldRender(camX, camY, camZ)) {
|
|
return false;
|
|
}
|
|
if (!this.affectedByCulling(entity)) {
|
|
return true;
|
|
}
|
|
AABB boundingBox = this.getBoundingBoxForCulling(entity).inflate(0.5);
|
|
if (boundingBox.hasNaN() || boundingBox.getSize() == 0.0) {
|
|
boundingBox = new AABB(((Entity)entity).getX() - 2.0, ((Entity)entity).getY() - 2.0, ((Entity)entity).getZ() - 2.0, ((Entity)entity).getX() + 2.0, ((Entity)entity).getY() + 2.0, ((Entity)entity).getZ() + 2.0);
|
|
}
|
|
if (culler.isVisible(boundingBox)) {
|
|
return true;
|
|
}
|
|
if (entity instanceof Leashable && (leashHolder = (leashable = (Leashable)entity).getLeashHolder()) != null) {
|
|
AABB leasherBox = this.entityRenderDispatcher.getRenderer(leashHolder).getBoundingBoxForCulling(leashHolder);
|
|
return culler.isVisible(leasherBox) || culler.isVisible(boundingBox.minmax(leasherBox));
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected AABB getBoundingBoxForCulling(T entity) {
|
|
return ((Entity)entity).getBoundingBox();
|
|
}
|
|
|
|
protected boolean affectedByCulling(T entity) {
|
|
return true;
|
|
}
|
|
|
|
public Vec3 getRenderOffset(S state) {
|
|
if (((EntityRenderState)state).passengerOffset != null) {
|
|
return ((EntityRenderState)state).passengerOffset;
|
|
}
|
|
return Vec3.ZERO;
|
|
}
|
|
|
|
public void submit(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) {
|
|
if (((EntityRenderState)state).leashStates != null) {
|
|
for (EntityRenderState.LeashState leashState : ((EntityRenderState)state).leashStates) {
|
|
submitNodeCollector.submitLeash(poseStack, leashState);
|
|
}
|
|
}
|
|
this.submitNameTag(state, poseStack, submitNodeCollector, camera);
|
|
}
|
|
|
|
protected boolean shouldShowName(T entity, double distanceToCameraSq) {
|
|
return ((Entity)entity).shouldShowName() || ((Entity)entity).hasCustomName() && entity == this.entityRenderDispatcher.crosshairPickEntity;
|
|
}
|
|
|
|
public Font getFont() {
|
|
return this.font;
|
|
}
|
|
|
|
protected void submitNameTag(S state, PoseStack poseStack, SubmitNodeCollector submitNodeCollector, CameraRenderState camera) {
|
|
if (((EntityRenderState)state).nameTag != null) {
|
|
submitNodeCollector.submitNameTag(poseStack, ((EntityRenderState)state).nameTagAttachment, 0, ((EntityRenderState)state).nameTag, !((EntityRenderState)state).isDiscrete, ((EntityRenderState)state).lightCoords, ((EntityRenderState)state).distanceToCameraSq, camera);
|
|
}
|
|
}
|
|
|
|
protected @Nullable Component getNameTag(T entity) {
|
|
return ((Entity)entity).getDisplayName();
|
|
}
|
|
|
|
protected float getShadowRadius(S state) {
|
|
return this.shadowRadius;
|
|
}
|
|
|
|
protected float getShadowStrength(S state) {
|
|
return this.shadowStrength;
|
|
}
|
|
|
|
public abstract S createRenderState();
|
|
|
|
public final S createRenderState(T entity, float partialTicks) {
|
|
S state = this.createRenderState();
|
|
this.extractRenderState(entity, state, partialTicks);
|
|
this.finalizeRenderState(entity, state);
|
|
return state;
|
|
}
|
|
|
|
public void extractRenderState(T entity, S state, float partialTicks) {
|
|
Leashable leashable;
|
|
Entity entity2;
|
|
NewMinecartBehavior behavior;
|
|
AbstractMinecart minecart;
|
|
Object object;
|
|
((EntityRenderState)state).entityType = ((Entity)entity).getType();
|
|
((EntityRenderState)state).x = Mth.lerp((double)partialTicks, ((Entity)entity).xOld, ((Entity)entity).getX());
|
|
((EntityRenderState)state).y = Mth.lerp((double)partialTicks, ((Entity)entity).yOld, ((Entity)entity).getY());
|
|
((EntityRenderState)state).z = Mth.lerp((double)partialTicks, ((Entity)entity).zOld, ((Entity)entity).getZ());
|
|
((EntityRenderState)state).isInvisible = ((Entity)entity).isInvisible();
|
|
((EntityRenderState)state).ageInTicks = (float)((Entity)entity).tickCount + partialTicks;
|
|
((EntityRenderState)state).boundingBoxWidth = ((Entity)entity).getBbWidth();
|
|
((EntityRenderState)state).boundingBoxHeight = ((Entity)entity).getBbHeight();
|
|
((EntityRenderState)state).eyeHeight = ((Entity)entity).getEyeHeight();
|
|
if (((Entity)entity).isPassenger() && (object = ((Entity)entity).getVehicle()) instanceof AbstractMinecart && (object = (minecart = (AbstractMinecart)object).getBehavior()) instanceof NewMinecartBehavior && (behavior = (NewMinecartBehavior)object).cartHasPosRotLerp()) {
|
|
double cartLerpX = Mth.lerp((double)partialTicks, minecart.xOld, minecart.getX());
|
|
double cartLerpY = Mth.lerp((double)partialTicks, minecart.yOld, minecart.getY());
|
|
double cartLerpZ = Mth.lerp((double)partialTicks, minecart.zOld, minecart.getZ());
|
|
((EntityRenderState)state).passengerOffset = behavior.getCartLerpPosition(partialTicks).subtract(new Vec3(cartLerpX, cartLerpY, cartLerpZ));
|
|
} else {
|
|
((EntityRenderState)state).passengerOffset = null;
|
|
}
|
|
if (this.entityRenderDispatcher.camera != null) {
|
|
boolean shouldShowName;
|
|
((EntityRenderState)state).distanceToCameraSq = this.entityRenderDispatcher.distanceToSqr((Entity)entity);
|
|
boolean bl = shouldShowName = ((EntityRenderState)state).distanceToCameraSq < 4096.0 && this.shouldShowName(entity, ((EntityRenderState)state).distanceToCameraSq);
|
|
if (shouldShowName) {
|
|
((EntityRenderState)state).nameTag = this.getNameTag(entity);
|
|
((EntityRenderState)state).nameTagAttachment = ((Entity)entity).getAttachments().getNullable(EntityAttachment.NAME_TAG, 0, ((Entity)entity).getYRot(partialTicks));
|
|
} else {
|
|
((EntityRenderState)state).nameTag = null;
|
|
}
|
|
}
|
|
((EntityRenderState)state).isDiscrete = ((Entity)entity).isDiscrete();
|
|
Level level = ((Entity)entity).level();
|
|
if (entity instanceof Leashable && (entity2 = (leashable = (Leashable)entity).getLeashHolder()) instanceof Entity) {
|
|
int leashCount;
|
|
Entity roper = entity2;
|
|
float entityYRot = ((Entity)entity).getPreciseBodyRotation(partialTicks) * ((float)Math.PI / 180);
|
|
Vec3 attachOffset = leashable.getLeashOffset(partialTicks);
|
|
BlockPos entityEyePos = BlockPos.containing(((Entity)entity).getEyePosition(partialTicks));
|
|
BlockPos roperEyePos = BlockPos.containing(roper.getEyePosition(partialTicks));
|
|
int startBlockLight = this.getBlockLightLevel(entity, entityEyePos);
|
|
int endBlockLight = this.entityRenderDispatcher.getRenderer(roper).getBlockLightLevel(roper, roperEyePos);
|
|
int startSkyLight = level.getBrightness(LightLayer.SKY, entityEyePos);
|
|
int endSkyLight = level.getBrightness(LightLayer.SKY, roperEyePos);
|
|
boolean quadConnection = roper.supportQuadLeashAsHolder() && leashable.supportQuadLeash();
|
|
int n = leashCount = quadConnection ? 4 : 1;
|
|
if (((EntityRenderState)state).leashStates == null || ((EntityRenderState)state).leashStates.size() != leashCount) {
|
|
((EntityRenderState)state).leashStates = new ArrayList<EntityRenderState.LeashState>(leashCount);
|
|
for (int i = 0; i < leashCount; ++i) {
|
|
((EntityRenderState)state).leashStates.add(new EntityRenderState.LeashState());
|
|
}
|
|
}
|
|
if (quadConnection) {
|
|
float roperYRot = roper.getPreciseBodyRotation(partialTicks) * ((float)Math.PI / 180);
|
|
Vec3 holderPos = roper.getPosition(partialTicks);
|
|
Vec3[] leashableAttachmentPoints = leashable.getQuadLeashOffsets();
|
|
Vec3[] roperAttachmentPoints = roper.getQuadLeashHolderOffsets();
|
|
for (int i = 0; i < leashCount; ++i) {
|
|
EntityRenderState.LeashState leashState = ((EntityRenderState)state).leashStates.get(i);
|
|
leashState.offset = leashableAttachmentPoints[i].yRot(-entityYRot);
|
|
leashState.start = ((Entity)entity).getPosition(partialTicks).add(leashState.offset);
|
|
leashState.end = holderPos.add(roperAttachmentPoints[i].yRot(-roperYRot));
|
|
leashState.startBlockLight = startBlockLight;
|
|
leashState.endBlockLight = endBlockLight;
|
|
leashState.startSkyLight = startSkyLight;
|
|
leashState.endSkyLight = endSkyLight;
|
|
leashState.slack = false;
|
|
}
|
|
} else {
|
|
Vec3 rotatedAttachOffset = attachOffset.yRot(-entityYRot);
|
|
EntityRenderState.LeashState leashState = ((EntityRenderState)state).leashStates.getFirst();
|
|
leashState.offset = rotatedAttachOffset;
|
|
leashState.start = ((Entity)entity).getPosition(partialTicks).add(rotatedAttachOffset);
|
|
leashState.end = roper.getRopeHoldPosition(partialTicks);
|
|
leashState.startBlockLight = startBlockLight;
|
|
leashState.endBlockLight = endBlockLight;
|
|
leashState.startSkyLight = startSkyLight;
|
|
leashState.endSkyLight = endSkyLight;
|
|
}
|
|
} else {
|
|
((EntityRenderState)state).leashStates = null;
|
|
}
|
|
((EntityRenderState)state).displayFireAnimation = ((Entity)entity).displayFireAnimation();
|
|
Minecraft minecraft = Minecraft.getInstance();
|
|
boolean appearsGlowing = minecraft.shouldEntityAppearGlowing((Entity)entity);
|
|
((EntityRenderState)state).outlineColor = appearsGlowing ? ARGB.opaque(((Entity)entity).getTeamColor()) : 0;
|
|
((EntityRenderState)state).lightCoords = this.getPackedLightCoords(entity, partialTicks);
|
|
}
|
|
|
|
protected void finalizeRenderState(T entity, S state) {
|
|
Minecraft minecraft = Minecraft.getInstance();
|
|
Level level = ((Entity)entity).level();
|
|
this.extractShadow(state, minecraft, level);
|
|
}
|
|
|
|
private void extractShadow(S state, Minecraft minecraft, Level level) {
|
|
((EntityRenderState)state).shadowPieces.clear();
|
|
if (minecraft.options.entityShadows().get().booleanValue() && !((EntityRenderState)state).isInvisible) {
|
|
double distSq;
|
|
float pow;
|
|
float shadowRadius;
|
|
((EntityRenderState)state).shadowRadius = shadowRadius = Math.min(this.getShadowRadius(state), 32.0f);
|
|
if (shadowRadius > 0.0f && (pow = (float)((1.0 - (distSq = ((EntityRenderState)state).distanceToCameraSq) / 256.0) * (double)this.getShadowStrength(state))) > 0.0f) {
|
|
int x0 = Mth.floor(((EntityRenderState)state).x - (double)shadowRadius);
|
|
int x1 = Mth.floor(((EntityRenderState)state).x + (double)shadowRadius);
|
|
int z0 = Mth.floor(((EntityRenderState)state).z - (double)shadowRadius);
|
|
int z1 = Mth.floor(((EntityRenderState)state).z + (double)shadowRadius);
|
|
float depth = Math.min(pow / 0.5f - 1.0f, shadowRadius);
|
|
int y0 = Mth.floor(((EntityRenderState)state).y - (double)depth);
|
|
int y1 = Mth.floor(((EntityRenderState)state).y);
|
|
BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
|
for (int z = z0; z <= z1; ++z) {
|
|
for (int x = x0; x <= x1; ++x) {
|
|
pos.set(x, 0, z);
|
|
ChunkAccess chunk = level.getChunk(pos);
|
|
for (int y = y0; y <= y1; ++y) {
|
|
pos.setY(y);
|
|
this.extractShadowPiece(state, level, pow, pos, chunk);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
((EntityRenderState)state).shadowRadius = 0.0f;
|
|
}
|
|
}
|
|
|
|
private void extractShadowPiece(S state, Level level, float pow, BlockPos.MutableBlockPos pos, ChunkAccess chunk) {
|
|
float powerAtDepth = pow - (float)(((EntityRenderState)state).y - (double)pos.getY()) * 0.5f;
|
|
Vec3i belowPos = pos.below();
|
|
BlockState belowState = chunk.getBlockState((BlockPos)belowPos);
|
|
if (belowState.getRenderShape() == RenderShape.INVISIBLE) {
|
|
return;
|
|
}
|
|
int brightness = level.getMaxLocalRawBrightness(pos);
|
|
if (brightness <= 3) {
|
|
return;
|
|
}
|
|
if (!belowState.isCollisionShapeFullBlock(chunk, (BlockPos)belowPos)) {
|
|
return;
|
|
}
|
|
VoxelShape belowShape = belowState.getShape(chunk, (BlockPos)belowPos);
|
|
if (belowShape.isEmpty()) {
|
|
return;
|
|
}
|
|
float alpha = Mth.clamp(powerAtDepth * 0.5f * LightTexture.getBrightness(level.dimensionType(), brightness), 0.0f, 1.0f);
|
|
float relativeX = (float)((double)pos.getX() - ((EntityRenderState)state).x);
|
|
float relativeY = (float)((double)pos.getY() - ((EntityRenderState)state).y);
|
|
float relativeZ = (float)((double)pos.getZ() - ((EntityRenderState)state).z);
|
|
((EntityRenderState)state).shadowPieces.add(new EntityRenderState.ShadowPiece(relativeX, relativeY, relativeZ, belowShape, alpha));
|
|
}
|
|
|
|
private static @Nullable Entity getServerSideEntity(Entity entity) {
|
|
ServerLevel level;
|
|
IntegratedServer server = Minecraft.getInstance().getSingleplayerServer();
|
|
if (server != null && (level = server.getLevel(entity.level().dimension())) != null) {
|
|
return level.getEntity(entity.getId());
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|