593 lines
18 KiB
Java
593 lines
18 KiB
Java
package net.minecraft.world.entity.vehicle;
|
|
|
|
import com.google.common.collect.ImmutableList;
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.datafixers.util.Pair;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import net.minecraft.Util;
|
|
import net.minecraft.BlockUtil.FoundRectangle;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Vec3i;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.NbtOps;
|
|
import net.minecraft.nbt.Tag;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.network.syncher.SynchedEntityData.Builder;
|
|
import net.minecraft.resources.RegistryOps;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityDimensions;
|
|
import net.minecraft.world.entity.EntitySpawnReason;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.InterpolationHandler;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.MoverType;
|
|
import net.minecraft.world.entity.Pose;
|
|
import net.minecraft.world.entity.npc.Villager;
|
|
import net.minecraft.world.entity.npc.WanderingTrader;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.flag.FeatureFlags;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.BaseRailBlock;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.PoweredRailBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.RailShape;
|
|
import net.minecraft.world.phys.AABB;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public abstract class AbstractMinecart extends VehicleEntity {
|
|
private static final Vec3 LOWERED_PASSENGER_ATTACHMENT = new Vec3(0.0, 0.0, 0.0);
|
|
private static final EntityDataAccessor<Optional<BlockState>> DATA_ID_CUSTOM_DISPLAY_BLOCK = SynchedEntityData.defineId(
|
|
AbstractMinecart.class, EntityDataSerializers.OPTIONAL_BLOCK_STATE
|
|
);
|
|
private static final EntityDataAccessor<Integer> DATA_ID_DISPLAY_OFFSET = SynchedEntityData.defineId(AbstractMinecart.class, EntityDataSerializers.INT);
|
|
private static final ImmutableMap<Pose, ImmutableList<Integer>> POSE_DISMOUNT_HEIGHTS = ImmutableMap.of(
|
|
Pose.STANDING, ImmutableList.of(0, 1, -1), Pose.CROUCHING, ImmutableList.of(0, 1, -1), Pose.SWIMMING, ImmutableList.of(0, 1)
|
|
);
|
|
protected static final float WATER_SLOWDOWN_FACTOR = 0.95F;
|
|
private static final boolean DEFAULT_FLIPPED_ROTATION = false;
|
|
private boolean onRails;
|
|
private boolean flipped = false;
|
|
private final MinecartBehavior behavior;
|
|
private static final Map<RailShape, Pair<Vec3i, Vec3i>> EXITS = Maps.newEnumMap(
|
|
Util.make(
|
|
() -> {
|
|
Vec3i vec3i = Direction.WEST.getUnitVec3i();
|
|
Vec3i vec3i2 = Direction.EAST.getUnitVec3i();
|
|
Vec3i vec3i3 = Direction.NORTH.getUnitVec3i();
|
|
Vec3i vec3i4 = Direction.SOUTH.getUnitVec3i();
|
|
Vec3i vec3i5 = vec3i.below();
|
|
Vec3i vec3i6 = vec3i2.below();
|
|
Vec3i vec3i7 = vec3i3.below();
|
|
Vec3i vec3i8 = vec3i4.below();
|
|
return ImmutableMap.of(
|
|
RailShape.NORTH_SOUTH,
|
|
Pair.of(vec3i3, vec3i4),
|
|
RailShape.EAST_WEST,
|
|
Pair.of(vec3i, vec3i2),
|
|
RailShape.ASCENDING_EAST,
|
|
Pair.of(vec3i5, vec3i2),
|
|
RailShape.ASCENDING_WEST,
|
|
Pair.of(vec3i, vec3i6),
|
|
RailShape.ASCENDING_NORTH,
|
|
Pair.of(vec3i3, vec3i8),
|
|
RailShape.ASCENDING_SOUTH,
|
|
Pair.of(vec3i7, vec3i4),
|
|
RailShape.SOUTH_EAST,
|
|
Pair.of(vec3i4, vec3i2),
|
|
RailShape.SOUTH_WEST,
|
|
Pair.of(vec3i4, vec3i),
|
|
RailShape.NORTH_WEST,
|
|
Pair.of(vec3i3, vec3i),
|
|
RailShape.NORTH_EAST,
|
|
Pair.of(vec3i3, vec3i2)
|
|
);
|
|
}
|
|
)
|
|
);
|
|
|
|
protected AbstractMinecart(EntityType<?> entityType, Level level) {
|
|
super(entityType, level);
|
|
this.blocksBuilding = true;
|
|
if (useExperimentalMovement(level)) {
|
|
this.behavior = new NewMinecartBehavior(this);
|
|
} else {
|
|
this.behavior = new OldMinecartBehavior(this);
|
|
}
|
|
}
|
|
|
|
protected AbstractMinecart(EntityType<?> entityType, Level level, double x, double y, double z) {
|
|
this(entityType, level);
|
|
this.setInitialPos(x, y, z);
|
|
}
|
|
|
|
public void setInitialPos(double x, double y, double z) {
|
|
this.setPos(x, y, z);
|
|
this.xo = x;
|
|
this.yo = y;
|
|
this.zo = z;
|
|
}
|
|
|
|
@Nullable
|
|
public static <T extends AbstractMinecart> T createMinecart(
|
|
Level level, double x, double y, double z, EntityType<T> type, EntitySpawnReason spawnReason, ItemStack spawnedFrom, @Nullable Player player
|
|
) {
|
|
T abstractMinecart = (T)type.create(level, spawnReason);
|
|
if (abstractMinecart != null) {
|
|
abstractMinecart.setInitialPos(x, y, z);
|
|
EntityType.createDefaultStackConfig(level, spawnedFrom, player).accept(abstractMinecart);
|
|
if (abstractMinecart.getBehavior() instanceof NewMinecartBehavior newMinecartBehavior) {
|
|
BlockPos blockPos = abstractMinecart.getCurrentBlockPosOrRailBelow();
|
|
BlockState blockState = level.getBlockState(blockPos);
|
|
newMinecartBehavior.adjustToRails(blockPos, blockState, true);
|
|
}
|
|
}
|
|
|
|
return abstractMinecart;
|
|
}
|
|
|
|
public MinecartBehavior getBehavior() {
|
|
return this.behavior;
|
|
}
|
|
|
|
@Override
|
|
protected Entity.MovementEmission getMovementEmission() {
|
|
return Entity.MovementEmission.EVENTS;
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData(Builder builder) {
|
|
super.defineSynchedData(builder);
|
|
builder.define(DATA_ID_CUSTOM_DISPLAY_BLOCK, Optional.empty());
|
|
builder.define(DATA_ID_DISPLAY_OFFSET, this.getDefaultDisplayOffset());
|
|
}
|
|
|
|
@Override
|
|
public boolean canCollideWith(Entity entity) {
|
|
return AbstractBoat.canVehicleCollide(this, entity);
|
|
}
|
|
|
|
@Override
|
|
public boolean isPushable() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getRelativePortalPosition(Direction.Axis axis, FoundRectangle portal) {
|
|
return LivingEntity.resetForwardDirectionOfRelativePortalPosition(super.getRelativePortalPosition(axis, portal));
|
|
}
|
|
|
|
@Override
|
|
protected Vec3 getPassengerAttachmentPoint(Entity entity, EntityDimensions dimensions, float partialTick) {
|
|
boolean bl = entity instanceof Villager || entity instanceof WanderingTrader;
|
|
return bl ? LOWERED_PASSENGER_ATTACHMENT : super.getPassengerAttachmentPoint(entity, dimensions, partialTick);
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getDismountLocationForPassenger(LivingEntity passenger) {
|
|
Direction direction = this.getMotionDirection();
|
|
if (direction.getAxis() == Direction.Axis.Y) {
|
|
return super.getDismountLocationForPassenger(passenger);
|
|
} else {
|
|
int[][] is = DismountHelper.offsetsForDirection(direction);
|
|
BlockPos blockPos = this.blockPosition();
|
|
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
ImmutableList<Pose> immutableList = passenger.getDismountPoses();
|
|
|
|
for (Pose pose : immutableList) {
|
|
EntityDimensions entityDimensions = passenger.getDimensions(pose);
|
|
float f = Math.min(entityDimensions.width(), 1.0F) / 2.0F;
|
|
|
|
for (int i : POSE_DISMOUNT_HEIGHTS.get(pose)) {
|
|
for (int[] js : is) {
|
|
mutableBlockPos.set(blockPos.getX() + js[0], blockPos.getY() + i, blockPos.getZ() + js[1]);
|
|
double d = this.level()
|
|
.getBlockFloorHeight(
|
|
DismountHelper.nonClimbableShape(this.level(), mutableBlockPos), () -> DismountHelper.nonClimbableShape(this.level(), mutableBlockPos.below())
|
|
);
|
|
if (DismountHelper.isBlockFloorValid(d)) {
|
|
AABB aABB = new AABB(-f, 0.0, -f, f, entityDimensions.height(), f);
|
|
Vec3 vec3 = Vec3.upFromBottomCenterOf(mutableBlockPos, d);
|
|
if (DismountHelper.canDismountTo(this.level(), passenger, aABB.move(vec3))) {
|
|
passenger.setPose(pose);
|
|
return vec3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
double e = this.getBoundingBox().maxY;
|
|
mutableBlockPos.set((double)blockPos.getX(), e, (double)blockPos.getZ());
|
|
|
|
for (Pose pose2 : immutableList) {
|
|
double g = passenger.getDimensions(pose2).height();
|
|
int j = Mth.ceil(e - mutableBlockPos.getY() + g);
|
|
double h = DismountHelper.findCeilingFrom(mutableBlockPos, j, blockPosx -> this.level().getBlockState(blockPosx).getCollisionShape(this.level(), blockPosx));
|
|
if (e + g <= h) {
|
|
passenger.setPose(pose2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return super.getDismountLocationForPassenger(passenger);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected float getBlockSpeedFactor() {
|
|
BlockState blockState = this.level().getBlockState(this.blockPosition());
|
|
return blockState.is(BlockTags.RAILS) ? 1.0F : super.getBlockSpeedFactor();
|
|
}
|
|
|
|
@Override
|
|
public void animateHurt(float yaw) {
|
|
this.setHurtDir(-this.getHurtDir());
|
|
this.setHurtTime(10);
|
|
this.setDamage(this.getDamage() + this.getDamage() * 10.0F);
|
|
}
|
|
|
|
@Override
|
|
public boolean isPickable() {
|
|
return !this.isRemoved();
|
|
}
|
|
|
|
public static Pair<Vec3i, Vec3i> exits(RailShape shape) {
|
|
return (Pair<Vec3i, Vec3i>)EXITS.get(shape);
|
|
}
|
|
|
|
@Override
|
|
public Direction getMotionDirection() {
|
|
return this.behavior.getMotionDirection();
|
|
}
|
|
|
|
@Override
|
|
protected double getDefaultGravity() {
|
|
return this.isInWater() ? 0.005 : 0.04;
|
|
}
|
|
|
|
@Override
|
|
public void tick() {
|
|
if (this.getHurtTime() > 0) {
|
|
this.setHurtTime(this.getHurtTime() - 1);
|
|
}
|
|
|
|
if (this.getDamage() > 0.0F) {
|
|
this.setDamage(this.getDamage() - 1.0F);
|
|
}
|
|
|
|
this.checkBelowWorld();
|
|
this.handlePortal();
|
|
this.behavior.tick();
|
|
this.updateInWaterStateAndDoFluidPushing();
|
|
if (this.isInLava()) {
|
|
this.lavaIgnite();
|
|
this.lavaHurt();
|
|
this.fallDistance *= 0.5;
|
|
}
|
|
|
|
this.firstTick = false;
|
|
}
|
|
|
|
public boolean isFirstTick() {
|
|
return this.firstTick;
|
|
}
|
|
|
|
public BlockPos getCurrentBlockPosOrRailBelow() {
|
|
int i = Mth.floor(this.getX());
|
|
int j = Mth.floor(this.getY());
|
|
int k = Mth.floor(this.getZ());
|
|
if (useExperimentalMovement(this.level())) {
|
|
double d = this.getY() - 0.1 - 1.0E-5F;
|
|
if (this.level().getBlockState(BlockPos.containing(i, d, k)).is(BlockTags.RAILS)) {
|
|
j = Mth.floor(d);
|
|
}
|
|
} else if (this.level().getBlockState(new BlockPos(i, j - 1, k)).is(BlockTags.RAILS)) {
|
|
j--;
|
|
}
|
|
|
|
return new BlockPos(i, j, k);
|
|
}
|
|
|
|
protected double getMaxSpeed(ServerLevel level) {
|
|
return this.behavior.getMaxSpeed(level);
|
|
}
|
|
|
|
/**
|
|
* Called every tick the minecart is on an activator rail.
|
|
*/
|
|
public void activateMinecart(int x, int y, int z, boolean powered) {
|
|
}
|
|
|
|
@Override
|
|
public void lerpPositionAndRotationStep(int steps, double targetX, double targetY, double targetZ, double targetYRot, double targetXRot) {
|
|
super.lerpPositionAndRotationStep(steps, targetX, targetY, targetZ, targetYRot, targetXRot);
|
|
}
|
|
|
|
@Override
|
|
public void applyGravity() {
|
|
super.applyGravity();
|
|
}
|
|
|
|
@Override
|
|
public void reapplyPosition() {
|
|
super.reapplyPosition();
|
|
}
|
|
|
|
@Override
|
|
public boolean updateInWaterStateAndDoFluidPushing() {
|
|
return super.updateInWaterStateAndDoFluidPushing();
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getKnownMovement() {
|
|
return this.behavior.getKnownMovement(super.getKnownMovement());
|
|
}
|
|
|
|
@Override
|
|
public InterpolationHandler getInterpolation() {
|
|
return this.behavior.getInterpolation();
|
|
}
|
|
|
|
@Override
|
|
public void lerpMotion(double x, double y, double z) {
|
|
this.behavior.lerpMotion(x, y, z);
|
|
}
|
|
|
|
protected void moveAlongTrack(ServerLevel level) {
|
|
this.behavior.moveAlongTrack(level);
|
|
}
|
|
|
|
protected void comeOffTrack(ServerLevel level) {
|
|
double d = this.getMaxSpeed(level);
|
|
Vec3 vec3 = this.getDeltaMovement();
|
|
this.setDeltaMovement(Mth.clamp(vec3.x, -d, d), vec3.y, Mth.clamp(vec3.z, -d, d));
|
|
if (this.onGround()) {
|
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.5));
|
|
}
|
|
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
if (!this.onGround()) {
|
|
this.setDeltaMovement(this.getDeltaMovement().scale(0.95));
|
|
}
|
|
}
|
|
|
|
protected double makeStepAlongTrack(BlockPos pos, RailShape railShape, double speed) {
|
|
return this.behavior.stepAlongTrack(pos, railShape, speed);
|
|
}
|
|
|
|
@Override
|
|
public void move(MoverType type, Vec3 movement) {
|
|
if (useExperimentalMovement(this.level())) {
|
|
Vec3 vec3 = this.position().add(movement);
|
|
super.move(type, movement);
|
|
boolean bl = this.behavior.pushAndPickupEntities();
|
|
if (bl) {
|
|
super.move(type, vec3.subtract(this.position()));
|
|
}
|
|
|
|
if (type.equals(MoverType.PISTON)) {
|
|
this.onRails = false;
|
|
}
|
|
} else {
|
|
super.move(type, movement);
|
|
this.applyEffectsFromBlocks();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void applyEffectsFromBlocks() {
|
|
if (!useExperimentalMovement(this.level())) {
|
|
this.applyEffectsFromBlocks(this.position(), this.position());
|
|
} else {
|
|
super.applyEffectsFromBlocks();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isOnRails() {
|
|
return this.onRails;
|
|
}
|
|
|
|
public void setOnRails(boolean onRails) {
|
|
this.onRails = onRails;
|
|
}
|
|
|
|
public boolean isFlipped() {
|
|
return this.flipped;
|
|
}
|
|
|
|
public void setFlipped(boolean flipped) {
|
|
this.flipped = flipped;
|
|
}
|
|
|
|
public Vec3 getRedstoneDirection(BlockPos pos) {
|
|
BlockState blockState = this.level().getBlockState(pos);
|
|
if (blockState.is(Blocks.POWERED_RAIL) && (Boolean)blockState.getValue(PoweredRailBlock.POWERED)) {
|
|
RailShape railShape = blockState.getValue(((BaseRailBlock)blockState.getBlock()).getShapeProperty());
|
|
if (railShape == RailShape.EAST_WEST) {
|
|
if (this.isRedstoneConductor(pos.west())) {
|
|
return new Vec3(1.0, 0.0, 0.0);
|
|
}
|
|
|
|
if (this.isRedstoneConductor(pos.east())) {
|
|
return new Vec3(-1.0, 0.0, 0.0);
|
|
}
|
|
} else if (railShape == RailShape.NORTH_SOUTH) {
|
|
if (this.isRedstoneConductor(pos.north())) {
|
|
return new Vec3(0.0, 0.0, 1.0);
|
|
}
|
|
|
|
if (this.isRedstoneConductor(pos.south())) {
|
|
return new Vec3(0.0, 0.0, -1.0);
|
|
}
|
|
}
|
|
|
|
return Vec3.ZERO;
|
|
} else {
|
|
return Vec3.ZERO;
|
|
}
|
|
}
|
|
|
|
public boolean isRedstoneConductor(BlockPos pos) {
|
|
return this.level().getBlockState(pos).isRedstoneConductor(this.level(), pos);
|
|
}
|
|
|
|
protected Vec3 applyNaturalSlowdown(Vec3 speed) {
|
|
double d = this.behavior.getSlowdownFactor();
|
|
Vec3 vec3 = speed.multiply(d, 0.0, d);
|
|
if (this.isInWater()) {
|
|
vec3 = vec3.scale(0.95F);
|
|
}
|
|
|
|
return vec3;
|
|
}
|
|
|
|
@Override
|
|
protected void readAdditionalSaveData(CompoundTag tag) {
|
|
RegistryOps<Tag> registryOps = this.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
this.setCustomDisplayBlockState(tag.read("DisplayState", BlockState.CODEC, registryOps));
|
|
this.setDisplayOffset(tag.getIntOr("DisplayOffset", this.getDefaultDisplayOffset()));
|
|
this.flipped = tag.getBooleanOr("FlippedRotation", false);
|
|
this.firstTick = tag.getBooleanOr("HasTicked", false);
|
|
}
|
|
|
|
@Override
|
|
protected void addAdditionalSaveData(CompoundTag tag) {
|
|
this.getCustomDisplayBlockState().ifPresent(blockState -> {
|
|
RegistryOps<Tag> registryOps = this.registryAccess().createSerializationContext(NbtOps.INSTANCE);
|
|
tag.store("DisplayState", BlockState.CODEC, registryOps, blockState);
|
|
});
|
|
int i = this.getDisplayOffset();
|
|
if (i != this.getDefaultDisplayOffset()) {
|
|
tag.putInt("DisplayOffset", i);
|
|
}
|
|
|
|
tag.putBoolean("FlippedRotation", this.flipped);
|
|
tag.putBoolean("HasTicked", this.firstTick);
|
|
}
|
|
|
|
@Override
|
|
public void push(Entity entity) {
|
|
if (!this.level().isClientSide) {
|
|
if (!entity.noPhysics && !this.noPhysics) {
|
|
if (!this.hasPassenger(entity)) {
|
|
double d = entity.getX() - this.getX();
|
|
double e = entity.getZ() - this.getZ();
|
|
double f = d * d + e * e;
|
|
if (f >= 1.0E-4F) {
|
|
f = Math.sqrt(f);
|
|
d /= f;
|
|
e /= f;
|
|
double g = 1.0 / f;
|
|
if (g > 1.0) {
|
|
g = 1.0;
|
|
}
|
|
|
|
d *= g;
|
|
e *= g;
|
|
d *= 0.1F;
|
|
e *= 0.1F;
|
|
d *= 0.5;
|
|
e *= 0.5;
|
|
if (entity instanceof AbstractMinecart abstractMinecart) {
|
|
this.pushOtherMinecart(abstractMinecart, d, e);
|
|
} else {
|
|
this.push(-d, 0.0, -e);
|
|
entity.push(d / 4.0, 0.0, e / 4.0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void pushOtherMinecart(AbstractMinecart otherMinecart, double deltaX, double deltaZ) {
|
|
double d;
|
|
double e;
|
|
if (useExperimentalMovement(this.level())) {
|
|
d = this.getDeltaMovement().x;
|
|
e = this.getDeltaMovement().z;
|
|
} else {
|
|
d = otherMinecart.getX() - this.getX();
|
|
e = otherMinecart.getZ() - this.getZ();
|
|
}
|
|
|
|
Vec3 vec3 = new Vec3(d, 0.0, e).normalize();
|
|
Vec3 vec32 = new Vec3(Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), 0.0, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0))).normalize();
|
|
double f = Math.abs(vec3.dot(vec32));
|
|
if (!(f < 0.8F) || useExperimentalMovement(this.level())) {
|
|
Vec3 vec33 = this.getDeltaMovement();
|
|
Vec3 vec34 = otherMinecart.getDeltaMovement();
|
|
if (otherMinecart.isFurnace() && !this.isFurnace()) {
|
|
this.setDeltaMovement(vec33.multiply(0.2, 1.0, 0.2));
|
|
this.push(vec34.x - deltaX, 0.0, vec34.z - deltaZ);
|
|
otherMinecart.setDeltaMovement(vec34.multiply(0.95, 1.0, 0.95));
|
|
} else if (!otherMinecart.isFurnace() && this.isFurnace()) {
|
|
otherMinecart.setDeltaMovement(vec34.multiply(0.2, 1.0, 0.2));
|
|
otherMinecart.push(vec33.x + deltaX, 0.0, vec33.z + deltaZ);
|
|
this.setDeltaMovement(vec33.multiply(0.95, 1.0, 0.95));
|
|
} else {
|
|
double g = (vec34.x + vec33.x) / 2.0;
|
|
double h = (vec34.z + vec33.z) / 2.0;
|
|
this.setDeltaMovement(vec33.multiply(0.2, 1.0, 0.2));
|
|
this.push(g - deltaX, 0.0, h - deltaZ);
|
|
otherMinecart.setDeltaMovement(vec34.multiply(0.2, 1.0, 0.2));
|
|
otherMinecart.push(g + deltaX, 0.0, h + deltaZ);
|
|
}
|
|
}
|
|
}
|
|
|
|
public BlockState getDisplayBlockState() {
|
|
return (BlockState)this.getCustomDisplayBlockState().orElseGet(this::getDefaultDisplayBlockState);
|
|
}
|
|
|
|
private Optional<BlockState> getCustomDisplayBlockState() {
|
|
return this.getEntityData().get(DATA_ID_CUSTOM_DISPLAY_BLOCK);
|
|
}
|
|
|
|
public BlockState getDefaultDisplayBlockState() {
|
|
return Blocks.AIR.defaultBlockState();
|
|
}
|
|
|
|
public int getDisplayOffset() {
|
|
return this.getEntityData().get(DATA_ID_DISPLAY_OFFSET);
|
|
}
|
|
|
|
public int getDefaultDisplayOffset() {
|
|
return 6;
|
|
}
|
|
|
|
public void setCustomDisplayBlockState(Optional<BlockState> customDisplayBlockState) {
|
|
this.getEntityData().set(DATA_ID_CUSTOM_DISPLAY_BLOCK, customDisplayBlockState);
|
|
}
|
|
|
|
public void setDisplayOffset(int displayOffset) {
|
|
this.getEntityData().set(DATA_ID_DISPLAY_OFFSET, displayOffset);
|
|
}
|
|
|
|
public static boolean useExperimentalMovement(Level level) {
|
|
return level.enabledFeatures().contains(FeatureFlags.MINECART_IMPROVEMENTS);
|
|
}
|
|
|
|
@Override
|
|
public abstract ItemStack getPickResult();
|
|
|
|
public boolean isRideable() {
|
|
return false;
|
|
}
|
|
|
|
public boolean isFurnace() {
|
|
return false;
|
|
}
|
|
}
|