feat: Highlight century cake slice players

This commit is contained in:
Linnea Gräf
2025-02-02 00:08:18 +01:00
parent c2aefe09ab
commit 89bceb6735
18 changed files with 559 additions and 3 deletions

View File

@@ -0,0 +1,62 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.state.LivingEntityRenderState;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Applies various rendering modifications from {@link EntityRenderTintEvent}
*/
@Mixin(LivingEntityRenderer.class)
public class ChangeColorOfLivingEntities<T extends LivingEntity, S extends LivingEntityRenderState, M extends EntityModel<? super S>> {
@ModifyReturnValue(method = "getMixColor", at = @At("RETURN"))
private int changeColor(int original, @Local(argsOnly = true) S state) {
var tintState = EntityRenderTintEvent.HasTintRenderState.cast(state);
if (tintState.getHasTintOverride_firmament())
return tintState.getTint_firmament();
return original;
}
@ModifyArg(
method = "getOverlay",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/OverlayTexture;getU(F)I"),
allow = 1
)
private static float modifyLightOverlay(float originalWhiteOffset, @Local(argsOnly = true) LivingEntityRenderState state) {
var tintState = EntityRenderTintEvent.HasTintRenderState.cast(state);
if (tintState.getHasTintOverride_firmament() || tintState.getOverlayTexture_firmament() != null) {
return 1F; // TODO: add interpolation percentage to render state extension
}
return originalWhiteOffset;
}
@Inject(method = "render(Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;pop()V"))
private void afterRender(S livingEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) {
var tintState = EntityRenderTintEvent.HasTintRenderState.cast(livingEntityRenderState);
var overlayTexture = tintState.getOverlayTexture_firmament();
if (overlayTexture != null && vertexConsumerProvider instanceof VertexConsumerProvider.Immediate imm) {
imm.drawCurrentLayer();
}
EntityRenderTintEvent.overlayOverride = null;
}
@Inject(method = "render(Lnet/minecraft/client/render/entity/state/LivingEntityRenderState;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/util/math/MatrixStack;push()V"))
private void beforeRender(S livingEntityRenderState, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, CallbackInfo ci) {
var tintState = EntityRenderTintEvent.HasTintRenderState.cast(livingEntityRenderState);
var overlayTexture = tintState.getOverlayTexture_firmament();
if (overlayTexture != null) {
EntityRenderTintEvent.overlayOverride = overlayTexture;
}
}
}

View File

@@ -0,0 +1,55 @@
package moe.nea.firmament.mixins.render.entitytints;
import moe.nea.firmament.events.EntityRenderTintEvent;
import moe.nea.firmament.util.render.TintedOverlayTexture;
import net.minecraft.client.render.entity.state.EntityRenderState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@Mixin(EntityRenderState.class)
public class EntityRenderStateTint implements EntityRenderTintEvent.HasTintRenderState {
@Unique
int tint = -1;
@Unique
TintedOverlayTexture overlayTexture;
@Unique
boolean hasTintOverride = false;
@Override
public int getTint_firmament() {
return tint;
}
@Override
public void setTint_firmament(int i) {
tint = i;
hasTintOverride = true;
}
@Override
public boolean getHasTintOverride_firmament() {
return hasTintOverride;
}
@Override
public void setHasTintOverride_firmament(boolean b) {
hasTintOverride = b;
}
@Override
public void reset_firmament() {
hasTintOverride = false;
overlayTexture = null;
}
@Override
public @Nullable TintedOverlayTexture getOverlayTexture_firmament() {
return overlayTexture;
}
@Override
public void setOverlayTexture_firmament(@Nullable TintedOverlayTexture tintedOverlayTexture) {
this.overlayTexture = tintedOverlayTexture;
}
}

View File

@@ -0,0 +1,30 @@
package moe.nea.firmament.mixins.render.entitytints;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.state.EntityRenderState;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* Dispatches {@link EntityRenderTintEvent} to collect additional render state used by {@link ChangeColorOfLivingEntities}
*/
@Mixin(EntityRenderer.class)
public class InjectIntoRenderState<T extends Entity, S extends EntityRenderState> {
@Inject(
method = "updateRenderState",
at = @At("RETURN"))
private void onUpdateRenderState(T entity, S state, float tickDelta, CallbackInfo ci) {
var renderState = EntityRenderTintEvent.HasTintRenderState.cast(state);
renderState.reset_firmament();
var tintEvent = new EntityRenderTintEvent(
entity,
renderState
);
EntityRenderTintEvent.Companion.publish(tintEvent);
}
}

View File

@@ -0,0 +1,24 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
/**
* Replaces the overlay texture used by rendering with the override specified in {@link EntityRenderTintEvent#overlayOverride}
*/
@Mixin(RenderLayer.Overlay.class)
public class ReplaceOverlayTexture {
@ModifyExpressionValue(
method = {"method_23555", "method_23556"},
expect = 2,
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/GameRenderer;getOverlayTexture()Lnet/minecraft/client/render/OverlayTexture;"))
private static OverlayTexture replaceOverlayTexture(OverlayTexture original) {
if (EntityRenderTintEvent.overlayOverride != null)
return EntityRenderTintEvent.overlayOverride;
return original;
}
}

View File

@@ -0,0 +1,34 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.entity.equipment.EquipmentRenderer;
import net.minecraft.util.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
/**
* Patch to make {@link EquipmentRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified.
*/
@Mixin(EquipmentRenderer.class)
public class UseOverlayableEquipmentRenderer {
@WrapOperation(method = "render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/RenderLayer;getArmorCutoutNoCull(Lnet/minecraft/util/Identifier;)Lnet/minecraft/client/render/RenderLayer;"))
private RenderLayer replace(Identifier texture, Operation<RenderLayer> original) {
if (EntityRenderTintEvent.overlayOverride != null)
return RenderLayer.getEntityTranslucent(texture);
return original.call(texture);
}
@ModifyExpressionValue(method = "render(Lnet/minecraft/client/render/entity/equipment/EquipmentModel$LayerType;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/client/model/Model;Lnet/minecraft/item/ItemStack;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/util/Identifier;)V",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I"))
private int replaceUvIndex(int original) {
if (EntityRenderTintEvent.overlayOverride != null)
return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride
return original;
}
}

View File

@@ -0,0 +1,25 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.entity.feature.HeadFeatureRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
/**
* Patch to make {@link HeadFeatureRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified.
* @see UseOverlayableItemRenderer
*/
@Mixin(HeadFeatureRenderer.class)
public class UseOverlayableHeadFeatureRenderer {
@ModifyExpressionValue(method = "render(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;ILnet/minecraft/client/render/entity/state/LivingEntityRenderState;FF)V",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I"))
private int replaceUvIndex(int original) {
if (EntityRenderTintEvent.overlayOverride != null)
return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride
return original;
}
}

View File

@@ -0,0 +1,25 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.RenderPhase;
import net.minecraft.client.render.item.ItemRenderState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
/**
* Patch to make {@link ItemRenderState} use a {@link RenderLayer} that allows uses Minecraft's overlay texture.
*
* @see UseOverlayableHeadFeatureRenderer
*/
@Mixin(ItemRenderState.LayerRenderState.class)
public class UseOverlayableItemRenderer {
@ModifyExpressionValue(method = "render", at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/item/ItemRenderState$LayerRenderState;renderLayer:Lnet/minecraft/client/render/RenderLayer;"))
private RenderLayer replace(RenderLayer original) {
if (EntityRenderTintEvent.overlayOverride != null && original instanceof RenderLayer.MultiPhase multiPhase && multiPhase.phases.texture instanceof RenderPhase.Texture texture && texture.getId().isPresent())
return RenderLayer.getEntityTranslucent(texture.getId().get());
return original;
}
}

View File

@@ -0,0 +1,25 @@
package moe.nea.firmament.mixins.render.entitytints;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import moe.nea.firmament.events.EntityRenderTintEvent;
import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.RenderLayer;
import net.minecraft.client.render.block.entity.SkullBlockEntityRenderer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
/**
* Patch to make {@link SkullBlockEntityRenderer} use a {@link RenderLayer} that allows uses Minecraft's overlay texture, if a {@link EntityRenderTintEvent#overlayOverride} is specified.
*/
@Mixin(SkullBlockEntityRenderer.class)
public class UseOverlayableSkullBlockEntityRenderer {
@ModifyExpressionValue(method = "renderSkull",
at = @At(value = "FIELD", target = "Lnet/minecraft/client/render/OverlayTexture;DEFAULT_UV:I"))
private static int replaceUvIndex(int original) {
if (EntityRenderTintEvent.overlayOverride != null)
return OverlayTexture.packUv(15, 10); // TODO: store this info in a global alongside overlayOverride
return original;
}
}