From 7ca2e63faebb9376c5bce3242f3b0ff6514efc9a Mon Sep 17 00:00:00 2001 From: Sollace Date: Sun, 25 Dec 2022 19:36:43 +0100 Subject: [PATCH] Set position and render entities being carried by pegasi in their arms arms --- .../unicopia/ability/CarryAbility.java | 1 + .../unicopia/client/URenderers.java | 1 + .../client/minelittlepony/HeldEntityGear.java | 69 ++++++++++++ .../unicopia/client/minelittlepony/Main.java | 2 + .../render/AccessoryFeatureRenderer.java | 1 - .../render/HeldEntityFeatureRenderer.java | 104 ++++++++++++++++++ .../unicopia/client/render/PlayerPoser.java | 16 +++ .../client/render/WorldRenderDelegate.java | 4 + .../unicopia/entity/Living.java | 32 +++++- .../unicopia/entity/duck/EntityDuck.java | 3 + .../unicopia/entity/player/Pony.java | 24 ++++ .../unicopia/mixin/MixinEntity.java | 17 +++ 12 files changed, 272 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/minelittlepony/unicopia/client/minelittlepony/HeldEntityGear.java create mode 100644 src/main/java/com/minelittlepony/unicopia/client/render/HeldEntityFeatureRenderer.java diff --git a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java index 14f5e74a..f567f378 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java @@ -73,6 +73,7 @@ public class CarryAbility implements Ability { if (rider != null) { rider.startRiding(player, true); + Living.getOrEmpty(rider).ifPresent(living -> living.setCarrier(player)); } Living.transmitPassengers(player); diff --git a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java index 3e108f08..a43009db 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/URenderers.java +++ b/src/main/java/com/minelittlepony/unicopia/client/URenderers.java @@ -64,6 +64,7 @@ public interface URenderers { AccessoryFeatureRenderer.register(IcarusWingsFeatureRenderer::new); AccessoryFeatureRenderer.register(BatWingsFeatureRenderer::new); AccessoryFeatureRenderer.register(GlassesFeatureRenderer::new); + AccessoryFeatureRenderer.register(HeldEntityFeatureRenderer::new); EntityRendererRegistry.register(UEntities.THROWN_ITEM, FlyingItemEntityRenderer::new); EntityRendererRegistry.register(UEntities.MUFFIN, FlyingItemEntityRenderer::new); diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/HeldEntityGear.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/HeldEntityGear.java new file mode 100644 index 00000000..68fb5d01 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/HeldEntityGear.java @@ -0,0 +1,69 @@ +package com.minelittlepony.unicopia.client.minelittlepony; + +import java.util.UUID; + +import com.minelittlepony.api.model.BodyPart; +import com.minelittlepony.api.model.IModel; +import com.minelittlepony.api.model.gear.IGear; +import com.minelittlepony.client.model.IPonyModel; +import com.minelittlepony.unicopia.client.render.HeldEntityFeatureRenderer; +import com.minelittlepony.unicopia.entity.Living; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Vec3d; + +class HeldEntityGear extends HeldEntityFeatureRenderer implements IGear { + + private LivingEntity entity; + + public HeldEntityGear() { + super(null); + } + + @Override + public boolean canRender(IModel model, Entity entity) { + return entity instanceof LivingEntity; + } + + @Override + public BodyPart getGearLocation() { + return BodyPart.BODY; + } + + @Override + public Identifier getTexture(T entity, Context context) { + return MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity).getTexture(entity); + } + + @Override + public & IPonyModel> void transform(M model, MatrixStack matrices) { + // noop + } + + @Override + public void pose(IModel model, Entity entity, boolean rainboom, UUID interpolatorId, float move, float swing, float bodySwing, float ticks) { + this.entity = (LivingEntity)entity; + } + + @Override + public void render(MatrixStack stack, VertexConsumer consumer, int light, int overlay, float red, float green, float blue, float alpha, UUID interpolatorId) { + render( + stack, + MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers(), + light, entity, + 0, 0, + MinecraftClient.getInstance().getTickDelta(), 0, 0, 0 + ); + } + + @Override + protected Vec3d getCarryPosition(Living entity, Living passenger) { + return super.getCarryPosition(entity, passenger); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java index c69ccdc9..2ca146f2 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java +++ b/src/main/java/com/minelittlepony/unicopia/client/minelittlepony/Main.java @@ -33,6 +33,7 @@ public class Main extends MineLPDelegate implements ClientModInitializer { PonyModelPrepareCallback.EVENT.register(this::onPonyModelPrepared); IGear.register(() -> new BangleGear(TrinketsDelegate.MAINHAND)); IGear.register(() -> new BangleGear(TrinketsDelegate.OFFHAND)); + IGear.register(() -> new HeldEntityGear()); IGear.register(AmuletGear::new); IGear.register(GlassesGear::new); } @@ -54,6 +55,7 @@ public class Main extends MineLPDelegate implements ClientModInitializer { model.getAttributes().isGoingFast |= zMotion > 0.4F; } model.getAttributes().isGoingFast |= pony.getMotion().isRainbooming(); + model.getAttributes().isGoingFast &= !pony.getEntityInArms().isPresent(); if (pony.getAnimation() == Animation.SPREAD_WINGS) { model.getAttributes().wingAngle = -AnimationUtil.seeSitSaw(pony.getAnimationProgress(1), 1.5F) * (float)Math.PI / 1.2F; diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java index 5ea9d68d..97835764 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/AccessoryFeatureRenderer.java @@ -47,7 +47,6 @@ public class AccessoryFeatureRenderer< 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) { - } } diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/HeldEntityFeatureRenderer.java b/src/main/java/com/minelittlepony/unicopia/client/render/HeldEntityFeatureRenderer.java new file mode 100644 index 00000000..8b9af780 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/client/render/HeldEntityFeatureRenderer.java @@ -0,0 +1,104 @@ +package com.minelittlepony.unicopia.client.render; + +import com.minelittlepony.unicopia.client.minelittlepony.MineLPDelegate; +import com.minelittlepony.unicopia.entity.Living; +import com.minelittlepony.unicopia.entity.duck.EntityDuck; +import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck; +import com.minelittlepony.unicopia.entity.player.Pony; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.EntityRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.BipedEntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Arm; +import net.minecraft.util.math.*; + +public class HeldEntityFeatureRenderer implements AccessoryFeatureRenderer.Feature { + + public HeldEntityFeatureRenderer(FeatureRendererContext> context) { + } + + @Override + public void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, E entity, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + Pony.of(entity).flatMap(Pony::getEntityInArms).ifPresent(passenger -> { + Living l = Living.living(entity); + Vec3d carryPosition = getCarryPosition(l, passenger); + + LivingEntity p = passenger.asEntity(); + + @SuppressWarnings("unchecked") + EntityRenderer renderer = (EntityRenderer)MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(p); + + float f = tickDelta; + + matrices.push(); + + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(180)); + + float leanAmount = ((LivingEntityDuck)entity).getLeaningPitch(); + + //matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(leanAmount * 0)); + matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(-leanAmount * 90)); + + carryPosition = carryPosition.rotateX(-leanAmount * MathHelper.PI / 4F) + .add(new Vec3d(0, -0.5F, 0).multiply(leanAmount)); + + matrices.translate(carryPosition.x, carryPosition.y, carryPosition.z); + if (!(passenger instanceof Pony)) { + matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees(90)); + } + + float oldYaw = entity.bodyYaw; + float prevOldYaw = entity.prevBodyYaw; + + entity.bodyYaw = 0; + entity.prevBodyYaw = 0; + + Entity vehicle = p.getVehicle(); + ((EntityDuck)p).setVehicle(null); + + p.prevBodyYaw = 0; + p.bodyYaw = 0; + p.headYaw = 0; + p.prevHeadYaw = 0; + p.prevYaw = 0; + p.setYaw(0); + p.setBodyYaw(0); + renderer.render(p, 0, f, matrices, vertexConsumers, light); + + entity.bodyYaw = oldYaw; + entity.prevBodyYaw = prevOldYaw; + + ((EntityDuck)p).setVehicle(vehicle); + + matrices.pop(); + }); + } + + @Override + public void renderArm(MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, E entity, ModelPart arm, Arm side) { + render(matrices, vertexConsumers, light, entity, 0, 0, 0, 0, 0, 0); + } + + protected Vec3d getCarryPosition(Living entity, Living passenger) { + float passengerHeight = passenger.asEntity().getHeight() / 2F; + float carrierHeight = entity.asEntity().getHeight() / 5F; + + if (entity instanceof Pony pony && !MineLPDelegate.getInstance().getPlayerPonyRace(pony.asEntity()).isDefault() && pony.getPhysics().isFlying()) { + return new Vec3d(0, + -passenger.asEntity().getHeight() - passengerHeight, + 0 + ); + } + + return new Vec3d(0, + -passengerHeight - carrierHeight, + entity.asEntity().getWidth() + ); + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java index 71ef5708..674c2b2e 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/PlayerPoser.java @@ -188,6 +188,22 @@ public class PlayerPoser { default: } + if (pony.getEntityInArms().isPresent()) { + if (isPony && pony.getPhysics().isFlying()) { + model.leftLeg.pitch = 1; + model.rightLeg.pitch = 1; + model.leftLeg.yaw = 0.3F; + model.rightLeg.yaw = -0.3F; + } else { + model.leftArm.pitch = -1; + model.rightArm.pitch = -1; + } + model.leftArm.yaw = -0.3F; + model.rightArm.yaw = 0.3F; + model.leftArm.roll = 0; + model.rightArm.roll = 0; + } + if (model instanceof PlayerEntityModel m) { m.leftSleeve.copyTransform(m.leftArm); m.rightSleeve.copyTransform(m.rightArm); diff --git a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java index 591553d3..2d13df69 100644 --- a/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java +++ b/src/main/java/com/minelittlepony/unicopia/client/render/WorldRenderDelegate.java @@ -104,6 +104,10 @@ public class WorldRenderDelegate { double x, double y, double z, float yaw, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light) { + if (pony.isBeingCarried() && !(pony instanceof Pony && ((Pony)pony).isClientPlayer())) { + return true; + } + matrices.push(); Entity owner = pony.asEntity(); diff --git a/src/main/java/com/minelittlepony/unicopia/entity/Living.java b/src/main/java/com/minelittlepony/unicopia/entity/Living.java index d336876c..be9127cc 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/Living.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/Living.java @@ -1,6 +1,7 @@ package com.minelittlepony.unicopia.entity; import java.util.Optional; +import java.util.UUID; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -28,7 +29,7 @@ import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.entity.*; import net.minecraft.entity.damage.DamageSource; -import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.*; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.projectile.ProjectileEntity; import net.minecraft.item.ItemStack; @@ -42,6 +43,7 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; public abstract class Living implements Equine, Caster, Transmittable { + private static final TrackedData> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID); protected final T entity; @@ -69,6 +71,7 @@ public abstract class Living implements Equine, Caste this.effectDelegate = new EffectSync(this, effect); entity.getDataTracker().startTracking(effect, new NbtCompound()); + entity.getDataTracker().startTracking(CARRIER_ID, Optional.empty()); } public boolean isInvisible() { @@ -113,6 +116,23 @@ public abstract class Living implements Equine, Caste return entity; } + public Optional getCarrierId() { + return entity.getDataTracker().get(CARRIER_ID); + } + + public void setCarrier(UUID carrier) { + entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier)); + } + + public void setCarrier(Entity carrier) { + entity.getDataTracker().set(CARRIER_ID, Optional.ofNullable(carrier).map(Entity::getUuid)); + } + + public boolean isBeingCarried() { + Entity vehicle = entity.getVehicle(); + return vehicle != null && getCarrierId().filter(vehicle.getUuid()::equals).isPresent(); + } + @Override public void tick() { armour.update(this, getArmourStacks()); @@ -176,6 +196,10 @@ public abstract class Living implements Equine, Caste } } + public boolean onUpdatePassengerPosition(Entity passender, Entity.PositionUpdater positionUpdater) { + return false; + } + public void onJump() { if (getPhysics().isGravityNegative()) { entity.setVelocity(entity.getVelocity().multiply(1, -1, 1)); @@ -275,11 +299,13 @@ public abstract class Living implements Equine, Caste @Override public void toSyncronisedNbt(NbtCompound compound) { compound.put("armour", armour.toNBT()); + getCarrierId().ifPresent(id -> compound.putUuid("carrier", id)); } @Override public void fromSynchronizedNbt(NbtCompound compound) { armour.fromNBT(compound.getCompound("armour")); + setCarrier(compound.containsUuid("carrier") ? compound.getUuid("carrier") : null); } public void updateVelocity() { @@ -294,6 +320,10 @@ public abstract class Living implements Equine, Caste return getOrEmpty(entity).orElse(null); } + public static Living living(E entity) { + return Equine.>of(entity, e -> e instanceof Living).orElse(null); + } + public static void updateVelocity(Entity entity) { entity.velocityModified = true; //if (entity instanceof ServerPlayerEntity ply) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java b/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java index a3df016c..a8ab9fc8 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/duck/EntityDuck.java @@ -1,10 +1,13 @@ package com.minelittlepony.unicopia.entity.duck; +import net.minecraft.entity.Entity; import net.minecraft.entity.Entity.RemovalReason; public interface EntityDuck extends LavaAffine { void setRemovalReason(RemovalReason reason); + void setVehicle(Entity vehicle); + @Override default void setLavaAffine(boolean lavaAffine) { diff --git a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java index 1204ddbe..25118d9b 100644 --- a/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java +++ b/src/main/java/com/minelittlepony/unicopia/entity/player/Pony.java @@ -451,6 +451,30 @@ public class Pony extends Living implements Copyable, Update sendCapabilities(); } + public Optional> getEntityInArms() { + return Living.getOrEmpty(entity.getFirstPassenger()).filter(Living::isBeingCarried); + } + + @Override + public boolean onUpdatePassengerPosition(Entity passender, Entity.PositionUpdater positionUpdater) { + Entity passenger = entity.getFirstPassenger(); + if (Living.getOrEmpty(passenger).filter(Living::isBeingCarried).isPresent()) { + + Vec3d carryPosition = new Vec3d(0, 0, entity.getWidth()); + + float leanAmount = ((LivingEntityDuck)entity).getLeaningPitch(); + carryPosition = carryPosition.rotateX(-leanAmount * MathHelper.PI / 4F) + .add(new Vec3d(0, -0.5F, 0).multiply(leanAmount)); + + carryPosition = carryPosition.rotateY(-entity.getBodyYaw() * MathHelper.RADIANS_PER_DEGREE); + + carryPosition = entity.getPos().add(carryPosition); + positionUpdater.accept(passenger, carryPosition.x, carryPosition.y, carryPosition.z); + return true; + } + return false; + } + public Optional modifyDamage(DamageSource cause, float amount) { if (!cause.isUnblockable() && !cause.isMagic() && !cause.isFire() && !cause.isOutOfWorld() diff --git a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java index c442cd6d..d9b180bf 100644 --- a/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java +++ b/src/main/java/com/minelittlepony/unicopia/mixin/MixinEntity.java @@ -4,12 +4,15 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import com.minelittlepony.unicopia.entity.duck.LavaAffine; +import com.minelittlepony.unicopia.entity.Living; import com.minelittlepony.unicopia.entity.duck.EntityDuck; import net.minecraft.entity.Entity; +import net.minecraft.entity.Entity.PositionUpdater; import net.minecraft.entity.Entity.RemovalReason; @Mixin(Entity.class) @@ -18,6 +21,10 @@ abstract class MixinEntity implements EntityDuck { @Accessor public abstract void setRemovalReason(RemovalReason reason); + @Override + @Accessor + public abstract void setVehicle(Entity vehicle); + @Override public boolean isLavaAffine() { Entity self = (Entity)(Object)this; @@ -30,4 +37,14 @@ abstract class MixinEntity implements EntityDuck { info.setReturnValue(true); } } + + @Inject(method = "updatePassengerPosition(Lnet/minecraft/entity/Entity;Lnet/minecraft/entity/Entity$PositionUpdater;)V", + at = @At("HEAD"), + cancellable = true + ) + private void updatePassengerPosition(Entity passenger, PositionUpdater positionUpdater, CallbackInfo info) { + if (Living.getOrEmpty((Entity)(Object)this).filter(l -> l.onUpdatePassengerPosition(passenger, positionUpdater)).isPresent()) { + info.cancel(); + } + } }