mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 23:27:59 +01:00
Pigs love muffins
This commit is contained in:
parent
2c77cfb4c3
commit
d9d56c634c
8 changed files with 183 additions and 6 deletions
|
@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.entity.ai.BreakHeartGoal;
|
||||
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.player.PlayerAttributes;
|
||||
|
||||
|
@ -32,15 +33,18 @@ import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
|||
import net.minecraft.entity.mob.HostileEntity;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.mob.SlimeEntity;
|
||||
import net.minecraft.entity.passive.PigEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.nbt.NbtCompound;
|
||||
import net.minecraft.nbt.NbtElement;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
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> MASTER = DataTracker.registerData(LivingEntity.class, TrackedDataHandlerRegistry.NBT_COMPOUND);
|
||||
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);
|
||||
|
||||
|
@ -55,10 +59,15 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
|
|||
@Nullable
|
||||
private GoalSelector targets;
|
||||
|
||||
private int eatTimer;
|
||||
@Nullable
|
||||
private EatMuffinGoal eatMuffinGoal;
|
||||
|
||||
public Creature(LivingEntity entity) {
|
||||
super(entity, EFFECT);
|
||||
physics = new EntityPhysics<>(entity, GRAVITY);
|
||||
entity.getDataTracker().startTracking(MASTER, master.toNBT());
|
||||
entity.getDataTracker().startTracking(EATING, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -115,6 +124,10 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
|
|||
if (entity.getType().getSpawnGroup() == SpawnGroup.MONSTER) {
|
||||
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())) {
|
||||
initMinionAi();
|
||||
|
@ -145,6 +158,37 @@ public class Creature extends Living<LivingEntity> implements WeaklyOwned<Living
|
|||
public void tick() {
|
||||
super.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
|
||||
|
|
|
@ -22,7 +22,7 @@ public class BreakHeartGoal extends Goal {
|
|||
public BreakHeartGoal(MobEntity mob, DynamicTargetGoal targetter) {
|
||||
this.mob = mob;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,11 +29,7 @@ abstract class ProjectileItem extends Item implements ProjectileDelegate<Project
|
|||
public TypedActionResult<ItemStack> use(World world, PlayerEntity player, Hand hand) {
|
||||
|
||||
if (isFood() && !player.isSneaking()) {
|
||||
TypedActionResult<ItemStack> eaten = super.use(world, player, hand);
|
||||
|
||||
if (eaten.getResult().isAccepted()) {
|
||||
return eaten;
|
||||
}
|
||||
return super.use(world, player, hand);
|
||||
}
|
||||
|
||||
ItemStack stack = player.getStackInHand(hand);
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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.callback.CallbackInfo;
|
||||
|
||||
import com.minelittlepony.unicopia.client.render.AnimalPoser;
|
||||
import com.minelittlepony.unicopia.client.render.PlayerPoser;
|
||||
|
||||
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.util.math.MatrixStack;
|
||||
import net.minecraft.entity.LivingEntity;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
|
||||
@Mixin(LivingEntityRenderer.class)
|
||||
|
@ -37,5 +39,8 @@ abstract class MixinLivingEntityRenderer<T extends LivingEntity, M extends Entit
|
|||
if (entity instanceof PlayerEntity player) {
|
||||
PlayerPoser.INSTANCE.applyPosing(matrices, player, (BipedEntityModel<?>)getModel());
|
||||
}
|
||||
if (entity instanceof MobEntity mob) {
|
||||
AnimalPoser.INSTANCE.applyPosing(matrices, mob, getModel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"MixinWorldChunk"
|
||||
],
|
||||
"client": [
|
||||
"client.MixinAnimalModel",
|
||||
"client.MixinArmorFeatureRenderer",
|
||||
"client.MixinCamera",
|
||||
"client.MixinClientPlayerInteractionManager",
|
||||
|
|
Loading…
Reference in a new issue