mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-23 13:37:58 +01:00
Properly render both arms in first person when holding an entity
This commit is contained in:
parent
015d3b29fa
commit
44802abf1b
7 changed files with 152 additions and 14 deletions
|
@ -0,0 +1,32 @@
|
|||
package com.minelittlepony.unicopia.client;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.minelittlepony.unicopia.client.render.AccessoryFeatureRenderer;
|
||||
import com.minelittlepony.unicopia.entity.player.Pony;
|
||||
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.item.HeldItemRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.Arm;
|
||||
|
||||
public class FirstPersonRendererOverrides {
|
||||
public static final FirstPersonRendererOverrides INSTANCE = new FirstPersonRendererOverrides();
|
||||
|
||||
public Optional<HeldItemRenderer.HandRenderType> getHandRenderType(PlayerEntity player) {
|
||||
return Pony.of(player).getEntityInArms().map(e -> HeldItemRenderer.HandRenderType.RENDER_BOTH_HANDS);
|
||||
}
|
||||
|
||||
public boolean beforeRenderHands(ArmRenderer sender, float tickDelta, MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, ClientPlayerEntity player, int light) {
|
||||
var root = AccessoryFeatureRenderer.FeatureRoot.of(player);
|
||||
return root != null && root.getAccessories().beforeRenderArms(sender, tickDelta, matrices, vertexConsumers, player, light);
|
||||
}
|
||||
|
||||
public interface ArmRenderer {
|
||||
void invokeRenderArmHoldingItem(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, float swingProgress, Arm arm);
|
||||
|
||||
float getEquipProgress(float tickDelta);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,14 @@
|
|||
package com.minelittlepony.unicopia.client.render;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import com.minelittlepony.unicopia.client.FirstPersonRendererOverrides.ArmRenderer;
|
||||
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.model.ModelPart;
|
||||
import net.minecraft.client.render.VertexConsumer;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRenderer;
|
||||
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
|
||||
|
@ -39,6 +44,14 @@ public class AccessoryFeatureRenderer<
|
|||
features.forEach(feature -> feature.renderArm(matrices, vertexConsumers, light, entity, arm, side));
|
||||
}
|
||||
|
||||
public boolean beforeRenderArms(ArmRenderer sender, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, T entity, int light) {
|
||||
boolean cancelled = false;
|
||||
for (var feature : features) {
|
||||
cancelled |= feature.beforeRenderArms(sender, tickDelta, matrices, vertexConsumers, entity, light);
|
||||
}
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public interface FeatureFactory<T extends LivingEntity> {
|
||||
Feature<T> create(FeatureRendererContext<T, ? extends BipedEntityModel<T>> context);
|
||||
}
|
||||
|
@ -46,7 +59,10 @@ public class AccessoryFeatureRenderer<
|
|||
public interface Feature<T extends LivingEntity> {
|
||||
void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch);
|
||||
|
||||
default void renderArm(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, ModelPart arm, Arm side) {
|
||||
default void renderArm(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, T entity, ModelPart arm, Arm side) {}
|
||||
|
||||
default boolean beforeRenderArms(ArmRenderer sender, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, T entity, int light) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,5 +70,14 @@ public class AccessoryFeatureRenderer<
|
|||
T extends LivingEntity,
|
||||
M extends BipedEntityModel<T>> {
|
||||
AccessoryFeatureRenderer<T, M> getAccessories();
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
static <T extends LivingEntity, M extends BipedEntityModel<T>> FeatureRoot<T, M> of(T entity) {
|
||||
var renderer = MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity);
|
||||
if (renderer instanceof FeatureRoot) {
|
||||
return (FeatureRoot<T, M>)renderer;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.minelittlepony.unicopia.client.render;
|
||||
|
||||
import com.minelittlepony.unicopia.client.FirstPersonRendererOverrides.ArmRenderer;
|
||||
import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate;
|
||||
import com.minelittlepony.unicopia.entity.Living;
|
||||
import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
||||
|
@ -20,7 +21,10 @@ import net.minecraft.util.math.*;
|
|||
|
||||
public class HeldEntityFeatureRenderer<E extends LivingEntity> implements AccessoryFeatureRenderer.Feature<E> {
|
||||
|
||||
private final FeatureRendererContext<E, ? extends BipedEntityModel<E>> context;
|
||||
|
||||
public HeldEntityFeatureRenderer(FeatureRendererContext<E, ? extends BipedEntityModel<E>> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -47,23 +51,37 @@ public class HeldEntityFeatureRenderer<E extends LivingEntity> implements Access
|
|||
|
||||
@Override
|
||||
public void renderArm(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, E entity, ModelPart arm, Arm side) {
|
||||
Pony.of(entity).flatMap(Pony::getEntityInArms).ifPresent(passenger -> {
|
||||
float tickDelta = MinecraftClient.getInstance().getTickDelta();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean beforeRenderArms(ArmRenderer sender, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, E entity, int light) {
|
||||
return Pony.of(entity).flatMap(Pony::getEntityInArms).filter(passenger -> {
|
||||
float swingProgress = entity.getHandSwingProgress(MinecraftClient.getInstance().getTickDelta());
|
||||
float f = -0.4f * MathHelper.sin(MathHelper.sqrt(swingProgress) * (float)Math.PI);
|
||||
float g = 0.2f * MathHelper.sin(MathHelper.sqrt(swingProgress) * ((float)Math.PI * 2));
|
||||
float h = -0.2f * MathHelper.sin(swingProgress * (float)Math.PI);
|
||||
matrices.push();
|
||||
matrices.translate(0.8F, 0.4F, -0.1F);
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90));
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-60 - 13));
|
||||
matrices.multiply(RotationAxis.POSITIVE_Z.rotationDegrees(-30));
|
||||
matrices.translate(0, 0, -0.2F);
|
||||
matrices.translate(f, g, h);
|
||||
matrices.translate(0, -1.3F, -1.3F);
|
||||
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(13));
|
||||
if (!(passenger instanceof Pony)) {
|
||||
matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90));
|
||||
}
|
||||
matrices.translate(-passenger.asEntity().getWidth() / 16F, 0.3F, 0);
|
||||
|
||||
renderCarriedEntity(passenger.asEntity(), matrices, vertexConsumers, light, tickDelta);
|
||||
matrices.pop();
|
||||
});
|
||||
|
||||
float equipProgress = 1 - sender.getEquipProgress(tickDelta);
|
||||
|
||||
matrices.push();
|
||||
sender.invokeRenderArmHoldingItem(matrices, vertexConsumers, light, equipProgress, swingProgress, Arm.LEFT);
|
||||
matrices.pop();
|
||||
matrices.push();
|
||||
sender.invokeRenderArmHoldingItem(matrices, vertexConsumers, light, equipProgress, swingProgress, Arm.RIGHT);
|
||||
matrices.pop();
|
||||
return true;
|
||||
}).isPresent();
|
||||
}
|
||||
|
||||
private void renderCarriedEntity(LivingEntity p, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float tickDelta) {
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package com.minelittlepony.unicopia.mixin.client;
|
||||
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.*;
|
||||
import org.spongepowered.asm.mixin.injection.At.Shift;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import com.minelittlepony.unicopia.client.FirstPersonRendererOverrides;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.render.VertexConsumerProvider;
|
||||
import net.minecraft.client.render.item.HeldItemRenderer;
|
||||
import net.minecraft.client.render.item.HeldItemRenderer.HandRenderType;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.Arm;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
@Mixin(HeldItemRenderer.class)
|
||||
abstract class MixinHeldItemRenderer implements FirstPersonRendererOverrides.ArmRenderer {
|
||||
@Shadow
|
||||
private float equipProgressMainHand;
|
||||
@Shadow
|
||||
private float prevEquipProgressMainHand;
|
||||
|
||||
@Override
|
||||
@Invoker("renderArmHoldingItem")
|
||||
public abstract void invokeRenderArmHoldingItem(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, float equipProgress, float swingProgress, Arm arm);
|
||||
|
||||
@Override
|
||||
public float getEquipProgress(float tickDelta) {
|
||||
return MathHelper.lerp(tickDelta, prevEquipProgressMainHand, equipProgressMainHand);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "getHandRenderType",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private static void onGetHandRenderType(ClientPlayerEntity player, CallbackInfoReturnable<HandRenderType> info) {
|
||||
FirstPersonRendererOverrides.INSTANCE.getHandRenderType(player).ifPresent(info::setReturnValue);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "renderItem(FLnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider$Immediate;Lnet/minecraft/client/network/ClientPlayerEntity;I)V",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
target = "net/minecraft/client/render/item/HeldItemRenderer$HandRenderType.renderMainHand",
|
||||
shift = Shift.BEFORE
|
||||
),
|
||||
cancellable = true)
|
||||
private void onRenderItem(float tickDelta, MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, ClientPlayerEntity player, int light, CallbackInfo info) {
|
||||
if (FirstPersonRendererOverrides.INSTANCE.beforeRenderHands(this, tickDelta, matrices, vertexConsumers, player, light)) {
|
||||
info.cancel();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,14 +21,17 @@ import net.minecraft.client.util.math.MatrixStack;
|
|||
import net.minecraft.util.Arm;
|
||||
|
||||
@Mixin(PlayerEntityRenderer.class)
|
||||
abstract class MixinPlayerEntityRenderer extends LivingEntityRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
|
||||
abstract class MixinPlayerEntityRenderer
|
||||
extends LivingEntityRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>>
|
||||
implements FeatureRoot<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> {
|
||||
@Nullable
|
||||
private AccessoryFeatureRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> accessories;
|
||||
|
||||
MixinPlayerEntityRenderer() { super(null, null, 0); }
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
private AccessoryFeatureRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> getAccessories() {
|
||||
public AccessoryFeatureRenderer<AbstractClientPlayerEntity, PlayerEntityModel<AbstractClientPlayerEntity>> getAccessories() {
|
||||
if (accessories == null) {
|
||||
accessories = features.stream()
|
||||
.filter(a -> a instanceof FeatureRoot)
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
accessWidener v1 named
|
||||
accessible class net/minecraft/client/render/RenderLayer$MultiPhaseParameters
|
||||
accessible method net/minecraft/client/render/RenderLayer of (Ljava/lang/String;Lnet/minecraft/client/render/VertexFormat;Lnet/minecraft/client/render/VertexFormat$DrawMode;IZZLnet/minecraft/client/render/RenderLayer$MultiPhaseParameters;)Lnet/minecraft/client/render/RenderLayer$MultiPhase;
|
||||
accessible class net/minecraft/client/render/item/HeldItemRenderer$HandRenderType
|
|
@ -47,6 +47,7 @@
|
|||
"client.MixinCamera",
|
||||
"client.MixinEntityRenderDispatcher",
|
||||
"client.MixinGameRenderer",
|
||||
"client.MixinHeldItemRenderer",
|
||||
"client.MixinInGameHud",
|
||||
"client.MixinInGameHud$HeartType",
|
||||
"client.MixinItem",
|
||||
|
|
Loading…
Reference in a new issue