mirror of
https://github.com/Sollace/Unicopia.git
synced 2025-02-24 21:54:33 +01:00
Fix janky hot air balloon physics
This commit is contained in:
parent
93d11531d6
commit
fbe444b56c
6 changed files with 313 additions and 233 deletions
|
@ -167,8 +167,6 @@ public class WorldRenderDelegate {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pony.updateSupportingEntity();
|
|
||||||
|
|
||||||
matrices.push();
|
matrices.push();
|
||||||
|
|
||||||
Entity owner = pony.asEntity();
|
Entity owner = pony.asEntity();
|
||||||
|
|
|
@ -20,7 +20,6 @@ import com.minelittlepony.unicopia.advancement.UCriteria;
|
||||||
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
|
import com.minelittlepony.unicopia.compat.trinkets.TrinketsDelegate;
|
||||||
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
|
import com.minelittlepony.unicopia.entity.behaviour.EntityAppearance;
|
||||||
import com.minelittlepony.unicopia.entity.behaviour.Guest;
|
import com.minelittlepony.unicopia.entity.behaviour.Guest;
|
||||||
import com.minelittlepony.unicopia.entity.collision.MultiBoundingBoxEntity;
|
|
||||||
import com.minelittlepony.unicopia.entity.damage.MagicalDamageSource;
|
import com.minelittlepony.unicopia.entity.damage.MagicalDamageSource;
|
||||||
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck;
|
import com.minelittlepony.unicopia.entity.duck.LivingEntityDuck;
|
||||||
import com.minelittlepony.unicopia.entity.effect.CorruptInfluenceStatusEffect;
|
import com.minelittlepony.unicopia.entity.effect.CorruptInfluenceStatusEffect;
|
||||||
|
@ -67,7 +66,6 @@ import net.minecraft.sound.SoundCategory;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.hit.BlockHitResult;
|
import net.minecraft.util.hit.BlockHitResult;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Box;
|
|
||||||
import net.minecraft.util.math.Direction;
|
import net.minecraft.util.math.Direction;
|
||||||
import net.minecraft.util.math.MathHelper;
|
import net.minecraft.util.math.MathHelper;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
@ -88,14 +86,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
private boolean invisible = false;
|
private boolean invisible = false;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Entity supportingEntity;
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
private Vec3d supportPositionOffset;
|
|
||||||
private int ticksOutsideVehicle;
|
|
||||||
private int ticksInVehicle;
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private Caster<?> attacker;
|
private Caster<?> attacker;
|
||||||
@Nullable
|
@Nullable
|
||||||
|
@ -109,6 +99,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
private final Enchantments enchants = addTicker(new Enchantments(this));
|
private final Enchantments enchants = addTicker(new Enchantments(this));
|
||||||
private final ItemTracker armour = addTicker(new ItemTracker(this));
|
private final ItemTracker armour = addTicker(new ItemTracker(this));
|
||||||
|
//private final Transportation<T> transportation = new Transportation<>(this);
|
||||||
|
private final Transportation<T> transportation = new Transportation<>(this);
|
||||||
|
|
||||||
protected Living(T entity, TrackedData<NbtCompound> effect) {
|
protected Living(T entity, TrackedData<NbtCompound> effect) {
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
|
@ -171,6 +163,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
return armour;
|
return armour;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Transportation<T> getTransportation() {
|
||||||
|
return transportation;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final T asEntity() {
|
public final T asEntity() {
|
||||||
return entity;
|
return entity;
|
||||||
|
@ -202,73 +198,6 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
return vehicle != null && getCarrierId().filter(vehicle.getUuid()::equals).isPresent();
|
return vehicle != null && getCarrierId().filter(vehicle.getUuid()::equals).isPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setSupportingEntity(@Nullable Entity supportingEntity) {
|
|
||||||
this.supportingEntity = supportingEntity;
|
|
||||||
if (supportingEntity != null) {
|
|
||||||
ticksOutsideVehicle = 0;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public Entity getSupportingEntity() {
|
|
||||||
return supportingEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getTicksInVehicle() {
|
|
||||||
return ticksInVehicle;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPositionOffset(@Nullable Vec3d positionOffset) {
|
|
||||||
this.supportPositionOffset = positionOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updatePositionOffset() {
|
|
||||||
setPositionOffset(supportingEntity == null ? null : entity.getPos().subtract(supportingEntity.getPos()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateRelativePosition(Box box) {
|
|
||||||
if (supportingEntity == null || supportPositionOffset == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (getPhysics().isFlying()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3d newPos = supportingEntity.getPos().add(supportPositionOffset);
|
|
||||||
Vec3d posChange = entity.getPos().subtract(newPos);
|
|
||||||
entity.setPosition(newPos);
|
|
||||||
if (isClient()) {
|
|
||||||
Vec3d newServerPos = LivingEntityDuck.serverPos(entity);
|
|
||||||
if (newServerPos.lengthSquared() != 0) {
|
|
||||||
newServerPos = newServerPos.subtract(posChange);
|
|
||||||
entity.updateTrackedPositionAndAngles(
|
|
||||||
newServerPos.x, newServerPos.y, newServerPos.z,
|
|
||||||
entity.getYaw(), entity.getPitch(), 3, true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
entity.updateTrackedPosition(newPos.x, newPos.y, newPos.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(entity instanceof PlayerEntity)) {
|
|
||||||
entity.lastRenderX = supportingEntity.lastRenderX + supportPositionOffset.x;
|
|
||||||
entity.lastRenderY = supportingEntity.lastRenderY + supportPositionOffset.y;
|
|
||||||
entity.lastRenderZ = supportingEntity.lastRenderZ + supportPositionOffset.z;
|
|
||||||
|
|
||||||
if (entity.getVelocity().length() < 0.1) {
|
|
||||||
LimbAnimationUtil.resetToZero(entity.limbAnimator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.horizontalSpeed = 0;
|
|
||||||
entity.prevHorizontalSpeed = 0;
|
|
||||||
entity.speed = 0;
|
|
||||||
entity.setOnGround(true);
|
|
||||||
entity.verticalCollision = true;
|
|
||||||
entity.groundCollision = true;
|
|
||||||
entity.fallDistance = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean beforeUpdate() {
|
public boolean beforeUpdate() {
|
||||||
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
if (EffectUtils.getAmplifier(entity, UEffects.PARALYSIS) > 1 && entity.getVelocity().horizontalLengthSquared() > 0) {
|
||||||
|
@ -276,44 +205,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
updateVelocity();
|
updateVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSupportingEntity();
|
//transportation.updateSupportingEntity();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateSupportingEntity() {
|
|
||||||
if (supportingEntity != null) {
|
|
||||||
Box ownBox = entity.getBoundingBox()
|
|
||||||
.stretch(entity.getVelocity())
|
|
||||||
.expand(0.1, 0.5, 0.1)
|
|
||||||
.stretch(supportingEntity.getVelocity().multiply(-2));
|
|
||||||
|
|
||||||
MultiBoundingBoxEntity.getBoundingBoxes(supportingEntity).stream()
|
|
||||||
.filter(box -> box.stretch(supportingEntity.getVelocity()).expand(0, 0.5, 0).intersects(ownBox))
|
|
||||||
.findFirst()
|
|
||||||
.ifPresentOrElse(box -> {
|
|
||||||
ticksOutsideVehicle = 0;
|
|
||||||
if (supportPositionOffset == null) {
|
|
||||||
updatePositionOffset();
|
|
||||||
} else {
|
|
||||||
updateRelativePosition(box);
|
|
||||||
}
|
|
||||||
entity.setOnGround(true);
|
|
||||||
entity.verticalCollision = true;
|
|
||||||
entity.groundCollision = true;
|
|
||||||
}, () -> {
|
|
||||||
// Rubberband passengers to try and prevent players falling out when the velocity changes suddenly
|
|
||||||
if (ticksOutsideVehicle++ > 30) {
|
|
||||||
supportingEntity = null;
|
|
||||||
supportPositionOffset = null;
|
|
||||||
Unicopia.LOGGER.info("Entity left vehicle");
|
|
||||||
} else {
|
|
||||||
supportPositionOffset = supportPositionOffset.multiply(0.25, 1, 0.25);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
tickers.forEach(Tickable::tick);
|
tickers.forEach(Tickable::tick);
|
||||||
|
@ -358,13 +253,7 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
|
||||||
|
|
||||||
updateDragonBreath();
|
updateDragonBreath();
|
||||||
|
|
||||||
if (ticksOutsideVehicle == 0) {
|
transportation.tick();
|
||||||
updatePositionOffset();
|
|
||||||
|
|
||||||
ticksInVehicle++;
|
|
||||||
} else {
|
|
||||||
ticksInVehicle = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
|
public void updateAttributeModifier(UUID id, EntityAttribute attribute, float desiredValue, Float2ObjectFunction<EntityAttributeModifier> modifierSupplier, boolean permanent) {
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
package com.minelittlepony.unicopia.entity;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.advancement.UCriteria;
|
||||||
|
import com.minelittlepony.unicopia.entity.collision.MultiBoundingBoxEntity;
|
||||||
|
import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
||||||
|
import com.minelittlepony.unicopia.entity.mob.AirBalloonEntity;
|
||||||
|
import com.minelittlepony.unicopia.util.Tickable;
|
||||||
|
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.LivingEntity;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.util.math.MathHelper;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
|
||||||
|
public class Transportation<T extends LivingEntity> implements Tickable {
|
||||||
|
|
||||||
|
private final Living<T> living;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private MultiBoundingBoxEntity vehicle;
|
||||||
|
@Nullable
|
||||||
|
private Entity vehicleEntity;
|
||||||
|
@Nullable
|
||||||
|
private Box vehicleBox;
|
||||||
|
|
||||||
|
private int ticksInVehicle;
|
||||||
|
|
||||||
|
private Vec3d lastVehiclePosition = Vec3d.ZERO;
|
||||||
|
|
||||||
|
Transportation(Living<T> living) {
|
||||||
|
this.living = living;
|
||||||
|
}
|
||||||
|
|
||||||
|
public <E extends Entity & MultiBoundingBoxEntity> void setVehicle(@Nullable E vehicle) {
|
||||||
|
this.vehicle = vehicle;
|
||||||
|
this.vehicleEntity = vehicle;
|
||||||
|
updatePreviousPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
if (vehicle != null) {
|
||||||
|
ticksInVehicle++;
|
||||||
|
} else {
|
||||||
|
ticksInVehicle = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ticksInVehicle > 20 && vehicle instanceof AirBalloonEntity) {
|
||||||
|
UCriteria.RIDE_BALLOON.trigger(living.asEntity());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updatePreviousPosition() {
|
||||||
|
vehicleBox = getVehicleBox();
|
||||||
|
lastVehiclePosition = vehicleEntity == null ? Vec3d.ZERO : vehicleEntity.getPos();
|
||||||
|
Entity entity = living.asEntity();
|
||||||
|
if (vehicleBox != null && living.asEntity().getBoundingBox().intersects(vehicleBox.expand(0.001, 0.5001, 0.001))) {
|
||||||
|
entity.setOnGround(true);
|
||||||
|
entity.onLanding();
|
||||||
|
entity.verticalCollision = true;
|
||||||
|
entity.groundCollision = true;
|
||||||
|
entity.velocityDirty = true;
|
||||||
|
entity.velocityModified = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onMove(MovementType movementType) {
|
||||||
|
if (vehicleBox == null || vehicleEntity == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entity entity = living.asEntity();
|
||||||
|
|
||||||
|
Box passengerBox = entity.getBoundingBox().expand(0.001);
|
||||||
|
Vec3d vehicleMovement = vehicleEntity.getPos().subtract(lastVehiclePosition);
|
||||||
|
|
||||||
|
List<VoxelShape> shapes = new ArrayList<>();
|
||||||
|
vehicle.getCollissionShapes(ShapeContext.of(entity), shapes::add);
|
||||||
|
vehicleMovement = vehicleMovement.add(vehicleEntity.getVelocity());
|
||||||
|
vehicleMovement = Entity.adjustMovementForCollisions(entity, vehicleMovement, passengerBox, entity.getWorld(), shapes);
|
||||||
|
|
||||||
|
Vec3d newPos = entity.getPos().add(vehicleMovement);
|
||||||
|
|
||||||
|
if (!vehicleEntity.isOnGround()) {
|
||||||
|
// surface check to prevent the player from floating
|
||||||
|
if (newPos.getY() > vehicleBox.minY + 0.1 || newPos.getY() < vehicleBox.minY + 0.1) {
|
||||||
|
newPos = new Vec3d(newPos.getX(), vehicleBox.minY + 0.01, newPos.getZ());
|
||||||
|
}
|
||||||
|
// containment checks to prevent the player from falling out of the basket when in flight
|
||||||
|
if (newPos.getY() < vehicleEntity.getPos().getY() + 3) {
|
||||||
|
double maxDeviation = 0.1;
|
||||||
|
double z = MathHelper.clamp(newPos.getZ(), vehicleBox.minZ + maxDeviation, vehicleBox.maxZ - maxDeviation);
|
||||||
|
double x = MathHelper.clamp(newPos.getX(), vehicleBox.minX + maxDeviation, vehicleBox.maxX - maxDeviation);
|
||||||
|
|
||||||
|
newPos = new Vec3d(x, newPos.getY(), z);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setPosition(newPos);
|
||||||
|
entity.updateTrackedPosition(newPos.x, newPos.y, newPos.z);
|
||||||
|
entity.setVelocity(Vec3d.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setOnGround(true);
|
||||||
|
entity.onLanding();
|
||||||
|
entity.verticalCollision = true;
|
||||||
|
entity.groundCollision = true;
|
||||||
|
|
||||||
|
if (entity.distanceTraveled > ((EntityDuck)entity).getNextStepSoundDistance()) {
|
||||||
|
entity.distanceTraveled -= 0.5;
|
||||||
|
entity.playSound(vehicle.getWalkedOnSound(entity.getY()), 0.5F, 1);
|
||||||
|
if (!entity.isSneaky()) {
|
||||||
|
entity.getWorld().emitGameEvent(entity, GameEvent.STEP, entity.getBlockPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Box getVehicleBox() {
|
||||||
|
if (vehicle == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Box entityBox = living.asEntity().getBoundingBox().stretch(living.asEntity().getVelocity());
|
||||||
|
for (Box box : vehicle.getGravityZoneBoxes()) {
|
||||||
|
if (entityBox.intersects(box.expand(0.001).stretch(vehicleEntity.getVelocity().multiply(1)))) {
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setVehicle(null);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,37 @@
|
||||||
package com.minelittlepony.unicopia.entity.collision;
|
package com.minelittlepony.unicopia.entity.collision;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import com.minelittlepony.unicopia.entity.collision.EntityCollisions.ComplexCollidable;
|
||||||
|
|
||||||
|
import net.minecraft.block.ShapeContext;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
import net.minecraft.util.math.Box;
|
import net.minecraft.util.math.Box;
|
||||||
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
|
import net.minecraft.util.shape.VoxelShapes;
|
||||||
|
|
||||||
public interface MultiBoundingBoxEntity {
|
public interface MultiBoundingBoxEntity extends ComplexCollidable {
|
||||||
List<Box> getBoundingBoxes();
|
List<Box> getBoundingBoxes();
|
||||||
|
|
||||||
|
default List<Box> getGravityZoneBoxes() {
|
||||||
|
return getBoundingBoxes();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Box, List<Entity>> getCollidingEntities(Stream<Box> boundingBoxes);
|
||||||
|
|
||||||
|
SoundEvent getWalkedOnSound(double y);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
|
||||||
|
for (Box box : getBoundingBoxes()) {
|
||||||
|
output.accept(VoxelShapes.cuboid(box));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static List<Box> getBoundingBoxes(Entity entity) {
|
static List<Box> getBoundingBoxes(Entity entity) {
|
||||||
return entity instanceof MultiBoundingBoxEntity multi ? multi.getBoundingBoxes() : List.of(entity.getBoundingBox());
|
return entity instanceof MultiBoundingBoxEntity multi ? multi.getBoundingBoxes() : List.of(entity.getBoundingBox());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,9 @@ import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.item.Items;
|
import net.minecraft.item.Items;
|
||||||
import net.minecraft.nbt.NbtCompound;
|
import net.minecraft.nbt.NbtCompound;
|
||||||
import net.minecraft.particle.ParticleTypes;
|
import net.minecraft.particle.ParticleTypes;
|
||||||
|
import net.minecraft.predicate.entity.EntityPredicates;
|
||||||
import net.minecraft.registry.RegistryKey;
|
import net.minecraft.registry.RegistryKey;
|
||||||
|
import net.minecraft.sound.SoundEvent;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.Hand;
|
import net.minecraft.util.Hand;
|
||||||
import net.minecraft.util.Identifier;
|
import net.minecraft.util.Identifier;
|
||||||
|
@ -22,20 +24,22 @@ import net.minecraft.util.function.ValueLists;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.math.*;
|
||||||
import net.minecraft.util.math.random.Random;
|
import net.minecraft.util.math.random.Random;
|
||||||
import net.minecraft.util.shape.VoxelShape;
|
import net.minecraft.util.shape.VoxelShape;
|
||||||
import net.minecraft.util.shape.VoxelShapes;
|
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.event.GameEvent;
|
import net.minecraft.world.event.GameEvent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.function.Function;
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.function.IntFunction;
|
import java.util.function.IntFunction;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import com.minelittlepony.unicopia.EquineContext;
|
import com.minelittlepony.unicopia.EquineContext;
|
||||||
|
@ -47,7 +51,6 @@ import com.minelittlepony.unicopia.entity.MagicImmune;
|
||||||
import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
|
import com.minelittlepony.unicopia.entity.collision.EntityCollisions;
|
||||||
import com.minelittlepony.unicopia.entity.collision.MultiBoundingBoxEntity;
|
import com.minelittlepony.unicopia.entity.collision.MultiBoundingBoxEntity;
|
||||||
import com.minelittlepony.unicopia.entity.collision.MultiBox;
|
import com.minelittlepony.unicopia.entity.collision.MultiBox;
|
||||||
import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
|
||||||
import com.minelittlepony.unicopia.item.BasketItem;
|
import com.minelittlepony.unicopia.item.BasketItem;
|
||||||
import com.minelittlepony.unicopia.item.HotAirBalloonItem;
|
import com.minelittlepony.unicopia.item.HotAirBalloonItem;
|
||||||
import com.minelittlepony.unicopia.item.UItems;
|
import com.minelittlepony.unicopia.item.UItems;
|
||||||
|
@ -61,13 +64,14 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
private static final TrackedData<String> BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.STRING);
|
private static final TrackedData<String> BASKET_TYPE = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.STRING);
|
||||||
private static final TrackedData<Integer> BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
private static final TrackedData<Integer> BALLOON_DESIGN = DataTracker.registerData(AirBalloonEntity.class, TrackedDataHandlerRegistry.INTEGER);
|
||||||
|
|
||||||
|
private static final Predicate<Entity> RIDER_PREDICATE = EntityPredicates.EXCEPT_SPECTATOR.and(e -> {
|
||||||
|
return !(e instanceof PlayerEntity p && p.getAbilities().flying);
|
||||||
|
});
|
||||||
|
|
||||||
private boolean prevBoosting;
|
private boolean prevBoosting;
|
||||||
private int prevInflation;
|
private int prevInflation;
|
||||||
private Vec3d oldPosition = Vec3d.ZERO;
|
|
||||||
private Vec3d manualVelocity = Vec3d.ZERO;
|
private Vec3d manualVelocity = Vec3d.ZERO;
|
||||||
|
|
||||||
private int ticksFlying;
|
|
||||||
|
|
||||||
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
public AirBalloonEntity(EntityType<? extends AirBalloonEntity> type, World world) {
|
||||||
super(type, world);
|
super(type, world);
|
||||||
intersectionChecked = true;
|
intersectionChecked = true;
|
||||||
|
@ -80,12 +84,12 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
dataTracker.startTracking(ASCENDING, false);
|
dataTracker.startTracking(ASCENDING, false);
|
||||||
dataTracker.startTracking(BOOSTING, 0);
|
dataTracker.startTracking(BOOSTING, 0);
|
||||||
dataTracker.startTracking(INFLATION, 0);
|
dataTracker.startTracking(INFLATION, 0);
|
||||||
dataTracker.startTracking(BASKET_TYPE, "");
|
dataTracker.startTracking(BASKET_TYPE, BasketType.DEFAULT.id().toString());
|
||||||
dataTracker.startTracking(BALLOON_DESIGN, 0);
|
dataTracker.startTracking(BALLOON_DESIGN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BasketType getBasketType() {
|
public BasketType getBasketType() {
|
||||||
return BasketType.REGISTRY.get(Identifier.tryParse(dataTracker.get(BASKET_TYPE)));
|
return BasketType.of(dataTracker.get(BASKET_TYPE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBasketType(BasketType type) {
|
public void setBasketType(BasketType type) {
|
||||||
|
@ -144,14 +148,6 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
return hasBalloon() && hasBurner() && getInflation() >= getMaxInflation();
|
return hasBalloon() && hasBurner() && getInflation() >= getMaxInflation();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Box> getBoundingBoxes() {
|
|
||||||
if (hasBalloon() && getInflation(1) > 0.999F) {
|
|
||||||
return List.of(getInteriorBoundingBox(), getBalloonBoundingBox());
|
|
||||||
}
|
|
||||||
return List.of(getInteriorBoundingBox());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick() {
|
public void tick() {
|
||||||
setAir(getMaxAir());
|
setAir(getMaxAir());
|
||||||
|
@ -248,86 +244,12 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
}
|
}
|
||||||
|
|
||||||
prevBoosting = boosting;
|
prevBoosting = boosting;
|
||||||
oldPosition = getPos();
|
|
||||||
|
|
||||||
if (getFireTicks() > 0) {
|
if (getFireTicks() > 0) {
|
||||||
setFireTicks(1);
|
setFireTicks(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isOnGround() && (isAirworthy() || isSubmergedInWater() || isLeashed())) {
|
|
||||||
ticksFlying++;
|
|
||||||
} else {
|
|
||||||
ticksFlying = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePassengers(false);
|
|
||||||
super.tick();
|
super.tick();
|
||||||
setBoundingBox(MultiBox.of(getBoundingBox(), getBoundingBoxes()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePassengers(boolean move) {
|
|
||||||
Set<Entity> alreadyTicked = new HashSet<>();
|
|
||||||
for (Box box : getBoundingBoxes()) {
|
|
||||||
for (Entity e : getWorld().getOtherEntities(this, box.stretch(getVelocity().multiply(-1)).expand(0, 0.5, 0))) {
|
|
||||||
|
|
||||||
if (e instanceof PlayerEntity p && p.getAbilities().flying) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!alreadyTicked.add(e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
updatePassenger(e, box, e.getY() > getY() + 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updatePassenger(Entity e, Box box, boolean inBalloon) {
|
|
||||||
|
|
||||||
if (e instanceof AirBalloonEntity) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ticksFlying > 0) {
|
|
||||||
if (Living.getOrEmpty(e).filter(living -> !living.setSupportingEntity(this)).isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3d vel = getVelocity();
|
|
||||||
|
|
||||||
double height = box.getYLength();
|
|
||||||
|
|
||||||
if (height < 3 || e.getBoundingBox().minY > box.minY + height / 2D) {
|
|
||||||
if (vel.y > 0 && e.getBoundingBox().minY < box.maxY + 0.02) {
|
|
||||||
e.setPos(e.getX(), box.maxY, e.getZ());
|
|
||||||
e.setOnGround(true);
|
|
||||||
}
|
|
||||||
if (vel.y < 0 && e.getBoundingBox().minY > box.maxY) {
|
|
||||||
e.setPos(e.getX(), box.maxY, e.getZ());
|
|
||||||
e.setOnGround(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Living.getOrEmpty(e).ifPresent(living -> {
|
|
||||||
living.setPositionOffset(e.getPos().subtract(oldPosition));
|
|
||||||
living.updateRelativePosition(box);
|
|
||||||
|
|
||||||
if (ticksFlying > 20 && living.getTicksInVehicle() > 20) {
|
|
||||||
UCriteria.RIDE_BALLOON.trigger(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getWorld().isClient) {
|
|
||||||
if (e.distanceTraveled > ((EntityDuck)e).getNextStepSoundDistance()) {
|
|
||||||
e.distanceTraveled--;
|
|
||||||
e.playSound(inBalloon ? USounds.ENTITY_HOT_AIR_BALLOON_STEP : USounds.ENTITY_HOT_AIR_BALLOON_BASKET_STEP, 0.5F, 1);
|
|
||||||
if (!e.isSneaky()) {
|
|
||||||
getWorld().emitGameEvent(e, GameEvent.STEP, getBlockPos());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -459,12 +381,16 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void fall(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) {
|
public Race getSpecies() {
|
||||||
|
return Race.UNSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Race getSpecies() {
|
public SoundEvent getWalkedOnSound(double y) {
|
||||||
return Race.UNSET;
|
if (y >= getBalloonBoundingBox().minY) {
|
||||||
|
return USounds.ENTITY_HOT_AIR_BALLOON_STEP;
|
||||||
|
}
|
||||||
|
return USounds.ENTITY_HOT_AIR_BALLOON_BASKET_STEP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -497,6 +423,18 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
move(MovementType.SELF, getVelocity());
|
move(MovementType.SELF, getVelocity());
|
||||||
setVelocity(getVelocity().multiply(slipperyness));
|
setVelocity(getVelocity().multiply(slipperyness));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Map<Box, List<Entity>> collidingEntities = getCollidingEntities(getBoundingBoxes().stream());
|
||||||
|
|
||||||
|
for (Map.Entry<Box, List<Entity>> passengers : collidingEntities.entrySet()) {
|
||||||
|
for (Entity passenger : passengers.getValue()) {
|
||||||
|
Living<?> living = Living.living(passenger);
|
||||||
|
if (living != null) {
|
||||||
|
living.getTransportation().setVehicle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
updateLimbs(false);
|
updateLimbs(false);
|
||||||
}
|
}
|
||||||
|
@ -507,17 +445,22 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Box calculateBoundingBox() {
|
||||||
|
return MultiBox.of(super.calculateBoundingBox(), getBoundingBoxes());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Box getVisibilityBoundingBox() {
|
public Box getVisibilityBoundingBox() {
|
||||||
if (hasBalloon()) {
|
if (hasBalloon()) {
|
||||||
return MultiBox.unbox(getBoundingBox()).union(getBalloonBoundingBox());
|
return getBalloonBoundingBox().withMinY(getY());
|
||||||
}
|
}
|
||||||
return MultiBox.unbox(getBoundingBox());
|
return getInteriorBoundingBox();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Box getInteriorBoundingBox() {
|
protected Box getInteriorBoundingBox() {
|
||||||
Box box = MultiBox.unbox(getBoundingBox());
|
Box box = MultiBox.unbox(getBoundingBox());
|
||||||
return box.withMinY(box.minY - 0.2).contract(0.2, 0, 0.2);
|
return box.withMinY(box.minY - 0.05).contract(0.15, 0, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Box getBalloonBoundingBox() {
|
protected Box getBalloonBoundingBox() {
|
||||||
|
@ -528,34 +471,96 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void getCollissionShapes(ShapeContext context, Consumer<VoxelShape> output) {
|
public List<Box> getGravityZoneBoxes() {
|
||||||
|
Box balloon = getBalloonBoundingBox().expand(0.001);
|
||||||
|
Box interior = getInteriorBoundingBox().expand(0.001);
|
||||||
|
return List.of(
|
||||||
|
// interior - basket to top of balloon
|
||||||
|
interior.withMaxY(balloon.minY).withMinY(interior.maxY),
|
||||||
|
// balloon
|
||||||
|
balloon.withMaxY(balloon.maxY + 0.5).withMinY(balloon.maxY)
|
||||||
|
);
|
||||||
|
|
||||||
Box box = MultiBox.unbox(getBoundingBox()).expand(0.3, 0, 0.3);
|
}
|
||||||
|
|
||||||
double wallheight = box.maxY + 0.7;
|
@Override
|
||||||
double wallThickness = 0.7;
|
public List<Box> getBoundingBoxes() {
|
||||||
|
List<Box> boxes = new ArrayList<>();
|
||||||
|
Box box = getInteriorBoundingBox();
|
||||||
|
boxes.add(box);
|
||||||
|
|
||||||
|
double wallheight = box.maxY + 0.72;
|
||||||
|
double wallThickness = 0.2;
|
||||||
|
|
||||||
if (!getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
if (!getBasketType().isOf(BoatEntity.Type.BAMBOO)) {
|
||||||
// front left (next to door)
|
// front left (next to door)
|
||||||
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness + 0.2, wallheight, box.minZ + wallThickness)));
|
boxes.add(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness + 0.4, wallheight, box.minZ + wallThickness));
|
||||||
// front right (next to door)
|
// front right (next to door)
|
||||||
output.accept(VoxelShapes.cuboid(new Box(box.maxX - wallThickness - 0.2, box.minY, box.minZ, box.maxX, wallheight, box.minZ + wallThickness)));
|
boxes.add(new Box(box.maxX - wallThickness - 0.4, box.minY, box.minZ, box.maxX, wallheight, box.minZ + wallThickness));
|
||||||
|
|
||||||
// back
|
// back
|
||||||
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.maxZ - wallThickness, box.maxX, wallheight, box.maxZ)));
|
boxes.add(new Box(box.minX, box.minY, box.maxZ - wallThickness, box.maxX, wallheight, box.maxZ));
|
||||||
|
|
||||||
// left
|
// left
|
||||||
output.accept(VoxelShapes.cuboid(new Box(box.maxX - wallThickness, box.minY, box.minZ, box.maxX, wallheight, box.maxZ)));
|
boxes.add(new Box(box.maxX - wallThickness, box.minY, box.minZ, box.maxX, wallheight, box.maxZ));
|
||||||
// right
|
// right
|
||||||
output.accept(VoxelShapes.cuboid(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness, wallheight, box.maxZ)));
|
boxes.add(new Box(box.minX, box.minY, box.minZ, box.minX + wallThickness, wallheight, box.maxZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
// top of balloon
|
if (hasBalloon() && getInflation(1) > 0.999F) {
|
||||||
if (hasBalloon() && getInflation() > 0) {
|
boxes.add(getBalloonBoundingBox());
|
||||||
output.accept(VoxelShapes.cuboid(getBalloonBoundingBox()));
|
}
|
||||||
|
return boxes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void move(MovementType movementType, Vec3d movement) {
|
||||||
|
Vec3d oldPos = this.getPos();
|
||||||
|
List<Box> boundingBoxes = getGravityZoneBoxes();
|
||||||
|
super.move(movementType, movement);
|
||||||
|
if (movementType == MovementType.SELF) {
|
||||||
|
Vec3d actualMovement = getPos().subtract(oldPos);
|
||||||
|
Map<Box, List<Entity>> collidingEntities = getCollidingEntities(
|
||||||
|
boundingBoxes.stream().map(box -> box.stretch(actualMovement))
|
||||||
|
);
|
||||||
|
|
||||||
|
for (Map.Entry<Box, List<Entity>> passengers : collidingEntities.entrySet()) {
|
||||||
|
for (Entity passenger : passengers.getValue()) {
|
||||||
|
movePassenger(passenger, actualMovement);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void movePassenger(Entity passenger, Vec3d movement) {
|
||||||
|
Living<?> living = Living.living(passenger);
|
||||||
|
if (living != null) {
|
||||||
|
if (living.getPhysics().isGravityNegative()) {
|
||||||
|
movement = movement.multiply(1, -1, 1);
|
||||||
|
}
|
||||||
|
living.getTransportation().setVehicle(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<VoxelShape> shapes = new ArrayList<>();
|
||||||
|
getCollissionShapes(ShapeContext.of(passenger), shapes::add);
|
||||||
|
movement = Entity.adjustMovementForCollisions(passenger, movement, passenger.getBoundingBox(), getWorld(), shapes);
|
||||||
|
|
||||||
|
passenger.setPosition(passenger.getPos().add(movement));
|
||||||
|
passenger.updateTrackedPosition(passenger.getX(), passenger.getY(), passenger.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<Box, List<Entity>> getCollidingEntities(Stream<Box> boundingBoxes) {
|
||||||
|
return boundingBoxes.collect(Collectors.toMap(Function.identity(), box -> {
|
||||||
|
return getWorld().getOtherEntities(this, box.expand(0.001).stretch(getVelocity().multiply(1)), RIDER_PREDICATE).stream().distinct().toList();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void fall(double heightDifference, boolean onGround, BlockState state, BlockPos landedPosition) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void readCustomDataFromNbt(NbtCompound compound) {
|
public void readCustomDataFromNbt(NbtCompound compound) {
|
||||||
super.readCustomDataFromNbt(compound);
|
super.readCustomDataFromNbt(compound);
|
||||||
|
@ -577,6 +582,10 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
compound.putInt("inflationAmount", getInflation());
|
compound.putInt("inflationAmount", getInflation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static boolean isBetween(double value, double min, double max) {
|
||||||
|
return value >= min && value <= max;
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public enum BalloonDesign implements StringIdentifiable {
|
public enum BalloonDesign implements StringIdentifiable {
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -607,6 +616,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
|
|
||||||
public record BasketType(Identifier id, @Nullable BoatEntity.Type boatType) {
|
public record BasketType(Identifier id, @Nullable BoatEntity.Type boatType) {
|
||||||
private static final Map<Identifier, BasketType> REGISTRY = new HashMap<>();
|
private static final Map<Identifier, BasketType> REGISTRY = new HashMap<>();
|
||||||
|
public static final BasketType DEFAULT = of(BoatEntity.Type.OAK);
|
||||||
static {
|
static {
|
||||||
Arrays.stream(BoatEntity.Type.values()).forEach(BasketType::of);
|
Arrays.stream(BoatEntity.Type.values()).forEach(BasketType::of);
|
||||||
}
|
}
|
||||||
|
@ -616,7 +626,7 @@ public class AirBalloonEntity extends MobEntity implements EntityCollisions.Comp
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BasketType of(String name) {
|
public static BasketType of(String name) {
|
||||||
Identifier id = Identifier.tryParse(name);
|
Identifier id = name == null || name.isEmpty() ? null : Identifier.tryParse(name);
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
return of(BoatEntity.Type.OAK);
|
return of(BoatEntity.Type.OAK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,13 @@ import com.minelittlepony.unicopia.entity.duck.EntityDuck;
|
||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.EntityType;
|
import net.minecraft.entity.EntityType;
|
||||||
import net.minecraft.entity.ItemEntity;
|
import net.minecraft.entity.ItemEntity;
|
||||||
|
import net.minecraft.entity.MovementType;
|
||||||
import net.minecraft.entity.Entity.PositionUpdater;
|
import net.minecraft.entity.Entity.PositionUpdater;
|
||||||
import net.minecraft.entity.Entity.RemovalReason;
|
import net.minecraft.entity.Entity.RemovalReason;
|
||||||
import net.minecraft.fluid.Fluid;
|
import net.minecraft.fluid.Fluid;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.registry.tag.TagKey;
|
import net.minecraft.registry.tag.TagKey;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
@Mixin(Entity.class)
|
@Mixin(Entity.class)
|
||||||
|
@ -118,4 +120,20 @@ abstract class MixinEntity implements EntityDuck {
|
||||||
info.setReturnValue(null);
|
info.setReturnValue(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Inject(method = "move", at = @At("HEAD"))
|
||||||
|
private void beforeMove(MovementType movementType, Vec3d movement, CallbackInfo info) {
|
||||||
|
Living<?> living = Living.living((Entity)(Object)this);
|
||||||
|
if (living != null) {
|
||||||
|
living.getTransportation().updatePreviousPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject(method = "move", at = @At("RETURN"))
|
||||||
|
private void afterMove(MovementType movementType, Vec3d movement, CallbackInfo info) {
|
||||||
|
Living<?> living = Living.living((Entity)(Object)this);
|
||||||
|
if (living != null) {
|
||||||
|
living.getTransportation().onMove(movementType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue