Changelings can now climb on walls and hang from ceilings, like little spider pigs!

This commit is contained in:
Sollace 2023-08-06 21:46:07 +01:00
parent ada4afd645
commit 25abf359bf
No known key found for this signature in database
GPG key ID: E52FACE7B5C773DB
4 changed files with 119 additions and 20 deletions

View file

@ -22,18 +22,18 @@ import net.minecraft.util.Identifier;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
public record Race (boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal) implements Affine {
public record Race (boolean canCast, FlightType flightType, boolean canUseEarth, boolean isNocturnal, boolean canHang) implements Affine {
public static final String DEFAULT_ID = "unicopia:unset";
public static final Registry<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID);
public static final RegistryKey<? extends Registry<Race>> REGISTRY_KEY = REGISTRY.getKey();
private static final DynamicCommandExceptionType UNKNOWN_RACE_EXCEPTION = new DynamicCommandExceptionType(id -> Text.translatable("race.unknown", id));
public static Race register(String name, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
return register(Unicopia.id(name), magic, flight, earth, nocturnal);
public static Race register(String name, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) {
return register(Unicopia.id(name), magic, flight, earth, nocturnal, canHang);
}
public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean nocturnal) {
return Registry.register(REGISTRY, id, new Race(magic, flight, earth, nocturnal));
public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean nocturnal, boolean canHang) {
return Registry.register(REGISTRY, id, new Race(magic, flight, earth, nocturnal, canHang));
}
public static RegistryKeyArgumentType<Race> argument() {
@ -44,14 +44,14 @@ public record Race (boolean canCast, FlightType flightType, boolean canUseEarth,
* The default, unset race.
* This is used if there are no other races.
*/
public static final Race UNSET = register("unset", false, FlightType.NONE, false, false);
public static final Race HUMAN = register("human", false, FlightType.NONE, false, false);
public static final Race EARTH = register("earth", false, FlightType.NONE, true, false);
public static final Race UNICORN = register("unicorn", true, FlightType.NONE, false, false);
public static final Race PEGASUS = register("pegasus", false, FlightType.AVIAN, false, false);
public static final Race BAT = register("bat", false, FlightType.AVIAN, false, true);
public static final Race ALICORN = register("alicorn", true, FlightType.AVIAN, true, false);
public static final Race CHANGELING = register("changeling", false, FlightType.INSECTOID, false, false);
public static final Race UNSET = register("unset", false, FlightType.NONE, false, false, false);
public static final Race HUMAN = register("human", false, FlightType.NONE, false, false, false);
public static final Race EARTH = register("earth", false, FlightType.NONE, true, false, false);
public static final Race UNICORN = register("unicorn", true, FlightType.NONE, false, false, false);
public static final Race PEGASUS = register("pegasus", false, FlightType.AVIAN, false, false, false);
public static final Race BAT = register("bat", false, FlightType.AVIAN, false, true, true);
public static final Race ALICORN = register("alicorn", true, FlightType.AVIAN, true, false, false);
public static final Race CHANGELING = register("changeling", false, FlightType.INSECTOID, false, false, true);
public static void bootstrap() {}

View file

@ -108,11 +108,10 @@ public class PlayerPoser {
float pitch = 3F * saw;
float yaw = 0.5F * saw;
float roll = saw;
if (ponyRace.isEquine()) {
rearUp(matrices, model, saw);
pitch = roll * 2F;
pitch = saw * 2F;
model.head.pitch += saw * 0.5F;
}
@ -132,6 +131,31 @@ public class PlayerPoser {
break;
}
case CLIMB: {
float saw = AnimationUtil.seesaw(progress);
float pitch = MathHelper.clamp(3F * saw, 1, 2);
float yaw = 0.5F * saw;
if (ponyRace.isEquine()) {
rearUp(matrices, model, saw);
pitch = saw * 2F;
model.head.pitch += saw * 0.5F;
}
rotateArm(model.leftArm, pitch, -yaw, yaw / 2F);
rotateArm(model.rightLeg, pitch / 2F, yaw, 0);
saw = AnimationUtil.seesaw((progress + 0.5F) % 1);
pitch = MathHelper.clamp(3F * saw, 1, 2) * (ponyRace.isEquine() ? 2 : 1);
yaw = 0.5F * saw;
rotateArm(model.rightArm, pitch, yaw, -yaw / 2F);
rotateArm(model.leftLeg, pitch / 2F, -yaw, 0);
break;
}
case WAVE_ONE:
case WAVE_TWO: {
progress = AnimationUtil.seesaw(progress);
@ -283,6 +307,7 @@ public class PlayerPoser {
WAVE_ONE(USounds.ENTITY_PLAYER_WHISTLE, 20),
WAVE_TWO(USounds.ENTITY_PLAYER_WHISTLE, 20),
KICK(USounds.ENTITY_PLAYER_KICK, 5),
CLIMB(20),
STOMP(5),
WIGGLE_NOSE(6),
SPREAD_WINGS(6),

View file

@ -98,7 +98,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
@Override
public float getGravityModifier() {
float modifier = getPersistantGravityModifier();
if (pony.isHanging()) {
if (pony.isHanging() && pony.getObservedSpecies() == Race.BAT) {
modifier *= -0.05F;
}
return modifier;

View file

@ -6,6 +6,7 @@ import java.util.stream.Stream;
import org.jetbrains.annotations.Nullable;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation.Recipient;
import com.minelittlepony.unicopia.client.render.PlayerPoser.AnimationInstance;
import com.minelittlepony.unicopia.*;
import com.minelittlepony.unicopia.ability.*;
@ -34,6 +35,7 @@ import com.minelittlepony.common.util.animation.Interpolator;
import com.mojang.authlib.GameProfile;
import net.minecraft.block.BlockState;
import net.minecraft.block.SideShapeType;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.*;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
@ -58,6 +60,7 @@ import net.minecraft.util.Hand;
import net.minecraft.util.math.*;
import net.minecraft.world.GameMode;
import net.minecraft.world.GameRules;
import net.minecraft.world.World;
public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, UpdateCallback {
private static final TrackedData<String> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
@ -101,6 +104,9 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
private boolean hasShades;
private int ticksSunImmunity = INITIAL_SUN_IMMUNITY;
private Direction attachDirection;
private double distanceClimbed;
private AnimationInstance animation = new AnimationInstance(Animation.NONE, Animation.Recipient.ANYONE);
private int animationMaxDuration;
private int animationDuration;
@ -359,14 +365,69 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
powers.tick();
if (entity.getClimbingPos().isPresent() && entity.isSneaky()) {
BlockPos climbingPos = entity.getClimbingPos().orElse(null);
if (!getPhysics().isFlying() && !entity.getAbilities().flying && climbingPos != null && getObservedSpecies() == Race.CHANGELING) {
Vec3d vel = entity.getVelocity();
entity.setVelocity(vel.x, 0, vel.z);
if (entity.isSneaky()) {
entity.setVelocity(vel.x, 0, vel.z);
}
distanceClimbed += vel.length();
BlockPos hangingPos = entity.getBlockPos().up();
boolean canhangHere = canHangAt(hangingPos);
if (distanceClimbed > 1.5) {
if (vel.length() > 0.08F && entity.age % (3 + entity.getRandom().nextInt(5)) == 0) {
entity.playSound(SoundEvents.ENTITY_CHICKEN_STEP,
(float)entity.getRandom().nextTriangular(0.5, 0.3),
entity.getSoundPitch()
);
}
boolean skipHangCheck = false;
Direction newAttachDirection = entity.getHorizontalFacing();
if (isFaceClimbable(entity.getWorld(), entity.getBlockPos(), newAttachDirection) && (newAttachDirection != attachDirection)) {
attachDirection = newAttachDirection;
skipHangCheck = true;
}
if (!skipHangCheck && canhangHere) {
if (!isHanging()) {
startHanging(hangingPos);
} else {
if (((LivingEntityDuck)entity).isJumping()) {
// Jump to let go
return false;
}
entity.setVelocity(entity.getVelocity().multiply(1, 0, 1));
entity.setSneaking(false);
}
} else if (attachDirection != null && isFaceClimbable(entity.getWorld(), entity.getBlockPos(), attachDirection)) {
entity.setBodyYaw(attachDirection.asRotation());
entity.prevBodyYaw = attachDirection.asRotation();
}
}
if (getAnimation().isOf(Animation.NONE) || (getAnimation().isOf(Animation.NONE) && canhangHere)) {
if (canhangHere) {
setAnimation(Animation.ARMS_UP, Recipient.HUMAN);
} else if (distanceClimbed > 1.5) {
setAnimation(Animation.CLIMB, Recipient.HUMAN);
}
}
} else {
distanceClimbed = 0;
}
return false;
}
private boolean isFaceClimbable(World world, BlockPos pos, Direction direction) {
pos = pos.offset(direction);
return world.getBlockState(pos).isSideSolid(world, pos, direction, SideShapeType.CENTER);
}
public Optional<BlockPos> getHangingPosition() {
return entity.getDataTracker().get(HANGING_POSITION);
}
@ -410,6 +471,17 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
}
private void updateAnimations() {
if (distanceClimbed > 0
&& ((animation.isOf(Animation.CLIMB) && entity.isSneaky()) || (animation.isOf(Animation.ARMS_UP) && isHanging()))
&& entity.getClimbingPos().isPresent()
&& entity.getVelocity().length() < 0.08F) {
if (animation.isOf(Animation.ARMS_UP)) {
animationDuration = 2;
}
return;
}
if (animationDuration > 0 && --animationDuration <= 0) {
setAnimation(AnimationInstance.NONE);
}
@ -422,8 +494,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
if (isHanging()) {
((LivingEntityDuck)entity).setLeaningPitch(0);
if (!isClient() && (getObservedSpecies() != Race.BAT || (ticksHanging++ > 2 && getHangingPosition().filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty()))) {
stopHanging();
if (!getObservedSpecies().canHang() || (ticksHanging++ > 2 && getHangingPosition().filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty())) {
if (!isClient()) {
stopHanging();
}
}
} else {
ticksHanging = 0;