Set position and render entities being carried by pegasi in their arms arms

This commit is contained in:
Sollace 2022-12-25 19:36:43 +01:00
parent e9070b87b0
commit 7ca2e63fae
12 changed files with 272 additions and 2 deletions

View file

@ -73,6 +73,7 @@ public class CarryAbility implements Ability<Hit> {
if (rider != null) {
rider.startRiding(player, true);
Living.getOrEmpty(rider).ifPresent(living -> living.setCarrier(player));
}
Living.transmitPassengers(player);

View file

@ -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);

View file

@ -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<LivingEntity> 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 <T extends Entity> Identifier getTexture(T entity, Context<T, ?> context) {
return MinecraftClient.getInstance().getEntityRenderDispatcher().getRenderer(entity).getTexture(entity);
}
@Override
public <M extends EntityModel<?> & 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<LivingEntity> entity, Living<?> passenger) {
return super.getCarryPosition(entity, passenger);
}
}

View file

@ -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;

View file

@ -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) {
}
}

View file

@ -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<E extends LivingEntity> implements AccessoryFeatureRenderer.Feature<E> {
public HeldEntityFeatureRenderer(FeatureRendererContext<E, ? extends BipedEntityModel<E>> 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<E> l = Living.living(entity);
Vec3d carryPosition = getCarryPosition(l, passenger);
LivingEntity p = passenger.asEntity();
@SuppressWarnings("unchecked")
EntityRenderer<LivingEntity> renderer = (EntityRenderer<LivingEntity>)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<E> 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()
);
}
}

View file

@ -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);

View file

@ -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();

View file

@ -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<T extends LivingEntity> implements Equine<T>, Caster<T>, Transmittable {
private static final TrackedData<Optional<UUID>> CARRIER_ID = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.OPTIONAL_UUID);
protected final T entity;
@ -69,6 +71,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, 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<T extends LivingEntity> implements Equine<T>, Caste
return entity;
}
public Optional<UUID> 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<T extends LivingEntity> implements Equine<T>, 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<T extends LivingEntity> implements Equine<T>, 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<T extends LivingEntity> implements Equine<T>, Caste
return getOrEmpty(entity).orElse(null);
}
public static <E extends LivingEntity> Living<E> living(E entity) {
return Equine.<E, Living<E>>of(entity, e -> e instanceof Living<?>).orElse(null);
}
public static void updateVelocity(Entity entity) {
entity.velocityModified = true;
//if (entity instanceof ServerPlayerEntity ply) {

View file

@ -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) {

View file

@ -451,6 +451,30 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
sendCapabilities();
}
public Optional<Living<?>> 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<Float> modifyDamage(DamageSource cause, float amount) {
if (!cause.isUnblockable() && !cause.isMagic() && !cause.isFire() && !cause.isOutOfWorld()

View file

@ -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();
}
}
}