mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-07 22:16:44 +01:00
Changelings can now climb on walls and hang from ceilings, like little spider pigs!
This commit is contained in:
parent
ada4afd645
commit
25abf359bf
4 changed files with 119 additions and 20 deletions
|
@ -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() {}
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue