mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-12 16:14:24 +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.Registry;
|
||||||
import net.minecraft.registry.RegistryKey;
|
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 String DEFAULT_ID = "unicopia:unset";
|
||||||
public static final Registry<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID);
|
public static final Registry<Race> REGISTRY = RegistryUtils.createDefaulted(Unicopia.id("race"), DEFAULT_ID);
|
||||||
public static final RegistryKey<? extends Registry<Race>> REGISTRY_KEY = REGISTRY.getKey();
|
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));
|
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) {
|
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);
|
return register(Unicopia.id(name), magic, flight, earth, nocturnal, canHang);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Race register(Identifier id, boolean magic, FlightType flight, boolean earth, boolean 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));
|
return Registry.register(REGISTRY, id, new Race(magic, flight, earth, nocturnal, canHang));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegistryKeyArgumentType<Race> argument() {
|
public static RegistryKeyArgumentType<Race> argument() {
|
||||||
|
@ -44,14 +44,14 @@ public record Race (boolean canCast, FlightType flightType, boolean canUseEarth,
|
||||||
* The default, unset race.
|
* The default, unset race.
|
||||||
* This is used if there are no other races.
|
* 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 UNSET = register("unset", false, FlightType.NONE, false, false, false);
|
||||||
public static final Race HUMAN = register("human", false, FlightType.NONE, 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);
|
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);
|
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);
|
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);
|
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);
|
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);
|
public static final Race CHANGELING = register("changeling", false, FlightType.INSECTOID, false, false, true);
|
||||||
|
|
||||||
public static void bootstrap() {}
|
public static void bootstrap() {}
|
||||||
|
|
||||||
|
|
|
@ -108,11 +108,10 @@ public class PlayerPoser {
|
||||||
|
|
||||||
float pitch = 3F * saw;
|
float pitch = 3F * saw;
|
||||||
float yaw = 0.5F * saw;
|
float yaw = 0.5F * saw;
|
||||||
float roll = saw;
|
|
||||||
|
|
||||||
if (ponyRace.isEquine()) {
|
if (ponyRace.isEquine()) {
|
||||||
rearUp(matrices, model, saw);
|
rearUp(matrices, model, saw);
|
||||||
pitch = roll * 2F;
|
pitch = saw * 2F;
|
||||||
model.head.pitch += saw * 0.5F;
|
model.head.pitch += saw * 0.5F;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,6 +131,31 @@ public class PlayerPoser {
|
||||||
|
|
||||||
break;
|
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_ONE:
|
||||||
case WAVE_TWO: {
|
case WAVE_TWO: {
|
||||||
progress = AnimationUtil.seesaw(progress);
|
progress = AnimationUtil.seesaw(progress);
|
||||||
|
@ -283,6 +307,7 @@ public class PlayerPoser {
|
||||||
WAVE_ONE(USounds.ENTITY_PLAYER_WHISTLE, 20),
|
WAVE_ONE(USounds.ENTITY_PLAYER_WHISTLE, 20),
|
||||||
WAVE_TWO(USounds.ENTITY_PLAYER_WHISTLE, 20),
|
WAVE_TWO(USounds.ENTITY_PLAYER_WHISTLE, 20),
|
||||||
KICK(USounds.ENTITY_PLAYER_KICK, 5),
|
KICK(USounds.ENTITY_PLAYER_KICK, 5),
|
||||||
|
CLIMB(20),
|
||||||
STOMP(5),
|
STOMP(5),
|
||||||
WIGGLE_NOSE(6),
|
WIGGLE_NOSE(6),
|
||||||
SPREAD_WINGS(6),
|
SPREAD_WINGS(6),
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class PlayerPhysics extends EntityPhysics<PlayerEntity> implements Tickab
|
||||||
@Override
|
@Override
|
||||||
public float getGravityModifier() {
|
public float getGravityModifier() {
|
||||||
float modifier = getPersistantGravityModifier();
|
float modifier = getPersistantGravityModifier();
|
||||||
if (pony.isHanging()) {
|
if (pony.isHanging() && pony.getObservedSpecies() == Race.BAT) {
|
||||||
modifier *= -0.05F;
|
modifier *= -0.05F;
|
||||||
}
|
}
|
||||||
return modifier;
|
return modifier;
|
||||||
|
|
|
@ -6,6 +6,7 @@ import java.util.stream.Stream;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.client.render.PlayerPoser.Animation;
|
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.client.render.PlayerPoser.AnimationInstance;
|
||||||
import com.minelittlepony.unicopia.*;
|
import com.minelittlepony.unicopia.*;
|
||||||
import com.minelittlepony.unicopia.ability.*;
|
import com.minelittlepony.unicopia.ability.*;
|
||||||
|
@ -34,6 +35,7 @@ import com.minelittlepony.common.util.animation.Interpolator;
|
||||||
import com.mojang.authlib.GameProfile;
|
import com.mojang.authlib.GameProfile;
|
||||||
|
|
||||||
import net.minecraft.block.BlockState;
|
import net.minecraft.block.BlockState;
|
||||||
|
import net.minecraft.block.SideShapeType;
|
||||||
import net.minecraft.enchantment.EnchantmentHelper;
|
import net.minecraft.enchantment.EnchantmentHelper;
|
||||||
import net.minecraft.entity.*;
|
import net.minecraft.entity.*;
|
||||||
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
import net.minecraft.entity.attribute.DefaultAttributeContainer;
|
||||||
|
@ -58,6 +60,7 @@ import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.math.*;
|
||||||
import net.minecraft.world.GameMode;
|
import net.minecraft.world.GameMode;
|
||||||
import net.minecraft.world.GameRules;
|
import net.minecraft.world.GameRules;
|
||||||
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, UpdateCallback {
|
public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, UpdateCallback {
|
||||||
private static final TrackedData<String> RACE = DataTracker.registerData(PlayerEntity.class, TrackedDataHandlerRegistry.STRING);
|
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 boolean hasShades;
|
||||||
private int ticksSunImmunity = INITIAL_SUN_IMMUNITY;
|
private int ticksSunImmunity = INITIAL_SUN_IMMUNITY;
|
||||||
|
|
||||||
|
private Direction attachDirection;
|
||||||
|
private double distanceClimbed;
|
||||||
|
|
||||||
private AnimationInstance animation = new AnimationInstance(Animation.NONE, Animation.Recipient.ANYONE);
|
private AnimationInstance animation = new AnimationInstance(Animation.NONE, Animation.Recipient.ANYONE);
|
||||||
private int animationMaxDuration;
|
private int animationMaxDuration;
|
||||||
private int animationDuration;
|
private int animationDuration;
|
||||||
|
@ -359,14 +365,69 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
|
|
||||||
powers.tick();
|
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();
|
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;
|
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() {
|
public Optional<BlockPos> getHangingPosition() {
|
||||||
return entity.getDataTracker().get(HANGING_POSITION);
|
return entity.getDataTracker().get(HANGING_POSITION);
|
||||||
}
|
}
|
||||||
|
@ -410,6 +471,17 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateAnimations() {
|
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) {
|
if (animationDuration > 0 && --animationDuration <= 0) {
|
||||||
setAnimation(AnimationInstance.NONE);
|
setAnimation(AnimationInstance.NONE);
|
||||||
}
|
}
|
||||||
|
@ -422,8 +494,10 @@ public class Pony extends Living<PlayerEntity> implements Copyable<Pony>, Update
|
||||||
|
|
||||||
if (isHanging()) {
|
if (isHanging()) {
|
||||||
((LivingEntityDuck)entity).setLeaningPitch(0);
|
((LivingEntityDuck)entity).setLeaningPitch(0);
|
||||||
if (!isClient() && (getObservedSpecies() != Race.BAT || (ticksHanging++ > 2 && getHangingPosition().filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty()))) {
|
if (!getObservedSpecies().canHang() || (ticksHanging++ > 2 && getHangingPosition().filter(getOrigin().down()::equals).filter(this::canHangAt).isEmpty())) {
|
||||||
stopHanging();
|
if (!isClient()) {
|
||||||
|
stopHanging();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ticksHanging = 0;
|
ticksHanging = 0;
|
||||||
|
|
Loading…
Reference in a new issue