Pigs love muffins

This commit is contained in:
Sollace 2022-03-27 17:47:52 +02:00
parent 2c77cfb4c3
commit d9d56c634c
8 changed files with 183 additions and 6 deletions

View file

@ -0,0 +1,36 @@
package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.Equine;
import com.minelittlepony.unicopia.mixin.client.MixinAnimalModel;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.QuadrupedEntityModel;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.PigEntity;
public class AnimalPoser {
public static final AnimalPoser INSTANCE = new AnimalPoser();
public void applyPosing(MatrixStack matrices, MobEntity entity, EntityModel<?> model) {
if (entity instanceof PigEntity && model instanceof QuadrupedEntityModel<?> quad) {
Equine.of((LivingEntity)entity)
.filter(eq -> eq instanceof Creature)
.map(Creature.class::cast)
.ifPresent(creature -> {
float tickDelta = MinecraftClient.getInstance().getTickDelta();
float headAngle = creature.getHeadAngle(tickDelta);
float neckAngle = 12;
((MixinAnimalModel)quad).invokeGetHeadParts().forEach(part -> {
part.pivotY = neckAngle;
part.pitch = headAngle;
});
});
}
}
}

View file

@ -15,6 +15,7 @@ import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter; import com.minelittlepony.unicopia.ability.magic.spell.effect.TargetSelecter;
import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal; import com.minelittlepony.unicopia.entity.ai.BreakHeartGoal;
import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal; import com.minelittlepony.unicopia.entity.ai.DynamicTargetGoal;
import com.minelittlepony.unicopia.entity.ai.EatMuffinGoal;
import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal; import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal;
import com.minelittlepony.unicopia.entity.player.PlayerAttributes; import com.minelittlepony.unicopia.entity.player.PlayerAttributes;
@ -32,15 +33,18 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.mob.HostileEntity; import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.mob.MobEntity; import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.mob.SlimeEntity; import net.minecraft.entity.mob.SlimeEntity;
import net.minecraft.entity.passive.PigEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World; import net.minecraft.world.World;
public class Creature extends Living<LivingEntity> implements WeaklyOwned<LivingEntity> { public class Creature extends Living<LivingEntity> implements WeaklyOwned<LivingEntity> {
private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); private static final TrackedData<NbtCompound> EFFECT = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
private static final TrackedData<NbtCompound> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND); private static final TrackedData<NbtCompound> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT); public static final TrackedData<Float> GRAVITY = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.FLOAT);
private static final TrackedData<Integer> EATING = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.INTEGER);
private static final LevelStore LEVELS = Levelled.fixed(0); private static final LevelStore LEVELS = Levelled.fixed(0);
@ -55,10 +59,15 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
@Nullable @Nullable
private GoalSelector targets; private GoalSelector targets;
private int eatTimer;
@Nullable
private EatMuffinGoal eatMuffinGoal;
public Creature(LivingEntity entity) { public Creature(LivingEntity entity) {
super(entity, EFFECT); super(entity, EFFECT);
physics = new EntityPhysics<>(entity, GRAVITY); physics = new EntityPhysics<>(entity, GRAVITY);
entity.getDataTracker().startTracking(MASTER, master.toNBT()); entity.getDataTracker().startTracking(MASTER, master.toNBT());
entity.getDataTracker().startTracking(EATING, 0);
} }
@Override @Override
@ -115,6 +124,10 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) { if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter)); goals.add(3, new BreakHeartGoal((MobEntity)entity, targetter));
} }
if (entity instanceof PigEntity) {
eatMuffinGoal = new EatMuffinGoal((MobEntity)entity, targetter);
goals.add(3, eatMuffinGoal);
}
if (master.isPresent(getWorld())) { if (master.isPresent(getWorld())) {
initMinionAi(); initMinionAi();
@ -145,6 +158,37 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
public void tick() { public void tick() {
super.tick(); super.tick();
physics.tick(); physics.tick();
if (isClient()) {
eatTimer = entity.getDataTracker().get(EATING);
} else if (eatMuffinGoal != null) {
eatTimer = eatMuffinGoal.getTimer();
entity.getDataTracker().set(EATING, eatTimer);
}
}
public float getNeckAngle(float delta) {
if (eatTimer <= 0) {
return 0;
}
if (eatTimer >= 4 && eatTimer <= 36) {
return 1;
}
if (eatTimer < 4) {
return (eatTimer - delta) / 4F;
}
return -(eatTimer - 40 - delta) / 4F;
}
public float getHeadAngle(float delta) {
if (eatTimer > 4 && eatTimer <= 36) {
float f = (eatTimer - 4 - delta) / 32F;
return 0.62831855f + 0.21991149f * MathHelper.sin(f * 28.7F);
}
if (eatTimer > 0) {
return 0.62831855f;
}
return entity.getPitch() * ((float)Math.PI / 180);
} }
@Override @Override

View file

@ -22,7 +22,7 @@ public class BreakHeartGoal extends Goal {
public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) { public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) {
this.mob = mob; this.mob = mob;
this.targetter = targetter; this.targetter = targetter;
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK)); this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK, Goal.Control.JUMP));
target = targetter.addPredicate(this::canTarget); target = targetter.addPredicate(this::canTarget);
} }

View file

@ -0,0 +1,83 @@
package com.minelittlepony.unicopia.entity.ai;
import com.minelittlepony.unicopia.entity.PhysicsBodyProjectileEntity;
import com.minelittlepony.unicopia.item.UItems;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.AnimalEntity;
import net.minecraft.entity.player.PlayerEntity;
public class EatMuffinGoal extends BreakHeartGoal {
private int timer;
private boolean eatingStarted;
public EatMuffinGoal(MobEntity mob, DynamicTargetGoal targetter) {
super(mob, targetter);
}
public int getTimer() {
return eatingStarted ? timer : 0;
}
@Override
public void start() {
eatingStarted = false;
timer = getTickCount(10);
mob.getNavigation().stop();
}
@Override
public void stop() {
super.stop();
eatingStarted = false;
timer = 0;
}
@Override
public boolean shouldContinue() {
return timer > 0 && super.shouldContinue();
}
@Override
protected boolean canTarget(Entity e) {
return !e.isRemoved()
&& e instanceof PhysicsBodyProjectileEntity
&& ((PhysicsBodyProjectileEntity)e).getStack().getItem() == UItems.MUFFIN
&& mob.getVisibilityCache().canSee(e);
}
@Override
protected void attackTarget(Entity target, double reach, double distance) {
double speed = 1D;
if (distance > 5) {
speed += 0.5;
}
if (distance < 2) {
speed += 0.1D;
}
mob.getNavigation().startMovingTo(target, speed);
if (distance <= reach + 0.5) {
eatingStarted = true;
if (target instanceof PhysicsBodyProjectileEntity projectile) {
mob.eatFood(mob.world, projectile.getStack());
projectile.discard();
if (mob instanceof AnimalEntity animal) {
if (mob.world.random.nextInt(12) == 0) {
Entity player = ((PhysicsBodyProjectileEntity) target).getOwner();
animal.lovePlayer(player instanceof PlayerEntity ? (PlayerEntity)player : null);
animal.setLoveTicks(1000);
}
}
}
}
}
}

View file

@ -29,11 +29,7 @@ abstract class ProjectileItem extends Item implements ProjectileDelegate<Project
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) { public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
if (isFood() && !player.isSneaking()) { if (isFood() && !player.isSneaking()) {
TypedActionResult<ItemStack> eaten = super.use(world, player, hand); return super.use(world, player, hand);
if (eaten.getResult().isAccepted()) {
return eaten;
}
} }
ItemStack stack = player.getStackInHand(hand); ItemStack stack = player.getStackInHand(hand);

View file

@ -0,0 +1,12 @@
package com.minelittlepony.unicopia.mixin.client;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
import net.minecraft.client.model.ModelPart;
import net.minecraft.client.render.entity.model.AnimalModel;
@Mixin(AnimalModel.class)
public interface MixinAnimalModel {
@Invoker("getHeadParts")
Iterable<ModelPart> invokeGetHeadParts();
}

View file

@ -6,6 +6,7 @@ import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.client.render.AnimalPoser;
import com.minelittlepony.unicopia.client.render.PlayerPoser; import com.minelittlepony.unicopia.client.render.PlayerPoser;
import net.minecraft.client.render.VertexConsumerProvider; import net.minecraft.client.render.VertexConsumerProvider;
@ -16,6 +17,7 @@ import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.model.EntityModel; import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.util.math.MatrixStack; import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@Mixin(LivingEntityRenderer.class) @Mixin(LivingEntityRenderer.class)
@ -37,5 +39,8 @@ abstract class MixinLivingEntityRenderer<T extends LivingEntity, M extends Entit
if (entity instanceof PlayerEntity player) { if (entity instanceof PlayerEntity player) {
PlayerPoser.INSTANCE.applyPosing(matrices, player, (BipedEntityModel<?>)getModel()); PlayerPoser.INSTANCE.applyPosing(matrices, player, (BipedEntityModel<?>)getModel());
} }
if (entity instanceof MobEntity mob) {
AnimalPoser.INSTANCE.applyPosing(matrices, mob, getModel());
}
} }
} }

View file

@ -32,6 +32,7 @@
"MixinWorldChunk" "MixinWorldChunk"
], ],
"client": [ "client": [
"client.MixinAnimalModel",
"client.MixinArmorFeatureRenderer", "client.MixinArmorFeatureRenderer",
"client.MixinCamera", "client.MixinCamera",
"client.MixinClientPlayerInteractionManager", "client.MixinClientPlayerInteractionManager",