Added player animations for doing things like casting spells and kicking

This commit is contained in:
Sollace 2022-01-03 22:54:07 +02:00
parent 4e621434af
commit bce1e5c8c1
10 changed files with 242 additions and 0 deletions

View file

@ -10,6 +10,7 @@ import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.data.Pos;
import com.minelittlepony.unicopia.ability.data.tree.TreeType;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.RayTraceHelper;
@ -89,6 +90,8 @@ public class EarthPonyKickAbility implements Ability<Pos> {
return;
}
iplayer.setAnimation(Animation.KICK, 30);
BlockPos pos = data.pos();
BlockDestructionManager destr = ((BlockDestructionManager.Source)player.world).getDestructionManager();

View file

@ -9,6 +9,7 @@ import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.AmuletItem;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
@ -106,11 +107,14 @@ public class UnicornCastingAbility implements Ability<Hit> {
player.spawnParticles(ParticleTypes.LARGE_SMOKE, 6);
player.playSound(SoundEvents.ENTITY_ITEM_BREAK, 1, 0.5F);
} else {
player.setAnimation(Animation.ARMS_UP, 5);
if (s instanceof HomingSpell) {
RayTraceHelper.doTrace(player.getMaster(), 600, 1, EntityPredicates.CAN_COLLIDE).getEntity().ifPresent(((HomingSpell)s)::setTarget);
}
player.playSound(SoundEvents.BLOCK_BEACON_POWER_SELECT, 0.05F, 2.2F);
}
} else {
player.setAnimation(Animation.WOLOLO, 20);
}
}
}

View file

@ -7,6 +7,7 @@ import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Pos;
import com.minelittlepony.unicopia.ability.magic.Caster;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.util.RayTraceHelper;
@ -43,6 +44,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
public boolean onQuickAction(Pony player, ActivationType type) {
if (type.getTapCount() > 1) {
player.setAnimation(Animation.WOLOLO, 10);
if (player.getSpellSlot().clear()) {
player.getMaster().sendMessage(new TranslatableText("gui.unicopia.action.spells_cleared"), true);
} else {
@ -73,6 +75,7 @@ public class UnicornDispellAbility implements Ability<Pos> {
@Override
public void apply(Pony player, Pos data) {
player.setAnimation(Animation.WOLOLO, 30);
Caster.stream(VecHelper.findInRange(player.getEntity(), player.getWorld(), data.vec(), 2, EquinePredicates.IS_PLACED_SPELL).stream()).forEach(target -> {
target.getSpellSlot().clear();
});

View file

@ -5,6 +5,7 @@ import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.ability.magic.spell.HomingSpell;
import com.minelittlepony.unicopia.ability.magic.spell.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.effect.CustomisedSpellType;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.util.RayTraceHelper;
@ -69,6 +70,7 @@ public class UnicornProjectileAbility implements Ability<Hit> {
Spell spell = thrown.getValue().create();
spell.toThrowable().throwProjectile(player).ifPresent(projectile -> {
player.setAnimation(Animation.ARMS_FORWARD, 5);
if (spell instanceof HomingSpell) {
RayTraceHelper.doTrace(player.getMaster(), 600, 1, EntityPredicates.CAN_COLLIDE).getEntity().filter(((HomingSpell)spell)::setTarget).ifPresent(target -> {
projectile.setHomingTarget(target);

View file

@ -0,0 +1,91 @@
package com.minelittlepony.unicopia.client.render;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.util.Arm;
import net.minecraft.util.math.MathHelper;
public class PlayerPoser {
public static final PlayerPoser INSTANCE = new PlayerPoser();
public void applyPosing(PlayerEntity entity, BipedEntityModel<?> model) {
Pony pony = Pony.of(entity);
float progress = pony.getAnimationProgress(MinecraftClient.getInstance().getTickDelta());
switch (pony.getAnimation()) {
case WOLOLO: {
float roll = MathHelper.sin(entity.age / 10F);
float yaw = MathHelper.cos(entity.age / 10F);
model.leftArm.pitch += -1;
model.rightArm.pitch += -1;
model.leftArm.roll = -roll;
model.rightArm.roll = roll;
model.leftArm.yaw = yaw;
model.rightArm.yaw = yaw;
break;
}
case ARMS_FORWARD: {
float roll = (progress + 1) / 2F;
float pitch = 1.5F * roll;
float yaw = 0.5F * roll;
model.leftArm.pitch -= pitch;
model.rightArm.pitch -= pitch;
model.leftArm.roll = 0;
model.rightArm.roll = 0;
model.leftArm.yaw = yaw;
model.rightArm.yaw = -yaw;
break;
}
case ARMS_UP: {
float roll = (progress + 1) / 2F;
float pitch = 3F * roll;
float yaw = 0.5F * roll;
model.leftArm.pitch -= pitch;
model.rightArm.pitch -= pitch;
model.leftArm.roll = 0;
model.rightArm.roll = 0;
model.leftArm.yaw = yaw;
model.rightArm.yaw = -yaw;
break;
}
case KICK: {
float roll = (progress + 1) / 2F;
model.rightArm.pitch += roll / 5F;
model.leftArm.roll -= roll / 5F;
model.rightArm.roll += roll / 5F;
if (entity.getMainArm() == Arm.LEFT) {
model.rightLeg.pitch = -roll * 1.5F;
model.rightLeg.roll = roll / 10F;
} else {
model.leftLeg.pitch = -roll * 1.5F;
model.leftLeg.roll = -roll / 10F;
}
}
default:
}
}
public enum Animation {
NONE,
WOLOLO,
ARMS_FORWARD,
ARMS_UP,
KICK
}
}

View file

@ -9,6 +9,7 @@ import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.Affinity;
import com.minelittlepony.unicopia.client.UnicopiaClient;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.InteractionManager;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UTags;
@ -30,6 +31,7 @@ import com.minelittlepony.unicopia.item.UItems;
import com.minelittlepony.unicopia.item.toxin.Toxin;
import com.minelittlepony.unicopia.network.Channel;
import com.minelittlepony.unicopia.network.MsgOtherPlayerCapabilities;
import com.minelittlepony.unicopia.network.MsgPlayerAnimationChange;
import com.minelittlepony.unicopia.network.MsgRequestSpeciesChange;
import com.minelittlepony.unicopia.network.datasync.Transmittable;
import com.minelittlepony.unicopia.network.datasync.EffectSync.UpdateCallback;
@ -58,6 +60,7 @@ import net.minecraft.nbt.NbtCompound;
import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundEvents;
import net.minecraft.text.Text;
import net.minecraft.text.TranslatableText;
import net.minecraft.util.Hand;
@ -106,6 +109,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
private int ticksInSun;
private boolean hasShades;
private Animation animation = Animation.NONE;
private int animationMaxDuration;
private int animationDuration;
public Pony(PlayerEntity player) {
super(player, EFFECT);
this.mana = new ManaContainer(this);
@ -121,6 +128,33 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
builder.add(PlayerAttributes.ENTITY_GRAVTY_MODIFIER);
}
public void setAnimation(Animation animation, int duration) {
if (animation != this.animation && duration != animationDuration) {
this.animation = animation;
this.animationDuration = animation == Animation.NONE ? 0 : Math.max(0, duration);
this.animationMaxDuration = animationDuration;
if (!isClient()) {
Channel.SERVER_PLAYER_ANIMATION_CHANGE.send(getWorld(), new MsgPlayerAnimationChange(this, animation, animationDuration));
}
if (animation == Animation.WOLOLO) {
playSound(SoundEvents.ENTITY_EVOKER_PREPARE_WOLOLO, 0.9F, 1);
}
}
}
public Animation getAnimation() {
return animation;
}
public float getAnimationProgress(float delta) {
if (animation == Animation.NONE) {
return 0;
}
return 1 - ((animationDuration + delta) / animationMaxDuration);
}
@Override
public Race getSpecies() {
if (getMaster() == null) {
@ -288,6 +322,11 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
@Override
public void tick() {
if (animationDuration >= 0) {
if (--animationDuration <= 0) {
setAnimation(Animation.NONE, 0);
}
}
if (isHanging()) {
if (ticksHanging++ > 40) {

View file

@ -0,0 +1,49 @@
package com.minelittlepony.unicopia.mixin.client;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.At.Shift;
import org.spongepowered.asm.mixin.injection.Desc;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.client.render.PlayerPoser;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.entity.EntityRenderer;
import net.minecraft.client.render.entity.LivingEntityRenderer;
import net.minecraft.client.render.entity.feature.FeatureRendererContext;
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.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
@Mixin(LivingEntityRenderer.class)
abstract class MixinLivingEntityRenderer<T extends LivingEntity, M extends EntityModel<T>> extends EntityRenderer<T> implements FeatureRendererContext<T, M> {
MixinLivingEntityRenderer() { super(null); }
@Inject(method = "render",
at = @At(
value = "INVOKE",
desc = @Desc(
value = "setAngles",
owner = EntityModel.class,
args = { Entity.class, float.class, float.class, float.class, float.class, float.class }
),
shift = Shift.AFTER
)
)
private void onRender(
T entity,
float f, float g,
MatrixStack matrixStack,
VertexConsumerProvider vertexConsumerProvider,
int i,
CallbackInfo into) {
if (entity instanceof PlayerEntity player) {
PlayerPoser.INSTANCE.applyPosing(player, (BipedEntityModel<?>)getModel());
}
}
}

View file

@ -25,6 +25,7 @@ public interface Channel {
S2CPacketType<MsgTribeSelect> SERVER_SELECT_TRIBE = SimpleNetworking.serverToClient(SERVER_SELECT_TRIBE_ID, MsgTribeSelect::new);
S2CBroadcastPacketType<MsgOtherPlayerCapabilities> SERVER_OTHER_PLAYER_CAPABILITIES = SimpleNetworking.serverToClients(new Identifier("unicopia", "other_player_capabilities"), MsgOtherPlayerCapabilities::new);
S2CBroadcastPacketType<MsgPlayerAnimationChange> SERVER_PLAYER_ANIMATION_CHANGE = SimpleNetworking.serverToClients(new Identifier("unicopia", "other_player_animation_change"), MsgPlayerAnimationChange::new);
static void bootstrap() {
ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> {

View file

@ -0,0 +1,49 @@
package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.util.network.Packet;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.PacketByteBuf;
/**
* Sent to the client when a player's animation changes.
*/
public class MsgPlayerAnimationChange implements Packet<PlayerEntity> {
private final UUID playerId;
private final Animation animation;
private final int duration;
MsgPlayerAnimationChange(PacketByteBuf buffer) {
playerId = buffer.readUuid();
animation = Animation.values()[buffer.readInt()];
duration = buffer.readInt();
}
public MsgPlayerAnimationChange(Pony player, Animation animation, int duration) {
this.playerId = player.getEntity().getUuid();
this.animation = animation;
this.duration = duration;
}
@Override
public void toBuffer(PacketByteBuf buffer) {
buffer.writeUuid(playerId);
buffer.writeInt(animation.ordinal());
buffer.writeInt(duration);
}
@Override
public void handle(PlayerEntity sender) {
Pony player = Pony.of(MinecraftClient.getInstance().world.getPlayerByUuid(playerId));
if (player == null) {
return;
}
player.setAnimation(animation, duration);
}
}

View file

@ -42,6 +42,7 @@
"client.MixinItemModels",
"client.MixinKeyboardInput",
"client.MixinLightmapTextureManager",
"client.MixinLivingEntityRenderer",
"client.MixinMouse",
"client.MixinPlayerEntityRenderer",
"client.MixinTooltipComponent",