mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-06-02 18:59:19 +02:00
614 lines
20 KiB
Java
614 lines
20 KiB
Java
package com.simibubi.create.content.contraptions;
|
|
|
|
import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp;
|
|
|
|
import java.util.Optional;
|
|
import java.util.UUID;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import com.jozufozu.flywheel.util.transform.TransformStack;
|
|
import com.mojang.blaze3d.vertex.PoseStack;
|
|
import com.simibubi.create.AllEntityTypes;
|
|
import com.simibubi.create.content.contraptions.bearing.StabilizedContraption;
|
|
import com.simibubi.create.content.contraptions.minecart.MinecartSim2020;
|
|
import com.simibubi.create.content.contraptions.minecart.capability.CapabilityMinecartController;
|
|
import com.simibubi.create.content.contraptions.minecart.capability.MinecartController;
|
|
import com.simibubi.create.content.contraptions.mounted.CartAssemblerBlockEntity.CartMovementMode;
|
|
import com.simibubi.create.content.contraptions.mounted.MountedContraption;
|
|
import com.simibubi.create.foundation.item.ItemHelper;
|
|
import com.simibubi.create.foundation.utility.AngleHelper;
|
|
import com.simibubi.create.foundation.utility.Couple;
|
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
|
import com.simibubi.create.foundation.utility.VecHelper;
|
|
|
|
import net.minecraft.client.Minecraft;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.core.Direction.Axis;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.nbt.ListTag;
|
|
import net.minecraft.network.syncher.EntityDataAccessor;
|
|
import net.minecraft.network.syncher.EntityDataSerializers;
|
|
import net.minecraft.network.syncher.SynchedEntityData;
|
|
import net.minecraft.tags.BlockTags;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
|
import net.minecraft.world.entity.vehicle.MinecartFurnace;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.Items;
|
|
import net.minecraft.world.item.crafting.Ingredient;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.level.block.BaseRailBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.RailShape;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
import net.minecraftforge.common.util.LazyOptional;
|
|
|
|
/**
|
|
* Ex: Minecarts, Couplings <br>
|
|
* Oriented Contraption Entities can rotate freely around two axes
|
|
* simultaneously.
|
|
*/
|
|
public class OrientedContraptionEntity extends AbstractContraptionEntity {
|
|
|
|
private static final Ingredient FUEL_ITEMS = Ingredient.of(Items.COAL, Items.CHARCOAL);
|
|
|
|
private static final EntityDataAccessor<Optional<UUID>> COUPLING =
|
|
SynchedEntityData.defineId(OrientedContraptionEntity.class, EntityDataSerializers.OPTIONAL_UUID);
|
|
private static final EntityDataAccessor<Direction> INITIAL_ORIENTATION =
|
|
SynchedEntityData.defineId(OrientedContraptionEntity.class, EntityDataSerializers.DIRECTION);
|
|
|
|
protected Vec3 motionBeforeStall;
|
|
protected boolean forceAngle;
|
|
private boolean isSerializingFurnaceCart;
|
|
private boolean attachedExtraInventories;
|
|
private boolean manuallyPlaced;
|
|
|
|
public float prevYaw;
|
|
public float yaw;
|
|
public float targetYaw;
|
|
|
|
public float prevPitch;
|
|
public float pitch;
|
|
|
|
public int nonDamageTicks;
|
|
|
|
public OrientedContraptionEntity(EntityType<?> type, Level world) {
|
|
super(type, world);
|
|
motionBeforeStall = Vec3.ZERO;
|
|
attachedExtraInventories = false;
|
|
isSerializingFurnaceCart = false;
|
|
nonDamageTicks = 10;
|
|
}
|
|
|
|
public static OrientedContraptionEntity create(Level world, Contraption contraption, Direction initialOrientation) {
|
|
OrientedContraptionEntity entity =
|
|
new OrientedContraptionEntity(AllEntityTypes.ORIENTED_CONTRAPTION.get(), world);
|
|
entity.setContraption(contraption);
|
|
entity.setInitialOrientation(initialOrientation);
|
|
entity.startAtInitialYaw();
|
|
return entity;
|
|
}
|
|
|
|
public static OrientedContraptionEntity createAtYaw(Level world, Contraption contraption,
|
|
Direction initialOrientation, float initialYaw) {
|
|
OrientedContraptionEntity entity = create(world, contraption, initialOrientation);
|
|
entity.startAtYaw(initialYaw);
|
|
entity.manuallyPlaced = true;
|
|
return entity;
|
|
}
|
|
|
|
public void setInitialOrientation(Direction direction) {
|
|
entityData.set(INITIAL_ORIENTATION, direction);
|
|
}
|
|
|
|
public Direction getInitialOrientation() {
|
|
return entityData.get(INITIAL_ORIENTATION);
|
|
}
|
|
|
|
@Override
|
|
public float getYawOffset() {
|
|
return getInitialYaw();
|
|
}
|
|
|
|
public float getInitialYaw() {
|
|
return (isInitialOrientationPresent() ? entityData.get(INITIAL_ORIENTATION) : Direction.SOUTH).toYRot();
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData() {
|
|
super.defineSynchedData();
|
|
entityData.define(COUPLING, Optional.empty());
|
|
entityData.define(INITIAL_ORIENTATION, Direction.UP);
|
|
}
|
|
|
|
@Override
|
|
public ContraptionRotationState getRotationState() {
|
|
ContraptionRotationState crs = new ContraptionRotationState();
|
|
|
|
float yawOffset = getYawOffset();
|
|
crs.zRotation = pitch;
|
|
crs.yRotation = -yaw + yawOffset;
|
|
|
|
if (pitch != 0 && yaw != 0) {
|
|
crs.secondYRotation = -yaw;
|
|
crs.yRotation = yawOffset;
|
|
}
|
|
|
|
return crs;
|
|
}
|
|
|
|
@Override
|
|
public void stopRiding() {
|
|
if (!level.isClientSide && isAlive())
|
|
disassemble();
|
|
super.stopRiding();
|
|
}
|
|
|
|
@Override
|
|
protected void readAdditional(CompoundTag compound, boolean spawnPacket) {
|
|
super.readAdditional(compound, spawnPacket);
|
|
|
|
if (compound.contains("InitialOrientation"))
|
|
setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class));
|
|
|
|
yaw = compound.getFloat("Yaw");
|
|
pitch = compound.getFloat("Pitch");
|
|
manuallyPlaced = compound.getBoolean("Placed");
|
|
|
|
if (compound.contains("ForceYaw"))
|
|
startAtYaw(compound.getFloat("ForceYaw"));
|
|
|
|
ListTag vecNBT = compound.getList("CachedMotion", 6);
|
|
if (!vecNBT.isEmpty()) {
|
|
motionBeforeStall = new Vec3(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2));
|
|
if (!motionBeforeStall.equals(Vec3.ZERO))
|
|
targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall);
|
|
setDeltaMovement(Vec3.ZERO);
|
|
}
|
|
|
|
setCouplingId(compound.contains("OnCoupling") ? compound.getUUID("OnCoupling") : null);
|
|
}
|
|
|
|
@Override
|
|
protected void writeAdditional(CompoundTag compound, boolean spawnPacket) {
|
|
super.writeAdditional(compound, spawnPacket);
|
|
|
|
if (motionBeforeStall != null)
|
|
compound.put("CachedMotion", newDoubleList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z));
|
|
|
|
Direction optional = entityData.get(INITIAL_ORIENTATION);
|
|
if (optional.getAxis()
|
|
.isHorizontal())
|
|
NBTHelper.writeEnum(compound, "InitialOrientation", optional);
|
|
if (forceAngle) {
|
|
compound.putFloat("ForceYaw", yaw);
|
|
forceAngle = false;
|
|
}
|
|
|
|
compound.putBoolean("Placed", manuallyPlaced);
|
|
compound.putFloat("Yaw", yaw);
|
|
compound.putFloat("Pitch", pitch);
|
|
|
|
if (getCouplingId() != null)
|
|
compound.putUUID("OnCoupling", getCouplingId());
|
|
}
|
|
|
|
@Override
|
|
public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
|
|
super.onSyncedDataUpdated(key);
|
|
if (INITIAL_ORIENTATION.equals(key) && isInitialOrientationPresent() && !manuallyPlaced)
|
|
startAtInitialYaw();
|
|
}
|
|
|
|
public boolean isInitialOrientationPresent() {
|
|
return entityData.get(INITIAL_ORIENTATION)
|
|
.getAxis()
|
|
.isHorizontal();
|
|
}
|
|
|
|
public void startAtInitialYaw() {
|
|
startAtYaw(getInitialYaw());
|
|
}
|
|
|
|
public void startAtYaw(float yaw) {
|
|
targetYaw = this.yaw = prevYaw = yaw;
|
|
forceAngle = true;
|
|
}
|
|
|
|
@Override
|
|
public Vec3 applyRotation(Vec3 localPos, float partialTicks) {
|
|
localPos = VecHelper.rotate(localPos, getInitialYaw(), Axis.Y);
|
|
localPos = VecHelper.rotate(localPos, getViewXRot(partialTicks), Axis.Z);
|
|
localPos = VecHelper.rotate(localPos, getViewYRot(partialTicks), Axis.Y);
|
|
return localPos;
|
|
}
|
|
|
|
@Override
|
|
public Vec3 reverseRotation(Vec3 localPos, float partialTicks) {
|
|
localPos = VecHelper.rotate(localPos, -getViewYRot(partialTicks), Axis.Y);
|
|
localPos = VecHelper.rotate(localPos, -getViewXRot(partialTicks), Axis.Z);
|
|
localPos = VecHelper.rotate(localPos, -getInitialYaw(), Axis.Y);
|
|
return localPos;
|
|
}
|
|
|
|
public float getViewYRot(float partialTicks) {
|
|
return -(partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw));
|
|
}
|
|
|
|
public float getViewXRot(float partialTicks) {
|
|
return partialTicks == 1.0F ? pitch : angleLerp(partialTicks, prevPitch, pitch);
|
|
}
|
|
|
|
@Override
|
|
protected void tickContraption() {
|
|
if (nonDamageTicks > 0)
|
|
nonDamageTicks--;
|
|
Entity e = getVehicle();
|
|
if (e == null)
|
|
return;
|
|
|
|
boolean rotationLock = false;
|
|
boolean pauseWhileRotating = false;
|
|
boolean wasStalled = isStalled();
|
|
if (contraption instanceof MountedContraption) {
|
|
MountedContraption mountedContraption = (MountedContraption) contraption;
|
|
rotationLock = mountedContraption.rotationMode == CartMovementMode.ROTATION_LOCKED;
|
|
pauseWhileRotating = mountedContraption.rotationMode == CartMovementMode.ROTATE_PAUSED;
|
|
}
|
|
|
|
Entity riding = e;
|
|
while (riding.getVehicle() != null && !(contraption instanceof StabilizedContraption))
|
|
riding = riding.getVehicle();
|
|
|
|
boolean isOnCoupling = false;
|
|
UUID couplingId = getCouplingId();
|
|
isOnCoupling = couplingId != null && riding instanceof AbstractMinecart;
|
|
|
|
if (!attachedExtraInventories) {
|
|
attachInventoriesFromRidingCarts(riding, isOnCoupling, couplingId);
|
|
attachedExtraInventories = true;
|
|
}
|
|
|
|
boolean rotating = updateOrientation(rotationLock, wasStalled, riding, isOnCoupling);
|
|
if (!rotating || !pauseWhileRotating)
|
|
tickActors();
|
|
boolean isStalled = isStalled();
|
|
|
|
LazyOptional<MinecartController> capability =
|
|
riding.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY);
|
|
if (capability.isPresent()) {
|
|
if (!level.isClientSide())
|
|
capability.orElse(null)
|
|
.setStalledExternally(isStalled);
|
|
} else {
|
|
if (isStalled) {
|
|
if (!wasStalled)
|
|
motionBeforeStall = riding.getDeltaMovement();
|
|
riding.setDeltaMovement(0, 0, 0);
|
|
}
|
|
if (wasStalled && !isStalled) {
|
|
riding.setDeltaMovement(motionBeforeStall);
|
|
motionBeforeStall = Vec3.ZERO;
|
|
}
|
|
}
|
|
|
|
if (level.isClientSide)
|
|
return;
|
|
|
|
if (!isStalled()) {
|
|
if (isOnCoupling) {
|
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
|
if (coupledCarts == null)
|
|
return;
|
|
coupledCarts.map(MinecartController::cart)
|
|
.forEach(this::powerFurnaceCartWithFuelFromStorage);
|
|
return;
|
|
}
|
|
powerFurnaceCartWithFuelFromStorage(riding);
|
|
}
|
|
}
|
|
|
|
protected boolean updateOrientation(boolean rotationLock, boolean wasStalled, Entity riding, boolean isOnCoupling) {
|
|
if (isOnCoupling) {
|
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
|
if (coupledCarts == null)
|
|
return false;
|
|
|
|
Vec3 positionVec = coupledCarts.getFirst()
|
|
.cart()
|
|
.position();
|
|
Vec3 coupledVec = coupledCarts.getSecond()
|
|
.cart()
|
|
.position();
|
|
|
|
double diffX = positionVec.x - coupledVec.x;
|
|
double diffY = positionVec.y - coupledVec.y;
|
|
double diffZ = positionVec.z - coupledVec.z;
|
|
|
|
prevYaw = yaw;
|
|
prevPitch = pitch;
|
|
yaw = (float) (Mth.atan2(diffZ, diffX) * 180 / Math.PI);
|
|
pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI);
|
|
|
|
if (getCouplingId().equals(riding.getUUID())) {
|
|
pitch *= -1;
|
|
yaw += 180;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (contraption instanceof StabilizedContraption) {
|
|
if (!(riding instanceof OrientedContraptionEntity))
|
|
return false;
|
|
StabilizedContraption stabilized = (StabilizedContraption) contraption;
|
|
Direction facing = stabilized.getFacing();
|
|
if (facing.getAxis()
|
|
.isVertical())
|
|
return false;
|
|
OrientedContraptionEntity parent = (OrientedContraptionEntity) riding;
|
|
prevYaw = yaw;
|
|
yaw = -parent.getViewYRot(1);
|
|
return false;
|
|
}
|
|
|
|
prevYaw = yaw;
|
|
if (wasStalled)
|
|
return false;
|
|
|
|
boolean rotating = false;
|
|
Vec3 movementVector = riding.getDeltaMovement();
|
|
Vec3 locationDiff = riding.position()
|
|
.subtract(riding.xo, riding.yo, riding.zo);
|
|
if (!(riding instanceof AbstractMinecart))
|
|
movementVector = locationDiff;
|
|
Vec3 motion = movementVector.normalize();
|
|
|
|
if (!rotationLock) {
|
|
if (riding instanceof AbstractMinecart) {
|
|
AbstractMinecart minecartEntity = (AbstractMinecart) riding;
|
|
BlockPos railPosition = minecartEntity.getCurrentRailPosition();
|
|
BlockState blockState = level.getBlockState(railPosition);
|
|
if (blockState.getBlock() instanceof BaseRailBlock) {
|
|
BaseRailBlock abstractRailBlock = (BaseRailBlock) blockState.getBlock();
|
|
RailShape railDirection =
|
|
abstractRailBlock.getRailDirection(blockState, level, railPosition, minecartEntity);
|
|
motion = VecHelper.project(motion, MinecartSim2020.getRailVec(railDirection));
|
|
}
|
|
}
|
|
|
|
if (motion.length() > 0) {
|
|
targetYaw = yawFromVector(motion);
|
|
if (targetYaw < 0)
|
|
targetYaw += 360;
|
|
if (yaw < 0)
|
|
yaw += 360;
|
|
}
|
|
|
|
prevYaw = yaw;
|
|
float maxApproachSpeed = (float) (motion.length() * 12f / (Math.max(1, getBoundingBox().getXsize() / 6f)));
|
|
float yawHint = AngleHelper.getShortestAngleDiff(yaw, yawFromVector(locationDiff));
|
|
float approach = AngleHelper.getShortestAngleDiff(yaw, targetYaw, yawHint);
|
|
approach = Mth.clamp(approach, -maxApproachSpeed, maxApproachSpeed);
|
|
yaw += approach;
|
|
if (Math.abs(AngleHelper.getShortestAngleDiff(yaw, targetYaw)) < 1f)
|
|
yaw = targetYaw;
|
|
else
|
|
rotating = true;
|
|
}
|
|
return rotating;
|
|
}
|
|
|
|
protected void powerFurnaceCartWithFuelFromStorage(Entity riding) {
|
|
if (!(riding instanceof MinecartFurnace))
|
|
return;
|
|
MinecartFurnace furnaceCart = (MinecartFurnace) riding;
|
|
|
|
// Notify to not trigger serialization side-effects
|
|
isSerializingFurnaceCart = true;
|
|
CompoundTag nbt = furnaceCart.serializeNBT();
|
|
isSerializingFurnaceCart = false;
|
|
|
|
int fuel = nbt.getInt("Fuel");
|
|
int fuelBefore = fuel;
|
|
double pushX = nbt.getDouble("PushX");
|
|
double pushZ = nbt.getDouble("PushZ");
|
|
|
|
int i = Mth.floor(furnaceCart.getX());
|
|
int j = Mth.floor(furnaceCart.getY());
|
|
int k = Mth.floor(furnaceCart.getZ());
|
|
if (furnaceCart.level.getBlockState(new BlockPos(i, j - 1, k))
|
|
.is(BlockTags.RAILS))
|
|
--j;
|
|
|
|
BlockPos blockpos = new BlockPos(i, j, k);
|
|
BlockState blockstate = this.level.getBlockState(blockpos);
|
|
if (furnaceCart.canUseRail() && blockstate.is(BlockTags.RAILS))
|
|
if (fuel > 1)
|
|
riding.setDeltaMovement(riding.getDeltaMovement()
|
|
.normalize()
|
|
.scale(1));
|
|
if (fuel < 5 && contraption != null) {
|
|
ItemStack coal = ItemHelper.extract(contraption.getSharedInventory(), FUEL_ITEMS, 1, false);
|
|
if (!coal.isEmpty())
|
|
fuel += 3600;
|
|
}
|
|
|
|
if (fuel != fuelBefore || pushX != 0 || pushZ != 0) {
|
|
nbt.putInt("Fuel", fuel);
|
|
nbt.putDouble("PushX", 0);
|
|
nbt.putDouble("PushZ", 0);
|
|
furnaceCart.deserializeNBT(nbt);
|
|
}
|
|
}
|
|
|
|
@Nullable
|
|
public Couple<MinecartController> getCoupledCartsIfPresent() {
|
|
UUID couplingId = getCouplingId();
|
|
if (couplingId == null)
|
|
return null;
|
|
MinecartController controller = CapabilityMinecartController.getIfPresent(level, couplingId);
|
|
if (controller == null || !controller.isPresent())
|
|
return null;
|
|
UUID coupledCart = controller.getCoupledCart(true);
|
|
MinecartController coupledController = CapabilityMinecartController.getIfPresent(level, coupledCart);
|
|
if (coupledController == null || !coupledController.isPresent())
|
|
return null;
|
|
return Couple.create(controller, coupledController);
|
|
}
|
|
|
|
protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) {
|
|
if (!(contraption instanceof MountedContraption mc))
|
|
return;
|
|
if (!isOnCoupling) {
|
|
mc.addExtraInventories(riding);
|
|
return;
|
|
}
|
|
Couple<MinecartController> coupledCarts = getCoupledCartsIfPresent();
|
|
if (coupledCarts == null)
|
|
return;
|
|
coupledCarts.map(MinecartController::cart)
|
|
.forEach(mc::addExtraInventories);
|
|
}
|
|
|
|
@Override
|
|
public CompoundTag saveWithoutId(CompoundTag nbt) {
|
|
return isSerializingFurnaceCart ? nbt : super.saveWithoutId(nbt);
|
|
}
|
|
|
|
@Nullable
|
|
public UUID getCouplingId() {
|
|
Optional<UUID> uuid = entityData.get(COUPLING);
|
|
return uuid == null ? null : uuid.isPresent() ? uuid.get() : null;
|
|
}
|
|
|
|
public void setCouplingId(UUID id) {
|
|
entityData.set(COUPLING, Optional.ofNullable(id));
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getAnchorVec() {
|
|
Vec3 anchorVec = super.getAnchorVec();
|
|
return anchorVec.subtract(.5, 0, .5);
|
|
}
|
|
|
|
@Override
|
|
public Vec3 getPrevAnchorVec() {
|
|
Vec3 prevAnchorVec = super.getPrevAnchorVec();
|
|
return prevAnchorVec.subtract(.5, 0, .5);
|
|
}
|
|
|
|
@Override
|
|
protected StructureTransform makeStructureTransform() {
|
|
BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5));
|
|
return new StructureTransform(offset, 0, -yaw + getInitialYaw(), 0);
|
|
}
|
|
|
|
@Override
|
|
protected float getStalledAngle() {
|
|
return yaw;
|
|
}
|
|
|
|
@Override
|
|
protected void handleStallInformation(double x, double y, double z, float angle) {
|
|
yaw = angle;
|
|
}
|
|
|
|
@Override
|
|
@OnlyIn(Dist.CLIENT)
|
|
public void applyLocalTransforms(PoseStack matrixStack, float partialTicks) {
|
|
float angleInitialYaw = getInitialYaw();
|
|
float angleYaw = getViewYRot(partialTicks);
|
|
float anglePitch = getViewXRot(partialTicks);
|
|
|
|
matrixStack.translate(-.5f, 0, -.5f);
|
|
|
|
Entity ridingEntity = getVehicle();
|
|
if (ridingEntity instanceof AbstractMinecart)
|
|
repositionOnCart(matrixStack, partialTicks, ridingEntity);
|
|
else if (ridingEntity instanceof AbstractContraptionEntity) {
|
|
if (ridingEntity.getVehicle() instanceof AbstractMinecart)
|
|
repositionOnCart(matrixStack, partialTicks, ridingEntity.getVehicle());
|
|
else
|
|
repositionOnContraption(matrixStack, partialTicks, ridingEntity);
|
|
}
|
|
|
|
TransformStack.cast(matrixStack)
|
|
.nudge(getId())
|
|
.centre()
|
|
.rotateY(angleYaw)
|
|
.rotateZ(anglePitch)
|
|
.rotateY(angleInitialYaw)
|
|
.unCentre();
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
private void repositionOnContraption(PoseStack matrixStack, float partialTicks, Entity ridingEntity) {
|
|
Vec3 pos = getContraptionOffset(partialTicks, ridingEntity);
|
|
matrixStack.translate(pos.x, pos.y, pos.z);
|
|
}
|
|
|
|
// Minecarts do not always render at their exact location, so the contraption
|
|
// has to adjust aswell
|
|
@OnlyIn(Dist.CLIENT)
|
|
private void repositionOnCart(PoseStack matrixStack, float partialTicks, Entity ridingEntity) {
|
|
Vec3 cartPos = getCartOffset(partialTicks, ridingEntity);
|
|
|
|
if (cartPos == Vec3.ZERO)
|
|
return;
|
|
|
|
matrixStack.translate(cartPos.x, cartPos.y, cartPos.z);
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
private Vec3 getContraptionOffset(float partialTicks, Entity ridingEntity) {
|
|
AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity;
|
|
Vec3 passengerPosition = parent.getPassengerPosition(this, partialTicks);
|
|
if (passengerPosition == null)
|
|
return Vec3.ZERO;
|
|
|
|
double x = passengerPosition.x - Mth.lerp(partialTicks, this.xOld, this.getX());
|
|
double y = passengerPosition.y - Mth.lerp(partialTicks, this.yOld, this.getY());
|
|
double z = passengerPosition.z - Mth.lerp(partialTicks, this.zOld, this.getZ());
|
|
|
|
return new Vec3(x, y, z);
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
private Vec3 getCartOffset(float partialTicks, Entity ridingEntity) {
|
|
AbstractMinecart cart = (AbstractMinecart) ridingEntity;
|
|
double cartX = Mth.lerp(partialTicks, cart.xOld, cart.getX());
|
|
double cartY = Mth.lerp(partialTicks, cart.yOld, cart.getY());
|
|
double cartZ = Mth.lerp(partialTicks, cart.zOld, cart.getZ());
|
|
Vec3 cartPos = cart.getPos(cartX, cartY, cartZ);
|
|
|
|
if (cartPos != null) {
|
|
Vec3 cartPosFront = cart.getPosOffs(cartX, cartY, cartZ, (double) 0.3F);
|
|
Vec3 cartPosBack = cart.getPosOffs(cartX, cartY, cartZ, (double) -0.3F);
|
|
if (cartPosFront == null)
|
|
cartPosFront = cartPos;
|
|
if (cartPosBack == null)
|
|
cartPosBack = cartPos;
|
|
|
|
cartX = cartPos.x - cartX;
|
|
cartY = (cartPosFront.y + cartPosBack.y) / 2.0D - cartY;
|
|
cartZ = cartPos.z - cartZ;
|
|
|
|
return new Vec3(cartX, cartY, cartZ);
|
|
}
|
|
|
|
return Vec3.ZERO;
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
public static void handleRelocationPacket(ContraptionRelocationPacket packet) {
|
|
if (Minecraft.getInstance().level.getEntity(packet.entityID) instanceof OrientedContraptionEntity oce)
|
|
oce.nonDamageTicks = 10;
|
|
}
|
|
}
|