908 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			908 lines
		
	
	
	
		
			33 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.entity;
 | |
| 
 | |
| import com.mojang.logging.LogUtils;
 | |
| import com.mojang.math.Transformation;
 | |
| import com.mojang.serialization.Codec;
 | |
| import it.unimi.dsi.fastutil.ints.IntSet;
 | |
| import java.util.List;
 | |
| import java.util.Optional;
 | |
| import java.util.function.IntFunction;
 | |
| import net.minecraft.commands.CommandSourceStack;
 | |
| import net.minecraft.network.chat.Component;
 | |
| import net.minecraft.network.chat.ComponentSerialization;
 | |
| import net.minecraft.network.chat.ComponentUtils;
 | |
| import net.minecraft.network.syncher.EntityDataAccessor;
 | |
| import net.minecraft.network.syncher.EntityDataSerializers;
 | |
| import net.minecraft.network.syncher.SynchedEntityData;
 | |
| import net.minecraft.server.level.ServerLevel;
 | |
| import net.minecraft.util.ARGB;
 | |
| import net.minecraft.util.Brightness;
 | |
| import net.minecraft.util.ByIdMap;
 | |
| import net.minecraft.util.FormattedCharSequence;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.StringRepresentable;
 | |
| import net.minecraft.world.damagesource.DamageSource;
 | |
| import net.minecraft.world.item.ItemDisplayContext;
 | |
| import net.minecraft.world.item.ItemStack;
 | |
| import net.minecraft.world.level.Level;
 | |
| import net.minecraft.world.level.block.Blocks;
 | |
| import net.minecraft.world.level.block.state.BlockState;
 | |
| import net.minecraft.world.level.material.PushReaction;
 | |
| import net.minecraft.world.level.storage.ValueInput;
 | |
| import net.minecraft.world.level.storage.ValueOutput;
 | |
| import net.minecraft.world.phys.AABB;
 | |
| import org.jetbrains.annotations.Nullable;
 | |
| import org.joml.Quaternionf;
 | |
| import org.joml.Vector3f;
 | |
| import org.slf4j.Logger;
 | |
| 
 | |
| public abstract class Display extends Entity {
 | |
| 	static final Logger LOGGER = LogUtils.getLogger();
 | |
| 	public static final int NO_BRIGHTNESS_OVERRIDE = -1;
 | |
| 	private static final EntityDataAccessor<Integer> DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID = SynchedEntityData.defineId(
 | |
| 		Display.class, EntityDataSerializers.INT
 | |
| 	);
 | |
| 	private static final EntityDataAccessor<Integer> DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID = SynchedEntityData.defineId(
 | |
| 		Display.class, EntityDataSerializers.INT
 | |
| 	);
 | |
| 	private static final EntityDataAccessor<Integer> DATA_POS_ROT_INTERPOLATION_DURATION_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.INT);
 | |
| 	private static final EntityDataAccessor<Vector3f> DATA_TRANSLATION_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.VECTOR3);
 | |
| 	private static final EntityDataAccessor<Vector3f> DATA_SCALE_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.VECTOR3);
 | |
| 	private static final EntityDataAccessor<Quaternionf> DATA_LEFT_ROTATION_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.QUATERNION);
 | |
| 	private static final EntityDataAccessor<Quaternionf> DATA_RIGHT_ROTATION_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.QUATERNION);
 | |
| 	private static final EntityDataAccessor<Byte> DATA_BILLBOARD_RENDER_CONSTRAINTS_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.BYTE);
 | |
| 	private static final EntityDataAccessor<Integer> DATA_BRIGHTNESS_OVERRIDE_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.INT);
 | |
| 	private static final EntityDataAccessor<Float> DATA_VIEW_RANGE_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.FLOAT);
 | |
| 	private static final EntityDataAccessor<Float> DATA_SHADOW_RADIUS_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.FLOAT);
 | |
| 	private static final EntityDataAccessor<Float> DATA_SHADOW_STRENGTH_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.FLOAT);
 | |
| 	private static final EntityDataAccessor<Float> DATA_WIDTH_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.FLOAT);
 | |
| 	private static final EntityDataAccessor<Float> DATA_HEIGHT_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.FLOAT);
 | |
| 	private static final EntityDataAccessor<Integer> DATA_GLOW_COLOR_OVERRIDE_ID = SynchedEntityData.defineId(Display.class, EntityDataSerializers.INT);
 | |
| 	private static final IntSet RENDER_STATE_IDS = IntSet.of(
 | |
| 		DATA_TRANSLATION_ID.id(),
 | |
| 		DATA_SCALE_ID.id(),
 | |
| 		DATA_LEFT_ROTATION_ID.id(),
 | |
| 		DATA_RIGHT_ROTATION_ID.id(),
 | |
| 		DATA_BILLBOARD_RENDER_CONSTRAINTS_ID.id(),
 | |
| 		DATA_BRIGHTNESS_OVERRIDE_ID.id(),
 | |
| 		DATA_SHADOW_RADIUS_ID.id(),
 | |
| 		DATA_SHADOW_STRENGTH_ID.id()
 | |
| 	);
 | |
| 	private static final int INITIAL_TRANSFORMATION_INTERPOLATION_DURATION = 0;
 | |
| 	private static final int INITIAL_TRANSFORMATION_START_INTERPOLATION = 0;
 | |
| 	private static final int INITIAL_POS_ROT_INTERPOLATION_DURATION = 0;
 | |
| 	private static final float INITIAL_SHADOW_RADIUS = 0.0F;
 | |
| 	private static final float INITIAL_SHADOW_STRENGTH = 1.0F;
 | |
| 	private static final float INITIAL_VIEW_RANGE = 1.0F;
 | |
| 	private static final float INITIAL_WIDTH = 0.0F;
 | |
| 	private static final float INITIAL_HEIGHT = 0.0F;
 | |
| 	private static final int NO_GLOW_COLOR_OVERRIDE = -1;
 | |
| 	public static final String TAG_POS_ROT_INTERPOLATION_DURATION = "teleport_duration";
 | |
| 	public static final String TAG_TRANSFORMATION_INTERPOLATION_DURATION = "interpolation_duration";
 | |
| 	public static final String TAG_TRANSFORMATION_START_INTERPOLATION = "start_interpolation";
 | |
| 	public static final String TAG_TRANSFORMATION = "transformation";
 | |
| 	public static final String TAG_BILLBOARD = "billboard";
 | |
| 	public static final String TAG_BRIGHTNESS = "brightness";
 | |
| 	public static final String TAG_VIEW_RANGE = "view_range";
 | |
| 	public static final String TAG_SHADOW_RADIUS = "shadow_radius";
 | |
| 	public static final String TAG_SHADOW_STRENGTH = "shadow_strength";
 | |
| 	public static final String TAG_WIDTH = "width";
 | |
| 	public static final String TAG_HEIGHT = "height";
 | |
| 	public static final String TAG_GLOW_COLOR_OVERRIDE = "glow_color_override";
 | |
| 	private long interpolationStartClientTick = -2147483648L;
 | |
| 	private int interpolationDuration;
 | |
| 	private float lastProgress;
 | |
| 	private AABB cullingBoundingBox;
 | |
| 	private boolean noCulling = true;
 | |
| 	protected boolean updateRenderState;
 | |
| 	private boolean updateStartTick;
 | |
| 	private boolean updateInterpolationDuration;
 | |
| 	@Nullable
 | |
| 	private Display.RenderState renderState;
 | |
| 	private final InterpolationHandler interpolation = new InterpolationHandler(this, 0);
 | |
| 
 | |
| 	public Display(EntityType<?> entityType, Level level) {
 | |
| 		super(entityType, level);
 | |
| 		this.noPhysics = true;
 | |
| 		this.cullingBoundingBox = this.getBoundingBox();
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void onSyncedDataUpdated(EntityDataAccessor<?> dataAccessor) {
 | |
| 		super.onSyncedDataUpdated(dataAccessor);
 | |
| 		if (DATA_HEIGHT_ID.equals(dataAccessor) || DATA_WIDTH_ID.equals(dataAccessor)) {
 | |
| 			this.updateCulling();
 | |
| 		}
 | |
| 
 | |
| 		if (DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID.equals(dataAccessor)) {
 | |
| 			this.updateStartTick = true;
 | |
| 		}
 | |
| 
 | |
| 		if (DATA_POS_ROT_INTERPOLATION_DURATION_ID.equals(dataAccessor)) {
 | |
| 			this.interpolation.setInterpolationLength(this.getPosRotInterpolationDuration());
 | |
| 		}
 | |
| 
 | |
| 		if (DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID.equals(dataAccessor)) {
 | |
| 			this.updateInterpolationDuration = true;
 | |
| 		}
 | |
| 
 | |
| 		if (RENDER_STATE_IDS.contains(dataAccessor.id())) {
 | |
| 			this.updateRenderState = true;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public final boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) {
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	private static Transformation createTransformation(SynchedEntityData synchedEntityData) {
 | |
| 		Vector3f vector3f = synchedEntityData.get(DATA_TRANSLATION_ID);
 | |
| 		Quaternionf quaternionf = synchedEntityData.get(DATA_LEFT_ROTATION_ID);
 | |
| 		Vector3f vector3f2 = synchedEntityData.get(DATA_SCALE_ID);
 | |
| 		Quaternionf quaternionf2 = synchedEntityData.get(DATA_RIGHT_ROTATION_ID);
 | |
| 		return new Transformation(vector3f, quaternionf, vector3f2, quaternionf2);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void tick() {
 | |
| 		Entity entity = this.getVehicle();
 | |
| 		if (entity != null && entity.isRemoved()) {
 | |
| 			this.stopRiding();
 | |
| 		}
 | |
| 
 | |
| 		if (this.level().isClientSide) {
 | |
| 			if (this.updateStartTick) {
 | |
| 				this.updateStartTick = false;
 | |
| 				int i = this.getTransformationInterpolationDelay();
 | |
| 				this.interpolationStartClientTick = this.tickCount + i;
 | |
| 			}
 | |
| 
 | |
| 			if (this.updateInterpolationDuration) {
 | |
| 				this.updateInterpolationDuration = false;
 | |
| 				this.interpolationDuration = this.getTransformationInterpolationDuration();
 | |
| 			}
 | |
| 
 | |
| 			if (this.updateRenderState) {
 | |
| 				this.updateRenderState = false;
 | |
| 				boolean bl = this.interpolationDuration != 0;
 | |
| 				if (bl && this.renderState != null) {
 | |
| 					this.renderState = this.createInterpolatedRenderState(this.renderState, this.lastProgress);
 | |
| 				} else {
 | |
| 					this.renderState = this.createFreshRenderState();
 | |
| 				}
 | |
| 
 | |
| 				this.updateRenderSubState(bl, this.lastProgress);
 | |
| 			}
 | |
| 
 | |
| 			this.interpolation.interpolate();
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public InterpolationHandler getInterpolation() {
 | |
| 		return this.interpolation;
 | |
| 	}
 | |
| 
 | |
| 	protected abstract void updateRenderSubState(boolean interpolate, float partialTick);
 | |
| 
 | |
| 	@Override
 | |
| 	protected void defineSynchedData(SynchedEntityData.Builder builder) {
 | |
| 		builder.define(DATA_POS_ROT_INTERPOLATION_DURATION_ID, 0);
 | |
| 		builder.define(DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID, 0);
 | |
| 		builder.define(DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID, 0);
 | |
| 		builder.define(DATA_TRANSLATION_ID, new Vector3f());
 | |
| 		builder.define(DATA_SCALE_ID, new Vector3f(1.0F, 1.0F, 1.0F));
 | |
| 		builder.define(DATA_RIGHT_ROTATION_ID, new Quaternionf());
 | |
| 		builder.define(DATA_LEFT_ROTATION_ID, new Quaternionf());
 | |
| 		builder.define(DATA_BILLBOARD_RENDER_CONSTRAINTS_ID, Display.BillboardConstraints.FIXED.getId());
 | |
| 		builder.define(DATA_BRIGHTNESS_OVERRIDE_ID, -1);
 | |
| 		builder.define(DATA_VIEW_RANGE_ID, 1.0F);
 | |
| 		builder.define(DATA_SHADOW_RADIUS_ID, 0.0F);
 | |
| 		builder.define(DATA_SHADOW_STRENGTH_ID, 1.0F);
 | |
| 		builder.define(DATA_WIDTH_ID, 0.0F);
 | |
| 		builder.define(DATA_HEIGHT_ID, 0.0F);
 | |
| 		builder.define(DATA_GLOW_COLOR_OVERRIDE_ID, -1);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void readAdditionalSaveData(ValueInput input) {
 | |
| 		this.setTransformation((Transformation)input.read("transformation", Transformation.EXTENDED_CODEC).orElse(Transformation.identity()));
 | |
| 		this.setTransformationInterpolationDuration(input.getIntOr("interpolation_duration", 0));
 | |
| 		this.setTransformationInterpolationDelay(input.getIntOr("start_interpolation", 0));
 | |
| 		int i = input.getIntOr("teleport_duration", 0);
 | |
| 		this.setPosRotInterpolationDuration(Mth.clamp(i, 0, 59));
 | |
| 		this.setBillboardConstraints(
 | |
| 			(Display.BillboardConstraints)input.read("billboard", Display.BillboardConstraints.CODEC).orElse(Display.BillboardConstraints.FIXED)
 | |
| 		);
 | |
| 		this.setViewRange(input.getFloatOr("view_range", 1.0F));
 | |
| 		this.setShadowRadius(input.getFloatOr("shadow_radius", 0.0F));
 | |
| 		this.setShadowStrength(input.getFloatOr("shadow_strength", 1.0F));
 | |
| 		this.setWidth(input.getFloatOr("width", 0.0F));
 | |
| 		this.setHeight(input.getFloatOr("height", 0.0F));
 | |
| 		this.setGlowColorOverride(input.getIntOr("glow_color_override", -1));
 | |
| 		this.setBrightnessOverride((Brightness)input.read("brightness", Brightness.CODEC).orElse(null));
 | |
| 	}
 | |
| 
 | |
| 	private void setTransformation(Transformation transformation) {
 | |
| 		this.entityData.set(DATA_TRANSLATION_ID, transformation.getTranslation());
 | |
| 		this.entityData.set(DATA_LEFT_ROTATION_ID, transformation.getLeftRotation());
 | |
| 		this.entityData.set(DATA_SCALE_ID, transformation.getScale());
 | |
| 		this.entityData.set(DATA_RIGHT_ROTATION_ID, transformation.getRightRotation());
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 		output.store("transformation", Transformation.EXTENDED_CODEC, createTransformation(this.entityData));
 | |
| 		output.store("billboard", Display.BillboardConstraints.CODEC, this.getBillboardConstraints());
 | |
| 		output.putInt("interpolation_duration", this.getTransformationInterpolationDuration());
 | |
| 		output.putInt("teleport_duration", this.getPosRotInterpolationDuration());
 | |
| 		output.putFloat("view_range", this.getViewRange());
 | |
| 		output.putFloat("shadow_radius", this.getShadowRadius());
 | |
| 		output.putFloat("shadow_strength", this.getShadowStrength());
 | |
| 		output.putFloat("width", this.getWidth());
 | |
| 		output.putFloat("height", this.getHeight());
 | |
| 		output.putInt("glow_color_override", this.getGlowColorOverride());
 | |
| 		output.storeNullable("brightness", Brightness.CODEC, this.getBrightnessOverride());
 | |
| 	}
 | |
| 
 | |
| 	public AABB getBoundingBoxForCulling() {
 | |
| 		return this.cullingBoundingBox;
 | |
| 	}
 | |
| 
 | |
| 	public boolean affectedByCulling() {
 | |
| 		return !this.noCulling;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public PushReaction getPistonPushReaction() {
 | |
| 		return PushReaction.IGNORE;
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean isIgnoringBlockTriggers() {
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	public Display.RenderState renderState() {
 | |
| 		return this.renderState;
 | |
| 	}
 | |
| 
 | |
| 	private void setTransformationInterpolationDuration(int transformationInterpolationDuration) {
 | |
| 		this.entityData.set(DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID, transformationInterpolationDuration);
 | |
| 	}
 | |
| 
 | |
| 	private int getTransformationInterpolationDuration() {
 | |
| 		return this.entityData.get(DATA_TRANSFORMATION_INTERPOLATION_DURATION_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setTransformationInterpolationDelay(int transformationInterpolationDelay) {
 | |
| 		this.entityData.set(DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID, transformationInterpolationDelay, true);
 | |
| 	}
 | |
| 
 | |
| 	private int getTransformationInterpolationDelay() {
 | |
| 		return this.entityData.get(DATA_TRANSFORMATION_INTERPOLATION_START_DELTA_TICKS_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setPosRotInterpolationDuration(int posRotInterpolationDuration) {
 | |
| 		this.entityData.set(DATA_POS_ROT_INTERPOLATION_DURATION_ID, posRotInterpolationDuration);
 | |
| 	}
 | |
| 
 | |
| 	private int getPosRotInterpolationDuration() {
 | |
| 		return this.entityData.get(DATA_POS_ROT_INTERPOLATION_DURATION_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setBillboardConstraints(Display.BillboardConstraints billboardConstraints) {
 | |
| 		this.entityData.set(DATA_BILLBOARD_RENDER_CONSTRAINTS_ID, billboardConstraints.getId());
 | |
| 	}
 | |
| 
 | |
| 	private Display.BillboardConstraints getBillboardConstraints() {
 | |
| 		return (Display.BillboardConstraints)Display.BillboardConstraints.BY_ID.apply(this.entityData.get(DATA_BILLBOARD_RENDER_CONSTRAINTS_ID));
 | |
| 	}
 | |
| 
 | |
| 	private void setBrightnessOverride(@Nullable Brightness brightnessOverride) {
 | |
| 		this.entityData.set(DATA_BRIGHTNESS_OVERRIDE_ID, brightnessOverride != null ? brightnessOverride.pack() : -1);
 | |
| 	}
 | |
| 
 | |
| 	@Nullable
 | |
| 	private Brightness getBrightnessOverride() {
 | |
| 		int i = this.entityData.get(DATA_BRIGHTNESS_OVERRIDE_ID);
 | |
| 		return i != -1 ? Brightness.unpack(i) : null;
 | |
| 	}
 | |
| 
 | |
| 	private int getPackedBrightnessOverride() {
 | |
| 		return this.entityData.get(DATA_BRIGHTNESS_OVERRIDE_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setViewRange(float viewRange) {
 | |
| 		this.entityData.set(DATA_VIEW_RANGE_ID, viewRange);
 | |
| 	}
 | |
| 
 | |
| 	private float getViewRange() {
 | |
| 		return this.entityData.get(DATA_VIEW_RANGE_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setShadowRadius(float shadowRadius) {
 | |
| 		this.entityData.set(DATA_SHADOW_RADIUS_ID, shadowRadius);
 | |
| 	}
 | |
| 
 | |
| 	private float getShadowRadius() {
 | |
| 		return this.entityData.get(DATA_SHADOW_RADIUS_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setShadowStrength(float shadowStrength) {
 | |
| 		this.entityData.set(DATA_SHADOW_STRENGTH_ID, shadowStrength);
 | |
| 	}
 | |
| 
 | |
| 	private float getShadowStrength() {
 | |
| 		return this.entityData.get(DATA_SHADOW_STRENGTH_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setWidth(float width) {
 | |
| 		this.entityData.set(DATA_WIDTH_ID, width);
 | |
| 	}
 | |
| 
 | |
| 	private float getWidth() {
 | |
| 		return this.entityData.get(DATA_WIDTH_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setHeight(float height) {
 | |
| 		this.entityData.set(DATA_HEIGHT_ID, height);
 | |
| 	}
 | |
| 
 | |
| 	private int getGlowColorOverride() {
 | |
| 		return this.entityData.get(DATA_GLOW_COLOR_OVERRIDE_ID);
 | |
| 	}
 | |
| 
 | |
| 	private void setGlowColorOverride(int glowColorOverride) {
 | |
| 		this.entityData.set(DATA_GLOW_COLOR_OVERRIDE_ID, glowColorOverride);
 | |
| 	}
 | |
| 
 | |
| 	public float calculateInterpolationProgress(float partialTick) {
 | |
| 		int i = this.interpolationDuration;
 | |
| 		if (i <= 0) {
 | |
| 			return 1.0F;
 | |
| 		} else {
 | |
| 			float f = (float)(this.tickCount - this.interpolationStartClientTick);
 | |
| 			float g = f + partialTick;
 | |
| 			float h = Mth.clamp(Mth.inverseLerp(g, 0.0F, (float)i), 0.0F, 1.0F);
 | |
| 			this.lastProgress = h;
 | |
| 			return h;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private float getHeight() {
 | |
| 		return this.entityData.get(DATA_HEIGHT_ID);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public void setPos(double x, double y, double z) {
 | |
| 		super.setPos(x, y, z);
 | |
| 		this.updateCulling();
 | |
| 	}
 | |
| 
 | |
| 	private void updateCulling() {
 | |
| 		float f = this.getWidth();
 | |
| 		float g = this.getHeight();
 | |
| 		this.noCulling = f == 0.0F || g == 0.0F;
 | |
| 		float h = f / 2.0F;
 | |
| 		double d = this.getX();
 | |
| 		double e = this.getY();
 | |
| 		double i = this.getZ();
 | |
| 		this.cullingBoundingBox = new AABB(d - h, e, i - h, d + h, e + g, i + h);
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public boolean shouldRenderAtSqrDistance(double distance) {
 | |
| 		return distance < Mth.square(this.getViewRange() * 64.0 * getViewScale());
 | |
| 	}
 | |
| 
 | |
| 	@Override
 | |
| 	public int getTeamColor() {
 | |
| 		int i = this.getGlowColorOverride();
 | |
| 		return i != -1 ? i : super.getTeamColor();
 | |
| 	}
 | |
| 
 | |
| 	private Display.RenderState createFreshRenderState() {
 | |
| 		return new Display.RenderState(
 | |
| 			Display.GenericInterpolator.constant(createTransformation(this.entityData)),
 | |
| 			this.getBillboardConstraints(),
 | |
| 			this.getPackedBrightnessOverride(),
 | |
| 			Display.FloatInterpolator.constant(this.getShadowRadius()),
 | |
| 			Display.FloatInterpolator.constant(this.getShadowStrength()),
 | |
| 			this.getGlowColorOverride()
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	private Display.RenderState createInterpolatedRenderState(Display.RenderState renderState, float partialTick) {
 | |
| 		Transformation transformation = renderState.transformation.get(partialTick);
 | |
| 		float f = renderState.shadowRadius.get(partialTick);
 | |
| 		float g = renderState.shadowStrength.get(partialTick);
 | |
| 		return new Display.RenderState(
 | |
| 			new Display.TransformationInterpolator(transformation, createTransformation(this.entityData)),
 | |
| 			this.getBillboardConstraints(),
 | |
| 			this.getPackedBrightnessOverride(),
 | |
| 			new Display.LinearFloatInterpolator(f, this.getShadowRadius()),
 | |
| 			new Display.LinearFloatInterpolator(g, this.getShadowStrength()),
 | |
| 			this.getGlowColorOverride()
 | |
| 		);
 | |
| 	}
 | |
| 
 | |
| 	public static enum BillboardConstraints implements StringRepresentable {
 | |
| 		FIXED((byte)0, "fixed"),
 | |
| 		VERTICAL((byte)1, "vertical"),
 | |
| 		HORIZONTAL((byte)2, "horizontal"),
 | |
| 		CENTER((byte)3, "center");
 | |
| 
 | |
| 		public static final Codec<Display.BillboardConstraints> CODEC = StringRepresentable.fromEnum(Display.BillboardConstraints::values);
 | |
| 		public static final IntFunction<Display.BillboardConstraints> BY_ID = ByIdMap.continuous(
 | |
| 			Display.BillboardConstraints::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO
 | |
| 		);
 | |
| 		private final byte id;
 | |
| 		private final String name;
 | |
| 
 | |
| 		private BillboardConstraints(final byte id, final String name) {
 | |
| 			this.name = name;
 | |
| 			this.id = id;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public String getSerializedName() {
 | |
| 			return this.name;
 | |
| 		}
 | |
| 
 | |
| 		byte getId() {
 | |
| 			return this.id;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public static class BlockDisplay extends Display {
 | |
| 		public static final String TAG_BLOCK_STATE = "block_state";
 | |
| 		private static final EntityDataAccessor<BlockState> DATA_BLOCK_STATE_ID = SynchedEntityData.defineId(
 | |
| 			Display.BlockDisplay.class, EntityDataSerializers.BLOCK_STATE
 | |
| 		);
 | |
| 		@Nullable
 | |
| 		private Display.BlockDisplay.BlockRenderState blockRenderState;
 | |
| 
 | |
| 		public BlockDisplay(EntityType<?> entityType, Level level) {
 | |
| 			super(entityType, level);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void defineSynchedData(SynchedEntityData.Builder builder) {
 | |
| 			super.defineSynchedData(builder);
 | |
| 			builder.define(DATA_BLOCK_STATE_ID, Blocks.AIR.defaultBlockState());
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public void onSyncedDataUpdated(EntityDataAccessor<?> dataAccessor) {
 | |
| 			super.onSyncedDataUpdated(dataAccessor);
 | |
| 			if (dataAccessor.equals(DATA_BLOCK_STATE_ID)) {
 | |
| 				this.updateRenderState = true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private BlockState getBlockState() {
 | |
| 			return this.entityData.get(DATA_BLOCK_STATE_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setBlockState(BlockState blockState) {
 | |
| 			this.entityData.set(DATA_BLOCK_STATE_ID, blockState);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void readAdditionalSaveData(ValueInput input) {
 | |
| 			super.readAdditionalSaveData(input);
 | |
| 			this.setBlockState((BlockState)input.read("block_state", BlockState.CODEC).orElse(Blocks.AIR.defaultBlockState()));
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 			super.addAdditionalSaveData(output);
 | |
| 			output.store("block_state", BlockState.CODEC, this.getBlockState());
 | |
| 		}
 | |
| 
 | |
| 		@Nullable
 | |
| 		public Display.BlockDisplay.BlockRenderState blockRenderState() {
 | |
| 			return this.blockRenderState;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void updateRenderSubState(boolean interpolate, float partialTick) {
 | |
| 			this.blockRenderState = new Display.BlockDisplay.BlockRenderState(this.getBlockState());
 | |
| 		}
 | |
| 
 | |
| 		public record BlockRenderState(BlockState blockState) {
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	record ColorInterpolator(int previous, int current) implements Display.IntInterpolator {
 | |
| 		@Override
 | |
| 		public int get(float f) {
 | |
| 			return ARGB.lerp(f, this.previous, this.current);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	@FunctionalInterface
 | |
| 	public interface FloatInterpolator {
 | |
| 		static Display.FloatInterpolator constant(float f) {
 | |
| 			return g -> f;
 | |
| 		}
 | |
| 
 | |
| 		float get(float partialTick);
 | |
| 	}
 | |
| 
 | |
| 	@FunctionalInterface
 | |
| 	public interface GenericInterpolator<T> {
 | |
| 		static <T> Display.GenericInterpolator<T> constant(T object) {
 | |
| 			return f -> object;
 | |
| 		}
 | |
| 
 | |
| 		T get(float partialTick);
 | |
| 	}
 | |
| 
 | |
| 	@FunctionalInterface
 | |
| 	public interface IntInterpolator {
 | |
| 		static Display.IntInterpolator constant(int i) {
 | |
| 			return f -> i;
 | |
| 		}
 | |
| 
 | |
| 		int get(float partialTick);
 | |
| 	}
 | |
| 
 | |
| 	public static class ItemDisplay extends Display {
 | |
| 		private static final String TAG_ITEM = "item";
 | |
| 		private static final String TAG_ITEM_DISPLAY = "item_display";
 | |
| 		private static final EntityDataAccessor<ItemStack> DATA_ITEM_STACK_ID = SynchedEntityData.defineId(
 | |
| 			Display.ItemDisplay.class, EntityDataSerializers.ITEM_STACK
 | |
| 		);
 | |
| 		private static final EntityDataAccessor<Byte> DATA_ITEM_DISPLAY_ID = SynchedEntityData.defineId(Display.ItemDisplay.class, EntityDataSerializers.BYTE);
 | |
| 		private final SlotAccess slot = SlotAccess.of(this::getItemStack, this::setItemStack);
 | |
| 		@Nullable
 | |
| 		private Display.ItemDisplay.ItemRenderState itemRenderState;
 | |
| 
 | |
| 		public ItemDisplay(EntityType<?> entityType, Level level) {
 | |
| 			super(entityType, level);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void defineSynchedData(SynchedEntityData.Builder builder) {
 | |
| 			super.defineSynchedData(builder);
 | |
| 			builder.define(DATA_ITEM_STACK_ID, ItemStack.EMPTY);
 | |
| 			builder.define(DATA_ITEM_DISPLAY_ID, ItemDisplayContext.NONE.getId());
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public void onSyncedDataUpdated(EntityDataAccessor<?> dataAccessor) {
 | |
| 			super.onSyncedDataUpdated(dataAccessor);
 | |
| 			if (DATA_ITEM_STACK_ID.equals(dataAccessor) || DATA_ITEM_DISPLAY_ID.equals(dataAccessor)) {
 | |
| 				this.updateRenderState = true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private ItemStack getItemStack() {
 | |
| 			return this.entityData.get(DATA_ITEM_STACK_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setItemStack(ItemStack itemStack) {
 | |
| 			this.entityData.set(DATA_ITEM_STACK_ID, itemStack);
 | |
| 		}
 | |
| 
 | |
| 		private void setItemTransform(ItemDisplayContext itemTransform) {
 | |
| 			this.entityData.set(DATA_ITEM_DISPLAY_ID, itemTransform.getId());
 | |
| 		}
 | |
| 
 | |
| 		private ItemDisplayContext getItemTransform() {
 | |
| 			return (ItemDisplayContext)ItemDisplayContext.BY_ID.apply(this.entityData.get(DATA_ITEM_DISPLAY_ID));
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void readAdditionalSaveData(ValueInput input) {
 | |
| 			super.readAdditionalSaveData(input);
 | |
| 			this.setItemStack((ItemStack)input.read("item", ItemStack.CODEC).orElse(ItemStack.EMPTY));
 | |
| 			this.setItemTransform((ItemDisplayContext)input.read("item_display", ItemDisplayContext.CODEC).orElse(ItemDisplayContext.NONE));
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 			super.addAdditionalSaveData(output);
 | |
| 			ItemStack itemStack = this.getItemStack();
 | |
| 			if (!itemStack.isEmpty()) {
 | |
| 				output.store("item", ItemStack.CODEC, itemStack);
 | |
| 			}
 | |
| 
 | |
| 			output.store("item_display", ItemDisplayContext.CODEC, this.getItemTransform());
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public SlotAccess getSlot(int slot) {
 | |
| 			return slot == 0 ? this.slot : SlotAccess.NULL;
 | |
| 		}
 | |
| 
 | |
| 		@Nullable
 | |
| 		public Display.ItemDisplay.ItemRenderState itemRenderState() {
 | |
| 			return this.itemRenderState;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void updateRenderSubState(boolean interpolate, float partialTick) {
 | |
| 			ItemStack itemStack = this.getItemStack();
 | |
| 			itemStack.setEntityRepresentation(this);
 | |
| 			this.itemRenderState = new Display.ItemDisplay.ItemRenderState(itemStack, this.getItemTransform());
 | |
| 		}
 | |
| 
 | |
| 		public record ItemRenderState(ItemStack itemStack, ItemDisplayContext itemTransform) {
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	record LinearFloatInterpolator(float previous, float current) implements Display.FloatInterpolator {
 | |
| 		@Override
 | |
| 		public float get(float f) {
 | |
| 			return Mth.lerp(f, this.previous, this.current);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	record LinearIntInterpolator(int previous, int current) implements Display.IntInterpolator {
 | |
| 		@Override
 | |
| 		public int get(float f) {
 | |
| 			return Mth.lerpInt(f, this.previous, this.current);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public record RenderState(
 | |
| 		Display.GenericInterpolator<Transformation> transformation,
 | |
| 		Display.BillboardConstraints billboardConstraints,
 | |
| 		int brightnessOverride,
 | |
| 		Display.FloatInterpolator shadowRadius,
 | |
| 		Display.FloatInterpolator shadowStrength,
 | |
| 		int glowColorOverride
 | |
| 	) {
 | |
| 	}
 | |
| 
 | |
| 	public static class TextDisplay extends Display {
 | |
| 		public static final String TAG_TEXT = "text";
 | |
| 		private static final String TAG_LINE_WIDTH = "line_width";
 | |
| 		private static final String TAG_TEXT_OPACITY = "text_opacity";
 | |
| 		private static final String TAG_BACKGROUND_COLOR = "background";
 | |
| 		private static final String TAG_SHADOW = "shadow";
 | |
| 		private static final String TAG_SEE_THROUGH = "see_through";
 | |
| 		private static final String TAG_USE_DEFAULT_BACKGROUND = "default_background";
 | |
| 		private static final String TAG_ALIGNMENT = "alignment";
 | |
| 		public static final byte FLAG_SHADOW = 1;
 | |
| 		public static final byte FLAG_SEE_THROUGH = 2;
 | |
| 		public static final byte FLAG_USE_DEFAULT_BACKGROUND = 4;
 | |
| 		public static final byte FLAG_ALIGN_LEFT = 8;
 | |
| 		public static final byte FLAG_ALIGN_RIGHT = 16;
 | |
| 		private static final byte INITIAL_TEXT_OPACITY = -1;
 | |
| 		public static final int INITIAL_BACKGROUND = 1073741824;
 | |
| 		private static final int INITIAL_LINE_WIDTH = 200;
 | |
| 		private static final EntityDataAccessor<Component> DATA_TEXT_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.COMPONENT);
 | |
| 		private static final EntityDataAccessor<Integer> DATA_LINE_WIDTH_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.INT);
 | |
| 		private static final EntityDataAccessor<Integer> DATA_BACKGROUND_COLOR_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.INT);
 | |
| 		private static final EntityDataAccessor<Byte> DATA_TEXT_OPACITY_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.BYTE);
 | |
| 		private static final EntityDataAccessor<Byte> DATA_STYLE_FLAGS_ID = SynchedEntityData.defineId(Display.TextDisplay.class, EntityDataSerializers.BYTE);
 | |
| 		private static final IntSet TEXT_RENDER_STATE_IDS = IntSet.of(
 | |
| 			DATA_TEXT_ID.id(), DATA_LINE_WIDTH_ID.id(), DATA_BACKGROUND_COLOR_ID.id(), DATA_TEXT_OPACITY_ID.id(), DATA_STYLE_FLAGS_ID.id()
 | |
| 		);
 | |
| 		@Nullable
 | |
| 		private Display.TextDisplay.CachedInfo clientDisplayCache;
 | |
| 		@Nullable
 | |
| 		private Display.TextDisplay.TextRenderState textRenderState;
 | |
| 
 | |
| 		public TextDisplay(EntityType<?> entityType, Level level) {
 | |
| 			super(entityType, level);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void defineSynchedData(SynchedEntityData.Builder builder) {
 | |
| 			super.defineSynchedData(builder);
 | |
| 			builder.define(DATA_TEXT_ID, Component.empty());
 | |
| 			builder.define(DATA_LINE_WIDTH_ID, 200);
 | |
| 			builder.define(DATA_BACKGROUND_COLOR_ID, 1073741824);
 | |
| 			builder.define(DATA_TEXT_OPACITY_ID, (byte)-1);
 | |
| 			builder.define(DATA_STYLE_FLAGS_ID, (byte)0);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		public void onSyncedDataUpdated(EntityDataAccessor<?> dataAccessor) {
 | |
| 			super.onSyncedDataUpdated(dataAccessor);
 | |
| 			if (TEXT_RENDER_STATE_IDS.contains(dataAccessor.id())) {
 | |
| 				this.updateRenderState = true;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private Component getText() {
 | |
| 			return this.entityData.get(DATA_TEXT_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setText(Component text) {
 | |
| 			this.entityData.set(DATA_TEXT_ID, text);
 | |
| 		}
 | |
| 
 | |
| 		private int getLineWidth() {
 | |
| 			return this.entityData.get(DATA_LINE_WIDTH_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setLineWidth(int lineWidth) {
 | |
| 			this.entityData.set(DATA_LINE_WIDTH_ID, lineWidth);
 | |
| 		}
 | |
| 
 | |
| 		private byte getTextOpacity() {
 | |
| 			return this.entityData.get(DATA_TEXT_OPACITY_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setTextOpacity(byte textOpacity) {
 | |
| 			this.entityData.set(DATA_TEXT_OPACITY_ID, textOpacity);
 | |
| 		}
 | |
| 
 | |
| 		private int getBackgroundColor() {
 | |
| 			return this.entityData.get(DATA_BACKGROUND_COLOR_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setBackgroundColor(int backgroundColor) {
 | |
| 			this.entityData.set(DATA_BACKGROUND_COLOR_ID, backgroundColor);
 | |
| 		}
 | |
| 
 | |
| 		private byte getFlags() {
 | |
| 			return this.entityData.get(DATA_STYLE_FLAGS_ID);
 | |
| 		}
 | |
| 
 | |
| 		private void setFlags(byte flags) {
 | |
| 			this.entityData.set(DATA_STYLE_FLAGS_ID, flags);
 | |
| 		}
 | |
| 
 | |
| 		private static byte loadFlag(byte flags, ValueInput input, String key, byte mask) {
 | |
| 			return input.getBooleanOr(key, false) ? (byte)(flags | mask) : flags;
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void readAdditionalSaveData(ValueInput input) {
 | |
| 			super.readAdditionalSaveData(input);
 | |
| 			this.setLineWidth(input.getIntOr("line_width", 200));
 | |
| 			this.setTextOpacity(input.getByteOr("text_opacity", (byte)-1));
 | |
| 			this.setBackgroundColor(input.getIntOr("background", 1073741824));
 | |
| 			byte b = loadFlag((byte)0, input, "shadow", (byte)1);
 | |
| 			b = loadFlag(b, input, "see_through", (byte)2);
 | |
| 			b = loadFlag(b, input, "default_background", (byte)4);
 | |
| 			Optional<Display.TextDisplay.Align> optional = input.read("alignment", Display.TextDisplay.Align.CODEC);
 | |
| 			if (optional.isPresent()) {
 | |
| 				b = switch ((Display.TextDisplay.Align)optional.get()) {
 | |
| 					case CENTER -> b;
 | |
| 					case LEFT -> (byte)(b | 8);
 | |
| 					case RIGHT -> (byte)(b | 16);
 | |
| 				};
 | |
| 			}
 | |
| 
 | |
| 			this.setFlags(b);
 | |
| 			Optional<Component> optional2 = input.read("text", ComponentSerialization.CODEC);
 | |
| 			if (optional2.isPresent()) {
 | |
| 				try {
 | |
| 					if (this.level() instanceof ServerLevel serverLevel) {
 | |
| 						CommandSourceStack commandSourceStack = this.createCommandSourceStackForNameResolution(serverLevel).withPermission(2);
 | |
| 						Component component = ComponentUtils.updateForEntity(commandSourceStack, (Component)optional2.get(), this, 0);
 | |
| 						this.setText(component);
 | |
| 					} else {
 | |
| 						this.setText(Component.empty());
 | |
| 					}
 | |
| 				} catch (Exception var8) {
 | |
| 					Display.LOGGER.warn("Failed to parse display entity text {}", optional2, var8);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		private static void storeFlag(byte flags, ValueOutput output, String key, byte name) {
 | |
| 			output.putBoolean(key, (flags & name) != 0);
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void addAdditionalSaveData(ValueOutput output) {
 | |
| 			super.addAdditionalSaveData(output);
 | |
| 			output.store("text", ComponentSerialization.CODEC, this.getText());
 | |
| 			output.putInt("line_width", this.getLineWidth());
 | |
| 			output.putInt("background", this.getBackgroundColor());
 | |
| 			output.putByte("text_opacity", this.getTextOpacity());
 | |
| 			byte b = this.getFlags();
 | |
| 			storeFlag(b, output, "shadow", (byte)1);
 | |
| 			storeFlag(b, output, "see_through", (byte)2);
 | |
| 			storeFlag(b, output, "default_background", (byte)4);
 | |
| 			output.store("alignment", Display.TextDisplay.Align.CODEC, getAlign(b));
 | |
| 		}
 | |
| 
 | |
| 		@Override
 | |
| 		protected void updateRenderSubState(boolean interpolate, float partialTick) {
 | |
| 			if (interpolate && this.textRenderState != null) {
 | |
| 				this.textRenderState = this.createInterpolatedTextRenderState(this.textRenderState, partialTick);
 | |
| 			} else {
 | |
| 				this.textRenderState = this.createFreshTextRenderState();
 | |
| 			}
 | |
| 
 | |
| 			this.clientDisplayCache = null;
 | |
| 		}
 | |
| 
 | |
| 		@Nullable
 | |
| 		public Display.TextDisplay.TextRenderState textRenderState() {
 | |
| 			return this.textRenderState;
 | |
| 		}
 | |
| 
 | |
| 		private Display.TextDisplay.TextRenderState createFreshTextRenderState() {
 | |
| 			return new Display.TextDisplay.TextRenderState(
 | |
| 				this.getText(),
 | |
| 				this.getLineWidth(),
 | |
| 				Display.IntInterpolator.constant(this.getTextOpacity()),
 | |
| 				Display.IntInterpolator.constant(this.getBackgroundColor()),
 | |
| 				this.getFlags()
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		private Display.TextDisplay.TextRenderState createInterpolatedTextRenderState(Display.TextDisplay.TextRenderState renderState, float partialTick) {
 | |
| 			int i = renderState.backgroundColor.get(partialTick);
 | |
| 			int j = renderState.textOpacity.get(partialTick);
 | |
| 			return new Display.TextDisplay.TextRenderState(
 | |
| 				this.getText(),
 | |
| 				this.getLineWidth(),
 | |
| 				new Display.LinearIntInterpolator(j, this.getTextOpacity()),
 | |
| 				new Display.ColorInterpolator(i, this.getBackgroundColor()),
 | |
| 				this.getFlags()
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		public Display.TextDisplay.CachedInfo cacheDisplay(Display.TextDisplay.LineSplitter splitter) {
 | |
| 			if (this.clientDisplayCache == null) {
 | |
| 				if (this.textRenderState != null) {
 | |
| 					this.clientDisplayCache = splitter.split(this.textRenderState.text(), this.textRenderState.lineWidth());
 | |
| 				} else {
 | |
| 					this.clientDisplayCache = new Display.TextDisplay.CachedInfo(List.of(), 0);
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			return this.clientDisplayCache;
 | |
| 		}
 | |
| 
 | |
| 		public static Display.TextDisplay.Align getAlign(byte flags) {
 | |
| 			if ((flags & 8) != 0) {
 | |
| 				return Display.TextDisplay.Align.LEFT;
 | |
| 			} else {
 | |
| 				return (flags & 16) != 0 ? Display.TextDisplay.Align.RIGHT : Display.TextDisplay.Align.CENTER;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public static enum Align implements StringRepresentable {
 | |
| 			CENTER("center"),
 | |
| 			LEFT("left"),
 | |
| 			RIGHT("right");
 | |
| 
 | |
| 			public static final Codec<Display.TextDisplay.Align> CODEC = StringRepresentable.fromEnum(Display.TextDisplay.Align::values);
 | |
| 			private final String name;
 | |
| 
 | |
| 			private Align(final String name) {
 | |
| 				this.name = name;
 | |
| 			}
 | |
| 
 | |
| 			@Override
 | |
| 			public String getSerializedName() {
 | |
| 				return this.name;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		public record CachedInfo(List<Display.TextDisplay.CachedLine> lines, int width) {
 | |
| 		}
 | |
| 
 | |
| 		public record CachedLine(FormattedCharSequence contents, int width) {
 | |
| 		}
 | |
| 
 | |
| 		@FunctionalInterface
 | |
| 		public interface LineSplitter {
 | |
| 			Display.TextDisplay.CachedInfo split(Component component, int i);
 | |
| 		}
 | |
| 
 | |
| 		public record TextRenderState(Component text, int lineWidth, Display.IntInterpolator textOpacity, Display.IntInterpolator backgroundColor, byte flags) {
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	record TransformationInterpolator(Transformation previous, Transformation current) implements Display.GenericInterpolator<Transformation> {
 | |
| 		public Transformation get(float f) {
 | |
| 			return f >= 1.0 ? this.current : this.previous.slerp(this.current, f);
 | |
| 		}
 | |
| 	}
 | |
| }
 |