Merge pull request 'Keep hats and cloaks on the posed model, and fix resources on 1.21.4 and 1.21.5' (#41) from cosmetics-follow-emotes into master

Reviewed-on: #41
This commit was merged in pull request #41.
This commit is contained in:
2026-09-28 21:01:06 +00:00
4 changed files with 60 additions and 14 deletions
@@ -4,15 +4,20 @@ import java.util.Arrays;
import org.joml.Matrix3f; import org.joml.Matrix3f;
import org.joml.Matrix4f; import org.joml.Matrix4f;
import org.joml.Quaternionf;
import org.joml.Vector3f; import org.joml.Vector3f;
import org.joml.Vector4f; import org.joml.Vector4f;
import org.saturnclient.client.player.SaturnPlayer; import org.saturnclient.client.player.SaturnPlayer;
import org.saturnclient.common.ref.asset.IdentifierRef; import org.saturnclient.common.ref.asset.IdentifierRef;
import org.saturnclient.config.Config; import org.saturnclient.config.Config;
import org.saturnclient.cosmetics.Cloaks; import org.saturnclient.cosmetics.Cloaks;
import org.saturnclient.emotes.core.bend.LimbBend;
import org.saturnclient.emotes.core.bend.Vec3;
import org.saturnclient.emotes.fabric.access.BendablePart;
import org.saturnclient.impl.cosmetics.utils.ShaderUtils; import org.saturnclient.impl.cosmetics.utils.ShaderUtils;
import org.saturnclient.saturnclient.SaturnRenderState; import org.saturnclient.saturnclient.SaturnRenderState;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.OverlayTexture; import net.minecraft.client.render.OverlayTexture;
import net.minecraft.client.render.VertexConsumer; import net.minecraft.client.render.VertexConsumer;
//? if >=1.21.9 { //? if >=1.21.9 {
@@ -33,7 +38,6 @@ import net.minecraft.item.ItemStack;
import net.minecraft.item.equipment.EquipmentAsset; import net.minecraft.item.equipment.EquipmentAsset;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.RotationAxis;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
/** /**
@@ -383,6 +387,25 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
} }
} }
/**
* An emote that bends the torso leans the chest from the hips, so the cloak hangs from where the
* top of the back ends up, turned as much as the torso is there.
*/
private static void followBend(MatrixStack matrices, ModelPart body) {
LimbBend bend = ((BendablePart) (Object) body).saturnEmotes$getBend();
if (bend == null || bend.isStraight()) {
return;
}
// The top of the torso, in the body's own pixels
float[] top = new float[3];
bend.bendPoint(0, 0, 0, top);
matrices.translate(top[0] / 16.0f, top[1] / 16.0f, top[2] / 16.0f);
Vec3 axis = bend.axis();
matrices.multiply(new Quaternionf().rotationAxis(bend.angleAt(0), axis.x(), axis.y(), axis.z()));
}
// Shift array left and insert new value at the start // Shift array left and insert new value at the start
private void updateSegmentValues(float value) { private void updateSegmentValues(float value) {
// Shift all elements one position to the right (from end to start) // Shift all elements one position to the right (from end to start)
@@ -436,17 +459,24 @@ public class CloakFeatureRenderer extends FeatureRenderer<PlayerEntityRenderStat
matrices.push(); matrices.push();
// On the back: the whole player (which emotes like the backflip turn), then the body's position
// and turn (which crouching and emotes move), then the chest's lean when an emote bends the torso
PlayerEntityModel model = this.getContextModel();
//? if >=1.21.5 {
model.getRootPart().applyTransform(matrices);
model.body.applyTransform(matrices);
//?} else {
/*model.getRootPart().rotate(matrices);
model.body.rotate(matrices);
*///?}
followBend(matrices, model.body);
matrices.translate(0.0f, 0.0f, 0.12f); matrices.translate(0.0f, 0.0f, 0.12f);
if (this.hasCustomModelForLayer(state.equippedChestStack, LayerType.HUMANOID)) { if (this.hasCustomModelForLayer(state.equippedChestStack, LayerType.HUMANOID)) {
matrices.translate(0.0F, -0.053125F, 0.06875F); matrices.translate(0.0F, -0.053125F, 0.06875F);
} }
if (state.isInSneakingPose) {
matrices.translate(0, 0.16f, 0.0f);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(29.0f));
}
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (now - lastUpdate >= 20) { if (now - lastUpdate >= 20) {
float velX = Math.min(0.8f, state.field_53537 / 108.0f); float velX = Math.min(0.8f, state.field_53537 / 108.0f);
@@ -1,6 +1,5 @@
package org.saturnclient.impl.cosmetics; package org.saturnclient.impl.cosmetics;
import org.joml.Quaternionf;
import org.saturnclient.client.player.SaturnPlayer; import org.saturnclient.client.player.SaturnPlayer;
import org.saturnclient.impl.cosmetics.obj.MtlLoader; import org.saturnclient.impl.cosmetics.obj.MtlLoader;
import org.saturnclient.impl.cosmetics.obj.ObjModel; import org.saturnclient.impl.cosmetics.obj.ObjModel;
@@ -16,7 +15,6 @@ import net.minecraft.client.render.entity.feature.FeatureRendererContext;
import net.minecraft.client.render.entity.model.PlayerEntityModel; import net.minecraft.client.render.entity.model.PlayerEntityModel;
import net.minecraft.client.render.entity.state.PlayerEntityRenderState; import net.minecraft.client.render.entity.state.PlayerEntityRenderState;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.client.model.ModelPart;
public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> { public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState, PlayerEntityModel> {
public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) { public HatFeatureRenderer(FeatureRendererContext<PlayerEntityRenderState, PlayerEntityModel> context) {
@@ -41,11 +39,16 @@ public class HatFeatureRenderer extends FeatureRenderer<PlayerEntityRenderState,
matrices.push(); matrices.push();
// On the head, as vanilla places head items: the whole player (which emotes like the backflip
// turn), then the head's position, turn and scale (which crouching and emotes move)
PlayerEntityModel model = this.getContextModel();
//? if >=1.21.5 { //? if >=1.21.5 {
ModelPart head = this.getContextModel().head; model.getRootPart().applyTransform(matrices);
matrices.multiply(new Quaternionf().rotationZYX(head.roll, head.yaw, head.pitch)); model.head.applyTransform(matrices);
//?} else //?} else {
//this.getContextModel().head.rotate(matrices); /*model.getRootPart().rotate(matrices);
model.head.rotate(matrices);
*///?}
ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat), ObjModel.cosmetic("hat", player.hat).render(MtlLoader.cosmetic(player.hat),
matrices, output, light, matrices, output, light,
@@ -48,6 +48,9 @@ public final class GlassRenderer {
.withLocation(Identifier.of("saturnclient", "pipeline/glass")) .withLocation(Identifier.of("saturnclient", "pipeline/glass"))
.withFragmentShader(Identifier.of("saturnclient", "core/glass")) .withFragmentShader(Identifier.of("saturnclient", "core/glass"))
.withSampler("Sampler1") .withSampler("Sampler1")
// The transforms block ends with LineWidth before 1.21.11 (see glass.fsh).
//? if <1.21.11
//.withShaderDefine("HAS_LINE_WIDTH")
.build(); .build();
private static final Identifier BLUR = Identifier.ofVanilla("post_effect/blur.json"); private static final Identifier BLUR = Identifier.ofVanilla("post_effect/blur.json");
@@ -3,8 +3,18 @@
// Saturn's glass: the blurred game behind the screen, cut to a panel's shape. For 1.21.6 and // Saturn's glass: the blurred game behind the screen, cut to a panel's shape. For 1.21.6 and
// later; glass_pre_1_21_6.fsh (with glass.json, the program 1.21.4 loads) is for older versions. // later; glass_pre_1_21_6.fsh (with glass.json, the program 1.21.4 loads) is for older versions.
// Vanilla's own, since its layout changes between versions (1.21.11 dropped LineWidth) // Vanilla's transforms, laid out as the version has them: 1.21.6 to 1.21.10 end with LineWidth, which
#moj_import <minecraft:dynamictransforms.glsl> // 1.21.11 dropped (GlassRenderer defines HAS_LINE_WIDTH there). Not imported: the include only exists
// from 1.21.6, and 1.21.4 and 1.21.5 still read every shader's imports while loading resources.
layout(std140) uniform DynamicTransforms {
mat4 ModelViewMat;
vec4 ColorModulator;
vec3 ModelOffset;
mat4 TextureMat;
#ifdef HAS_LINE_WIDTH
float LineWidth;
#endif
};
// The panel's rounded rectangle, the same texture its background is drawn with // The panel's rounded rectangle, the same texture its background is drawn with
uniform sampler2D Sampler0; uniform sampler2D Sampler0;