diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 71434e161..e48a3ac76 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -46,6 +46,7 @@ import com.simibubi.create.content.contraptions.components.motor.CreativeMotorGe import com.simibubi.create.content.contraptions.components.press.MechanicalPressBlock; import com.simibubi.create.content.contraptions.components.saw.SawBlock; import com.simibubi.create.content.contraptions.components.saw.SawGenerator; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedBearingMovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkBearingBlock; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.SailBlock; @@ -668,6 +669,7 @@ public class AllBlocks { REGISTRATE.block("mechanical_bearing", MechanicalBearingBlock::new) .transform(BuilderTransformers.bearing("mechanical", "gearbox", false)) .transform(StressConfigDefaults.setImpact(4.0)) + .onRegister(addMovementBehaviour(new StabilizedBearingMovementBehaviour())) .register(); public static final BlockEntry CLOCKWORK_BEARING = diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 0e2e5b593..08a1a8d1a 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -1,8 +1,11 @@ package com.simibubi.create; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntityRenderer; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRenderer; import com.simibubi.create.foundation.utility.Lang; @@ -19,34 +22,38 @@ import net.minecraftforge.fml.client.registry.RenderingRegistry; public class AllEntityTypes { - public static final RegistryEntry> CONTRAPTION = - register("contraption", ContraptionEntity::new, EntityClassification.MISC, 5, 3, true, ContraptionEntity::build); - public static final RegistryEntry> STATIONARY_CONTRAPTION = - register("stationary_contraption", ContraptionEntity::new, EntityClassification.MISC, 20, 40, false, ContraptionEntity::build); - public static final RegistryEntry> SUPER_GLUE = - register("super_glue", SuperGlueEntity::new, EntityClassification.MISC, 10, Integer.MAX_VALUE, false, SuperGlueEntity::build); + public static final RegistryEntry> ORIENTED_CONTRAPTION = + register("contraption", OrientedContraptionEntity::new, EntityClassification.MISC, 5, 3, true, + AbstractContraptionEntity::build); + public static final RegistryEntry> CONTROLLED_CONTRAPTION = + register("stationary_contraption", ControlledContraptionEntity::new, EntityClassification.MISC, 20, 40, false, + AbstractContraptionEntity::build); + public static final RegistryEntry> SUPER_GLUE = register("super_glue", + SuperGlueEntity::new, EntityClassification.MISC, 10, Integer.MAX_VALUE, false, SuperGlueEntity::build); public static final RegistryEntry> SEAT = - register("seat", SeatEntity::new, EntityClassification.MISC, 0, Integer.MAX_VALUE, false, SeatEntity::build); + register("seat", SeatEntity::new, EntityClassification.MISC, 0, Integer.MAX_VALUE, false, SeatEntity::build); private static RegistryEntry> register(String name, IFactory factory, - EntityClassification group, int range, int updateFrequency, boolean sendVelocity, - NonNullConsumer> propertyBuilder) { + EntityClassification group, int range, int updateFrequency, boolean sendVelocity, + NonNullConsumer> propertyBuilder) { String id = Lang.asId(name); - return Create.registrate().entity(id, factory, group) - .properties(b -> b - .setTrackingRange(range) - .setUpdateInterval(updateFrequency) - .setShouldReceiveVelocityUpdates(sendVelocity)) - .properties(propertyBuilder) - .register(); + return Create.registrate() + .entity(id, factory, group) + .properties(b -> b.setTrackingRange(range) + .setUpdateInterval(updateFrequency) + .setShouldReceiveVelocityUpdates(sendVelocity)) + .properties(propertyBuilder) + .register(); } - + public static void register() {} @OnlyIn(value = Dist.CLIENT) public static void registerRenderers() { - RenderingRegistry.registerEntityRenderingHandler(STATIONARY_CONTRAPTION.get(), ContraptionEntityRenderer::new); - RenderingRegistry.registerEntityRenderingHandler(CONTRAPTION.get(), ContraptionEntityRenderer::new); + RenderingRegistry.registerEntityRenderingHandler(CONTROLLED_CONTRAPTION.get(), + ControlledContraptionEntityRenderer::new); + RenderingRegistry.registerEntityRenderingHandler(ORIENTED_CONTRAPTION.get(), + OrientedContraptionEntityRenderer::new); RenderingRegistry.registerEntityRenderingHandler(SUPER_GLUE.get(), SuperGlueRenderer::new); RenderingRegistry.registerEntityRenderingHandler(SEAT.get(), SeatEntity.Render::new); } diff --git a/src/main/java/com/simibubi/create/AllMovementBehaviours.java b/src/main/java/com/simibubi/create/AllMovementBehaviours.java index cf86e8ccb..44d298625 100644 --- a/src/main/java/com/simibubi/create/AllMovementBehaviours.java +++ b/src/main/java/com/simibubi/create/AllMovementBehaviours.java @@ -12,6 +12,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov import com.tterrag.registrate.util.nullness.NonNullConsumer; import net.minecraft.block.Block; +import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.util.ResourceLocation; @@ -29,16 +30,21 @@ public class AllMovementBehaviours { } @Nullable - public static MovementBehaviour getMovementBehaviour(ResourceLocation resourceLocation) { + public static MovementBehaviour of(ResourceLocation resourceLocation) { return movementBehaviours.getOrDefault(resourceLocation, null); } @Nullable - public static MovementBehaviour getMovementBehaviour(Block block) { - return getMovementBehaviour(block.getRegistryName()); + public static MovementBehaviour of(Block block) { + return of(block.getRegistryName()); + } + + @Nullable + public static MovementBehaviour of(BlockState state) { + return of(state.getBlock()); } - public static boolean hasMovementBehaviour(Block block) { + public static boolean contains(Block block) { return movementBehaviours.containsKey(block.getRegistryName()); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java index 3e36607b3..2305ae8df 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/BlockBreakingMovementBehaviour.java @@ -1,6 +1,6 @@ package com.simibubi.create.content.contraptions.components.actors; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.foundation.utility.BlockHelper; @@ -52,12 +52,12 @@ public class BlockBreakingMovementBehaviour extends MovementBehaviour { Entities: for (Entity entity : world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(pos))) { if (entity instanceof ItemEntity) continue; - if (entity instanceof ContraptionEntity) + if (entity instanceof AbstractContraptionEntity) continue; if (entity instanceof AbstractMinecartEntity) for (Entity passenger : entity.getRecursivePassengers()) - if (passenger instanceof ContraptionEntity - && ((ContraptionEntity) passenger).getContraption() == context.contraption) + if (passenger instanceof AbstractContraptionEntity + && ((AbstractContraptionEntity) passenger).getContraption() == context.contraption) continue Entities; if (damageSource != null && !world.isRemote) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java index f6ac7143b..66a72fdbb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatBlock.java @@ -16,7 +16,6 @@ import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MobEntity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.DyeColor; import net.minecraft.item.ItemGroup; @@ -132,8 +131,7 @@ public class SeatBlock extends Block { } public static boolean canBePickedUp(Entity passenger) { - return !(passenger instanceof PlayerEntity) - && (passenger instanceof LivingEntity || passenger instanceof AbstractMinecartEntity); + return !(passenger instanceof PlayerEntity) && (passenger instanceof LivingEntity); } public static void sitDown(World world, BlockPos pos, Entity entity) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java index 00ec2db8f..6b7ddd899 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java @@ -4,7 +4,7 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.foundation.utility.VecHelper; @@ -30,7 +30,8 @@ public class SeatMovementBehaviour extends MovementBehaviour { @Override public void visitNewPosition(MovementContext context, BlockPos pos) { super.visitNewPosition(context, pos); - ContraptionEntity contraptionEntity = context.contraption.entity; + + AbstractContraptionEntity contraptionEntity = context.contraption.entity; if (contraptionEntity == null) return; int index = context.data.getInt("SeatIndex"); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java index 9dd309231..aa8f4240e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/deployer/DeployerMovementBehaviour.java @@ -7,7 +7,7 @@ import org.apache.commons.lang3.tuple.Pair; import com.mojang.blaze3d.matrix.MatrixStack; import com.simibubi.create.content.contraptions.components.deployer.DeployerTileEntity.Mode; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.logistics.item.filter.FilterItem; @@ -53,8 +53,8 @@ public class DeployerMovementBehaviour extends MovementBehaviour { .getDirectionVec()); facingVec = context.rotation.apply(facingVec); Vec3d vec = context.position.subtract(facingVec.scale(2)); - player.rotationYaw = ContraptionEntity.yawFromVector(facingVec); - player.rotationPitch = ContraptionEntity.pitchFromVector(facingVec) - 90; + player.rotationYaw = AbstractContraptionEntity.yawFromVector(facingVec); + player.rotationPitch = AbstractContraptionEntity.pitchFromVector(facingVec) - 90; DeployerHandler.activate(player, vec, pos, facingVec, mode); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java new file mode 100644 index 000000000..bfbb03470 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -0,0 +1,582 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; +import java.util.UUID; + +import org.apache.commons.lang3.tuple.MutablePair; + +import com.simibubi.create.AllMovementBehaviours; +import com.simibubi.create.content.contraptions.components.actors.SeatEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.foundation.collision.Matrix3d; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.block.material.PushReaction; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.IProjectile; +import net.minecraft.entity.item.HangingEntity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.IPacket; +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.util.DamageSource; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.network.NetworkHooks; +import net.minecraftforge.fml.network.PacketDistributor; + +public abstract class AbstractContraptionEntity extends Entity implements IEntityAdditionalSpawnData { + + private static final DataParameter STALLED = + EntityDataManager.createKey(AbstractContraptionEntity.class, DataSerializers.BOOLEAN); + + public final List collidingEntities = new ArrayList<>(); + + protected Contraption contraption; + protected boolean initialized; + private boolean prevPosInvalid; + + public AbstractContraptionEntity(EntityType entityTypeIn, World worldIn) { + super(entityTypeIn, worldIn); + prevPosInvalid = true; + } + + protected void setContraption(Contraption contraption) { + this.contraption = contraption; + if (contraption == null) + return; + if (world.isRemote) + return; + contraption.onEntityCreated(this); + } + + protected void contraptionInitialize() { + contraption.onEntityInitialize(world, this); + initialized = true; + } + + public boolean collisionEnabled() { + return true; + } + + public void addSittingPassenger(Entity passenger, int seatIndex) { + passenger.startRiding(this, true); + if (world.isRemote) + return; + contraption.getSeatMapping() + .put(passenger.getUniqueID(), seatIndex); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionSeatMappingPacket(getEntityId(), contraption.getSeatMapping())); + } + + @Override + protected void removePassenger(Entity passenger) { + Vec3d transformedVector = getPassengerPosition(passenger, 1); + super.removePassenger(passenger); + if (world.isRemote) + return; + if (transformedVector != null) + passenger.getPersistentData() + .put("ContraptionDismountLocation", VecHelper.writeNBT(transformedVector)); + contraption.getSeatMapping() + .remove(passenger.getUniqueID()); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionSeatMappingPacket(getEntityId(), contraption.getSeatMapping())); + } + + @Override + public void updatePassengerPosition(Entity passenger, IMoveCallback callback) { + if (!isPassenger(passenger)) + return; + Vec3d transformedVector = getPassengerPosition(passenger, 1); + if (transformedVector == null) + return; + callback.accept(passenger, transformedVector.x, transformedVector.y, transformedVector.z); + } + + protected Vec3d getPassengerPosition(Entity passenger, float partialTicks) { + UUID id = passenger.getUniqueID(); + if (passenger instanceof OrientedContraptionEntity) { + BlockPos localPos = contraption.getBearingPosOf(id); + if (localPos != null) + return toGlobalVector(VecHelper.getCenterOf(localPos), partialTicks) + .add(VecHelper.getCenterOf(BlockPos.ZERO)) + .subtract(.5f, 1, .5f); + } + + AxisAlignedBB bb = passenger.getBoundingBox(); + double ySize = bb.getYSize(); + BlockPos seat = contraption.getSeatOf(id); + if (seat == null) + return null; + Vec3d transformedVector = + toGlobalVector(new Vec3d(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5), partialTicks) + .add(VecHelper.getCenterOf(BlockPos.ZERO)) + .subtract(0.5, ySize, 0.5); + return transformedVector; + } + + @Override + protected boolean canFitPassenger(Entity p_184219_1_) { + if (p_184219_1_ instanceof OrientedContraptionEntity) + return true; + return contraption.getSeatMapping() + .size() < contraption.getSeats() + .size(); + } + + public boolean handlePlayerInteraction(PlayerEntity player, BlockPos localPos, Direction side, + Hand interactionHand) { + int indexOfSeat = contraption.getSeats() + .indexOf(localPos); + if (indexOfSeat == -1) + return false; + + // Eject potential existing passenger + Entity toDismount = null; + for (Entry entry : contraption.getSeatMapping() + .entrySet()) { + if (entry.getValue() != indexOfSeat) + continue; + for (Entity entity : getPassengers()) { + if (!entry.getKey() + .equals(entity.getUniqueID())) + continue; + if (entity instanceof PlayerEntity) + return false; + toDismount = entity; + } + } + + if (toDismount != null && !world.isRemote) { + Vec3d transformedVector = getPassengerPosition(toDismount, 1); + toDismount.stopRiding(); + if (transformedVector != null) + toDismount.setPositionAndUpdate(transformedVector.x, transformedVector.y, transformedVector.z); + } + + if (world.isRemote) + return true; + addSittingPassenger(player, indexOfSeat); + return true; + } + + public Vec3d toGlobalVector(Vec3d localVec, float partialTicks) { + Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); + localVec = localVec.subtract(rotationOffset); + localVec = applyRotation(localVec, partialTicks); + localVec = localVec.add(rotationOffset) + .add(getAnchorVec()); + return localVec; + } + + public Vec3d toLocalVector(Vec3d globalVec, float partialTicks) { + Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); + globalVec = globalVec.subtract(getAnchorVec()) + .subtract(rotationOffset); + globalVec = reverseRotation(globalVec, partialTicks); + globalVec = globalVec.add(rotationOffset); + return globalVec; + } + + @Override + public final void tick() { + if (contraption == null) { + remove(); + return; + } + + prevPosX = getX(); + prevPosY = getY(); + prevPosZ = getZ(); + prevPosInvalid = false; + + if (!initialized) + contraptionInitialize(); + tickContraption(); + super.tick(); + } + + protected abstract void tickContraption(); + + public abstract Vec3d applyRotation(Vec3d localPos, float partialTicks); + + public abstract Vec3d reverseRotation(Vec3d localPos, float partialTicks); + + public void tickActors() { + boolean stalledPreviously = contraption.stalled; + + if (!world.isRemote) + contraption.stalled = false; + + for (MutablePair pair : contraption.getActors()) { + MovementContext context = pair.right; + BlockInfo blockInfo = pair.left; + MovementBehaviour actor = AllMovementBehaviours.of(blockInfo.state); + + Vec3d actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos) + .add(actor.getActiveAreaOffset(context)), 1); + BlockPos gridPosition = new BlockPos(actorPosition); + boolean newPosVisited = + !context.stall && shouldActorTrigger(context, blockInfo, actor, actorPosition, gridPosition); + + context.rotation = v -> applyRotation(v, 1); + context.position = actorPosition; + + Vec3d oldMotion = context.motion; + if (!actor.isActive(context)) + continue; + if (newPosVisited && !context.stall) { + actor.visitNewPosition(context, gridPosition); + context.firstMovement = false; + } + if (!oldMotion.equals(context.motion)) + actor.onSpeedChanged(context, oldMotion, context.motion); + actor.tick(context); + contraption.stalled |= context.stall; + } + + for (Entity entity : getPassengers()) { + if (!(entity instanceof OrientedContraptionEntity)) + continue; + if (!contraption.stabilizedSubContraptions.containsKey(entity.getUniqueID())) + continue; + OrientedContraptionEntity orientedCE = (OrientedContraptionEntity) entity; + if (orientedCE.contraption != null && orientedCE.contraption.stalled) { + contraption.stalled = true; + break; + } + } + + if (!world.isRemote) { + if (!stalledPreviously && contraption.stalled) + onContraptionStalled(); + dataManager.set(STALLED, contraption.stalled); + return; + } + + contraption.stalled = isStalled(); + } + + protected void onContraptionStalled() { + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionStallPacket(getEntityId(), getX(), getY(), getZ(), getStalledAngle())); + } + + protected boolean shouldActorTrigger(MovementContext context, BlockInfo blockInfo, MovementBehaviour actor, + Vec3d actorPosition, BlockPos gridPosition) { + Vec3d previousPosition = context.position; + if (previousPosition == null) + return false; + + context.motion = actorPosition.subtract(previousPosition); + Vec3d relativeMotion = context.motion; + relativeMotion = reverseRotation(relativeMotion, 1); + context.relativeMotion = relativeMotion; + return !new BlockPos(previousPosition).equals(gridPosition) + || context.relativeMotion.length() > 0 && context.firstMovement; + } + + public void move(double x, double y, double z) { + setPosition(getX() + x, getY() + y, getZ() + z); + } + + public Vec3d getAnchorVec() { + return getPositionVec(); + } + + public float getYawOffset() { + return 0; + } + + @Override + public void setPosition(double x, double y, double z) { + super.setPosition(x, y, z); + if (contraption == null) + return; + AxisAlignedBB cbox = contraption.bounds; + if (cbox == null) + return; + Vec3d actualVec = getAnchorVec(); + setBoundingBox(cbox.offset(actualVec)); + } + + public static float yawFromVector(Vec3d vec) { + return (float) ((3 * Math.PI / 2 + Math.atan2(vec.z, vec.x)) / Math.PI * 180); + } + + public static float pitchFromVector(Vec3d vec) { + return (float) ((Math.acos(vec.y)) / Math.PI * 180); + } + + public static EntityType.Builder build(EntityType.Builder builder) { + @SuppressWarnings("unchecked") + EntityType.Builder entityBuilder = + (EntityType.Builder) builder; + return entityBuilder.size(1, 1); + } + + @Override + protected void registerData() { + this.dataManager.register(STALLED, false); + } + + @Override + protected void readAdditional(CompoundNBT compound) { + initialized = compound.getBoolean("Initialized"); + contraption = Contraption.fromNBT(world, compound.getCompound("Contraption")); + contraption.entity = this; + dataManager.set(STALLED, compound.getBoolean("Stalled")); + } + + @Override + protected void writeAdditional(CompoundNBT compound) { + if (contraption != null) + compound.put("Contraption", contraption.writeNBT()); + compound.putBoolean("Stalled", isStalled()); + compound.putBoolean("Initialized", initialized); + } + + @Override + public IPacket createSpawnPacket() { + return NetworkHooks.getEntitySpawningPacket(this); + } + + @Override + public void writeSpawnData(PacketBuffer buffer) { + CompoundNBT compound = new CompoundNBT(); + writeAdditional(compound); + buffer.writeCompoundTag(compound); + } + + @Override + public void readSpawnData(PacketBuffer additionalData) { + readAdditional(additionalData.readCompoundTag()); + } + + public void disassemble() { + if (!isAlive()) + return; + if (contraption == null) + return; + remove(); + StructureTransform transform = makeStructureTransform(); + contraption.addBlocksToWorld(world, transform); + contraption.addPassengersToWorld(world, transform, getPassengers()); + + for (Entity entity : getPassengers()) { + if (!(entity instanceof OrientedContraptionEntity)) + continue; + UUID id = entity.getUniqueID(); + if (!contraption.stabilizedSubContraptions.containsKey(id)) + continue; + BlockPos transformed = transform.apply(contraption.stabilizedSubContraptions.get(id) + .getConnectedPos()); + entity.setPosition(transformed.getX(), transformed.getY(), transformed.getZ()); + ((AbstractContraptionEntity) entity).disassemble(); + } + + removePassengers(); + + for (Entity entity : collidingEntities) { + Vec3d positionVec = getPositionVec(); + Vec3d localVec = entity.getPositionVec() + .subtract(positionVec); + localVec = reverseRotation(localVec, 1); + Vec3d transformed = transform.apply(localVec); + entity.setPositionAndUpdate(transformed.x, transformed.y, transformed.z); + } + } + + protected abstract StructureTransform makeStructureTransform(); + + @Override + public void onKillCommand() { + removePassengers(); + super.onKillCommand(); + } + + @Override + protected void outOfWorld() { + removePassengers(); + super.outOfWorld(); + } + + @Override + public void onRemovedFromWorld() { + super.onRemovedFromWorld(); + if (world != null && world.isRemote) + return; + getPassengers().forEach(Entity::remove); + } + + @Override + protected void doWaterSplashEffect() {} + + public Contraption getContraption() { + return contraption; + } + + public boolean isStalled() { + return dataManager.get(STALLED); + } + + @OnlyIn(Dist.CLIENT) + static void handleStallPacket(ContraptionStallPacket packet) { + Entity entity = Minecraft.getInstance().world.getEntityByID(packet.entityID); + if (!(entity instanceof AbstractContraptionEntity)) + return; + AbstractContraptionEntity ce = (AbstractContraptionEntity) entity; + ce.handleStallInformation(packet.x, packet.y, packet.z, packet.angle); + } + + protected abstract float getStalledAngle(); + + protected abstract void handleStallInformation(float x, float y, float z, float angle); + + @Override + @SuppressWarnings("deprecation") + public CompoundNBT writeWithoutTypeId(CompoundNBT nbt) { + Vec3d vec = getPositionVec(); + List passengers = getPassengers(); + + for (Entity entity : passengers) { + // setPos has world accessing side-effects when removed == false + entity.removed = true; + + // Gather passengers into same chunk when saving + Vec3d prevVec = entity.getPositionVec(); + entity.setPos(vec.x, prevVec.y, vec.z); + + // Super requires all passengers to not be removed in order to write them to the + // tag + entity.removed = false; + } + + CompoundNBT tag = super.writeWithoutTypeId(nbt); + return tag; + } + + @Override + // Make sure nothing can move contraptions out of the way + public void setMotion(Vec3d motionIn) {} + + @Override + public PushReaction getPushReaction() { + return PushReaction.IGNORE; + } + + public void setContraptionMotion(Vec3d vec) { + super.setMotion(vec); + } + + @Override + public boolean canBeCollidedWith() { + return false; + } + + @Override + public boolean attackEntityFrom(DamageSource source, float amount) { + return false; + } + + public Vec3d getPrevPositionVec() { + return prevPosInvalid ? getPositionVec() : new Vec3d(prevPosX, prevPosY, prevPosZ); + } + + public abstract ContraptionRotationState getRotationState(); + + public Vec3d getContactPointMotion(Vec3d globalContactPoint) { + if (prevPosInvalid) + return Vec3d.ZERO; + Vec3d contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1); + return contactPoint.subtract(globalContactPoint) + .add(getPositionVec().subtract(getPrevPositionVec())); + } + + public boolean canCollideWith(Entity e) { + if (e instanceof PlayerEntity && e.isSpectator()) + return false; + if (e.noClip) + return false; + if (e instanceof HangingEntity) + return false; + if (e instanceof AbstractMinecartEntity) + return false; + if (e instanceof SuperGlueEntity) + return false; + if (e instanceof SeatEntity) + return false; + if (e instanceof IProjectile) + return false; + if (e.getRidingEntity() != null) + return false; + + Entity riding = this.getRidingEntity(); + while (riding != null) { + if (riding == e) + return false; + riding = riding.getRidingEntity(); + } + + return e.getPushReaction() == PushReaction.NORMAL; + } + + @Override + public boolean isOnePlayerRiding() { + return false; + } + + public static class ContraptionRotationState { + static final ContraptionRotationState NONE = new ContraptionRotationState(); + + float xRotation = 0; + float yRotation = 0; + float zRotation = 0; + float secondYRotation = 0; + Matrix3d matrix; + + public Matrix3d asMatrix() { + if (matrix != null) + return matrix; + + matrix = new Matrix3d().asIdentity(); + if (xRotation != 0) + matrix.multiply(new Matrix3d().asXRotation(AngleHelper.rad(-xRotation))); + if (yRotation != 0) + matrix.multiply(new Matrix3d().asYRotation(AngleHelper.rad(yRotation))); + if (zRotation != 0) + matrix.multiply(new Matrix3d().asZRotation(AngleHelper.rad(-zRotation))); + return matrix; + } + + public boolean hasVerticalRotation() { + return xRotation != 0 || zRotation != 0; + } + + public float getYawOffset() { + return secondYRotation; + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java new file mode 100644 index 000000000..54438be96 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntityRenderer.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.mojang.blaze3d.matrix.MatrixStack; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.culling.ClippingHelperImpl; +import net.minecraft.client.renderer.entity.EntityRenderer; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; + +public abstract class AbstractContraptionEntityRenderer extends EntityRenderer { + + protected AbstractContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { + super(p_i46179_1_); + } + + @Override + public ResourceLocation getEntityTexture(C p_110775_1_) { + return null; + } + + protected abstract void transform(C contraptionEntity, float partialTicks, MatrixStack[] matrixStacks); + + @Override + public boolean shouldRender(C entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, double p_225626_5_, + double p_225626_7_) { + if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) + return false; + if (!entity.isAlive()) + return false; + if (entity.getContraption() == null) + return false; + return true; + } + + @Override + public void render(C entity, float yaw, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffers, + int overlay) { + super.render(entity, yaw, partialTicks, ms, buffers, overlay); + + // Keep a copy of the transforms in order to determine correct lighting + MatrixStack msLocal = getLocalTransform(entity); + MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal }; + + ms.push(); + transform(entity, partialTicks, matrixStacks); + ContraptionRenderer.render(entity.world, entity.getContraption(), ms, msLocal, buffers); + ms.pop(); + + } + + protected MatrixStack getLocalTransform(AbstractContraptionEntity entity) { + double pt = Minecraft.getInstance() + .getRenderPartialTicks(); + MatrixStack matrixStack = new MatrixStack(); + double x = MathHelper.lerp(pt, entity.lastTickPosX, entity.getX()); + double y = MathHelper.lerp(pt, entity.lastTickPosY, entity.getY()); + double z = MathHelper.lerp(pt, entity.lastTickPosZ, entity.getZ()); + matrixStack.translate(x, y, z); + return matrixStack; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AllContraptionTypes.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AllContraptionTypes.java index ba213a14d..7fc1b3483 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AllContraptionTypes.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AllContraptionTypes.java @@ -4,6 +4,7 @@ import java.util.function.Supplier; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonContraption; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyContraption; @@ -16,6 +17,7 @@ public enum AllContraptionTypes { PULLEY(PulleyContraption::new), CLOCKWORK(ClockworkContraption::new), MOUNTED(MountedContraption::new), + STABILIZED(StabilizedContraption::new), ; @@ -28,10 +30,9 @@ public enum AllContraptionTypes { } public static Contraption fromType(String type) { - for (AllContraptionTypes allContraptionTypes : values()) { + for (AllContraptionTypes allContraptionTypes : values()) if (type.equals(allContraptionTypes.id)) return allContraptionTypes.factory.get(); - } return null; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java index ee271473d..744444c12 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementTraits.java @@ -194,6 +194,8 @@ public class BlockMovementTraits { public static boolean notSupportive(BlockState state, Direction facing) { if (AllBlocks.MECHANICAL_DRILL.has(state)) return state.get(BlockStateProperties.FACING) == facing; + if (AllBlocks.MECHANICAL_BEARING.has(state)) + return state.get(BlockStateProperties.FACING) == facing; if (AllBlocks.CART_ASSEMBLER.has(state)) return Direction.DOWN == facing; if (AllBlocks.MECHANICAL_SAW.has(state)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java index b21309879..f0d5cff5f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/Contraption.java @@ -10,6 +10,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.BiConsumer; @@ -25,6 +26,8 @@ import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.components.actors.SeatBlock; import com.simibubi.create.content.contraptions.components.actors.SeatEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; @@ -40,6 +43,7 @@ import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; import com.simibubi.create.content.logistics.block.inventories.AdjustableCrateBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.utility.BlockFace; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; @@ -54,8 +58,6 @@ import net.minecraft.block.DoorBlock; import net.minecraft.block.IWaterLoggable; import net.minecraft.block.PressurePlateBlock; import net.minecraft.block.SlimeBlock; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; import net.minecraft.entity.Entity; import net.minecraft.fluid.Fluids; import net.minecraft.fluid.IFluidState; @@ -83,54 +85,58 @@ import net.minecraftforge.items.wrapper.CombinedInvWrapper; public abstract class Contraption { - public Map blocks; - public Map storage; - public List> actors; + public AbstractContraptionEntity entity; public CombinedInvWrapper inventory; - public List customRenderTEs; - public Set> superglue; - public ContraptionEntity entity; - public AxisAlignedBB bounds; + public BlockPos anchor; public boolean stalled; + protected Map blocks; + protected Map storage; + protected List> actors; + protected Set> superglue; protected List seats; protected Map seatMapping; - protected Map initialPassengers; + protected Map stabilizedSubContraptions; - protected Set cachedColliders; - protected Direction cachedColliderDirection; - protected BlockPos anchor; - protected List glueToRemove; - List renderOrder; + private List glueToRemove; + private Map initialPassengers; + private List pendingSubContraptions; + + // Client + public List renderedTileEntities; public Contraption() { blocks = new HashMap<>(); storage = new HashMap<>(); - actors = new ArrayList<>(); seats = new ArrayList<>(); - seatMapping = new HashMap<>(); - initialPassengers = new HashMap<>(); + actors = new ArrayList<>(); superglue = new HashSet<>(); - renderOrder = new ArrayList<>(); - customRenderTEs = new ArrayList<>(); + seatMapping = new HashMap<>(); glueToRemove = new ArrayList<>(); + initialPassengers = new HashMap<>(); + renderedTileEntities = new ArrayList<>(); + pendingSubContraptions = new ArrayList<>(); + stabilizedSubContraptions = new HashMap<>(); } - protected static boolean isChassis(BlockState state) { - return state.getBlock() instanceof AbstractChassisBlock; + public abstract boolean assemble(World world, BlockPos pos); + + protected abstract boolean canAxisBeStabilized(Axis axis); + + protected abstract AllContraptionTypes getType(); + + protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) { + return false; } - public static CompoundNBT getTileEntityNBT(World world, BlockPos pos) { - TileEntity tileentity = world.getTileEntity(pos); - CompoundNBT compoundnbt = null; - if (tileentity != null) { - compoundnbt = tileentity.write(new CompoundNBT()); - compoundnbt.remove("x"); - compoundnbt.remove("y"); - compoundnbt.remove("z"); - } - return compoundnbt; + protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { + return false; + } + + protected boolean addToInitialFrontier(World world, BlockPos pos, Direction forcedDirection, + List frontier) { + return true; } public static Contraption fromNBT(World world, CompoundNBT nbt) { @@ -140,35 +146,6 @@ public abstract class Contraption { return contraption; } - protected static MovementBehaviour getMovement(BlockState state) { - Block block = state.getBlock(); - if (!AllMovementBehaviours.hasMovementBehaviour(block)) - return null; - return AllMovementBehaviours.getMovementBehaviour(block); - } - - public Set getColliders(World world, Direction movementDirection) { - if (blocks == null) - return null; - if (cachedColliders == null || cachedColliderDirection != movementDirection) { - cachedColliders = new HashSet<>(); - cachedColliderDirection = movementDirection; - - for (BlockInfo info : blocks.values()) { - BlockPos offsetPos = info.pos.offset(movementDirection); - if (info.state.getCollisionShape(world, offsetPos) - .isEmpty()) - continue; - if (blocks.containsKey(offsetPos) && !blocks.get(offsetPos).state.getCollisionShape(world, offsetPos) - .isEmpty()) - continue; - cachedColliders.add(info.pos); - } - - } - return cachedColliders; - } - public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) { initialPassengers.clear(); List frontier = new ArrayList<>(); @@ -191,7 +168,27 @@ public abstract class Contraption { return false; } - public void gatherStoredItems() { + public void onEntityCreated(AbstractContraptionEntity entity) { + this.entity = entity; + + // Create subcontraptions + for (BlockFace blockFace : pendingSubContraptions) { + Direction face = blockFace.getFace(); + StabilizedContraption subContraption = new StabilizedContraption(face); + World world = entity.world; + BlockPos pos = blockFace.getPos(); + if (!subContraption.assemble(world, pos)) + continue; + subContraption.removeBlocksFromWorld(world, BlockPos.ZERO); + OrientedContraptionEntity movedContraption = + OrientedContraptionEntity.create(world, subContraption, Optional.of(face)); + BlockPos anchor = blockFace.getConnectedPos(); + movedContraption.setPosition(anchor.getX() + .5f, anchor.getY(), anchor.getZ() + .5f); + world.addEntity(movedContraption); + stabilizedSubContraptions.put(movedContraption.getUniqueID(), new BlockFace(toLocalPos(pos), face)); + } + + // Gather itemhandlers of mounted storage List list = storage.values() .stream() .map(MountedStorage::getItemHandler) @@ -199,10 +196,16 @@ public abstract class Contraption { inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); } - public void mountPassengers(ContraptionEntity contraptionEntity) { - this.entity = contraptionEntity; - if (contraptionEntity.world.isRemote) + public void onEntityInitialize(World world, AbstractContraptionEntity contraptionEntity) { + if (world.isRemote) return; + + for (OrientedContraptionEntity orientedCE : world.getEntitiesWithinAABB(OrientedContraptionEntity.class, + contraptionEntity.getBoundingBox() + .grow(1))) + if (stabilizedSubContraptions.containsKey(orientedCE.getUniqueID())) + orientedCE.startRiding(contraptionEntity); + for (BlockPos seatPos : getSeats()) { Entity passenger = initialPassengers.get(seatPos); if (passenger == null) @@ -214,11 +217,6 @@ public abstract class Contraption { } } - protected boolean addToInitialFrontier(World world, BlockPos pos, Direction forcedDirection, - List frontier) { - return true; - } - protected boolean moveBlock(World world, BlockPos pos, Direction forcedDirection, List frontier, Set visited) { visited.add(pos); @@ -233,96 +231,32 @@ public abstract class Contraption { if (!movementAllowed(world, pos)) return false; BlockState state = world.getBlockState(pos); - if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited)) + if (state.getBlock() instanceof AbstractChassisBlock + && !moveChassis(world, pos, forcedDirection, frontier, visited)) return false; if (AllBlocks.ADJUSTABLE_CRATE.has(state)) AdjustableCrateBlock.splitCrate(world, pos); - if (AllBlocks.BELT.has(state)) { - BlockPos nextPos = BeltBlock.nextSegmentPosition(state, pos, true); - BlockPos prevPos = BeltBlock.nextSegmentPosition(state, pos, false); - if (nextPos != null && !visited.contains(nextPos)) - frontier.add(nextPos); - if (prevPos != null && !visited.contains(prevPos)) - frontier.add(prevPos); - } + + if (AllBlocks.BELT.has(state)) + moveBelt(pos, frontier, visited, state); + + // Bearings potentially create stabilized sub-contraptions + if (AllBlocks.MECHANICAL_BEARING.has(state)) + moveBearing(pos, frontier, visited, state); // Seats transfer their passenger to the contraption - if (state.getBlock() instanceof SeatBlock) { - BlockPos local = toLocalPos(pos); - getSeats().add(local); - List seatsEntities = world.getEntitiesWithinAABB(SeatEntity.class, new AxisAlignedBB(pos)); - if (!seatsEntities.isEmpty()) { - SeatEntity seat = seatsEntities.get(0); - List passengers = seat.getPassengers(); - if (!passengers.isEmpty()) - initialPassengers.put(local, passengers.get(0)); - } - } + if (state.getBlock() instanceof SeatBlock) + moveSeat(world, pos); // Pulleys drag their rope and their attached structure - if (state.getBlock() instanceof PulleyBlock) { - int limit = AllConfigs.SERVER.kinetics.maxRopeLength.get(); - BlockPos ropePos = pos; - while (limit-- >= 0) { - ropePos = ropePos.down(); - if (!world.isBlockPresent(ropePos)) - break; - BlockState ropeState = world.getBlockState(ropePos); - Block block = ropeState.getBlock(); - if (!(block instanceof RopeBlock) && !(block instanceof MagnetBlock)) { - if (!visited.contains(ropePos)) - frontier.add(ropePos); - break; - } - add(ropePos, capture(world, ropePos)); - } - } + if (state.getBlock() instanceof PulleyBlock) + movePulley(world, pos, frontier, visited); // Pistons drag their attaches poles and extension - if (state.getBlock() instanceof MechanicalPistonBlock) { - int limit = AllConfigs.SERVER.kinetics.maxPistonPoles.get(); - Direction direction = state.get(MechanicalPistonBlock.FACING); - if (state.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) { - BlockPos searchPos = pos; - while (limit-- >= 0) { - searchPos = searchPos.offset(direction); - BlockState blockState = world.getBlockState(searchPos); - if (isExtensionPole(blockState)) { - if (blockState.get(PistonExtensionPoleBlock.FACING) - .getAxis() != direction.getAxis()) - break; - if (!visited.contains(searchPos)) - frontier.add(searchPos); - continue; - } - if (isPistonHead(blockState)) - if (!visited.contains(searchPos)) - frontier.add(searchPos); - break; - } - if (limit <= -1) - return false; - } - - BlockPos searchPos = pos; - while (limit-- >= 0) { - searchPos = searchPos.offset(direction.getOpposite()); - BlockState blockState = world.getBlockState(searchPos); - if (isExtensionPole(blockState)) { - if (blockState.get(PistonExtensionPoleBlock.FACING) - .getAxis() != direction.getAxis()) - break; - if (!visited.contains(searchPos)) - frontier.add(searchPos); - continue; - } - break; - } - - if (limit <= -1) + if (state.getBlock() instanceof MechanicalPistonBlock) + if (!moveMechanicalPiston(world, pos, frontier, visited, state)) return false; - } // Doors try to stay whole if (state.getBlock() instanceof DoorBlock) { @@ -363,16 +297,104 @@ public abstract class Contraption { addGlue(superglue.get(offset)); } - add(pos, capture(world, pos)); + addBlock(pos, capture(world, pos)); return blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get(); } - protected boolean movementAllowed(World world, BlockPos pos) { - return BlockMovementTraits.movementAllowed(world, pos); + private void moveBearing(BlockPos pos, List frontier, Set visited, BlockState state) { + Direction facing = state.get(MechanicalBearingBlock.FACING); + if (!canAxisBeStabilized(facing.getAxis())) { + BlockPos offset = pos.offset(facing); + if (!visited.contains(offset)) + frontier.add(offset); + return; + } + pendingSubContraptions.add(new BlockFace(pos, facing)); } - protected boolean isAnchoringBlockAt(BlockPos pos) { - return pos.equals(anchor); + private void moveBelt(BlockPos pos, List frontier, Set visited, BlockState state) { + BlockPos nextPos = BeltBlock.nextSegmentPosition(state, pos, true); + BlockPos prevPos = BeltBlock.nextSegmentPosition(state, pos, false); + if (nextPos != null && !visited.contains(nextPos)) + frontier.add(nextPos); + if (prevPos != null && !visited.contains(prevPos)) + frontier.add(prevPos); + } + + private void moveSeat(World world, BlockPos pos) { + BlockPos local = toLocalPos(pos); + getSeats().add(local); + List seatsEntities = world.getEntitiesWithinAABB(SeatEntity.class, new AxisAlignedBB(pos)); + if (!seatsEntities.isEmpty()) { + SeatEntity seat = seatsEntities.get(0); + List passengers = seat.getPassengers(); + if (!passengers.isEmpty()) + initialPassengers.put(local, passengers.get(0)); + } + } + + private void movePulley(World world, BlockPos pos, List frontier, Set visited) { + int limit = AllConfigs.SERVER.kinetics.maxRopeLength.get(); + BlockPos ropePos = pos; + while (limit-- >= 0) { + ropePos = ropePos.down(); + if (!world.isBlockPresent(ropePos)) + break; + BlockState ropeState = world.getBlockState(ropePos); + Block block = ropeState.getBlock(); + if (!(block instanceof RopeBlock) && !(block instanceof MagnetBlock)) { + if (!visited.contains(ropePos)) + frontier.add(ropePos); + break; + } + addBlock(ropePos, capture(world, ropePos)); + } + } + + private boolean moveMechanicalPiston(World world, BlockPos pos, List frontier, Set visited, + BlockState state) { + int limit = AllConfigs.SERVER.kinetics.maxPistonPoles.get(); + Direction direction = state.get(MechanicalPistonBlock.FACING); + if (state.get(MechanicalPistonBlock.STATE) == PistonState.EXTENDED) { + BlockPos searchPos = pos; + while (limit-- >= 0) { + searchPos = searchPos.offset(direction); + BlockState blockState = world.getBlockState(searchPos); + if (isExtensionPole(blockState)) { + if (blockState.get(PistonExtensionPoleBlock.FACING) + .getAxis() != direction.getAxis()) + break; + if (!visited.contains(searchPos)) + frontier.add(searchPos); + continue; + } + if (isPistonHead(blockState)) + if (!visited.contains(searchPos)) + frontier.add(searchPos); + break; + } + if (limit <= -1) + return false; + } + + BlockPos searchPos = pos; + while (limit-- >= 0) { + searchPos = searchPos.offset(direction.getOpposite()); + BlockState blockState = world.getBlockState(searchPos); + if (isExtensionPole(blockState)) { + if (blockState.get(PistonExtensionPoleBlock.FACING) + .getAxis() != direction.getAxis()) + break; + if (!visited.contains(searchPos)) + frontier.add(searchPos); + continue; + } + break; + } + + if (limit <= -1) + return false; + return true; } private boolean moveChassis(World world, BlockPos pos, Direction movementDirection, List frontier, @@ -414,18 +436,7 @@ public abstract class Contraption { return Pair.of(new BlockInfo(pos, blockstate, compoundnbt), tileentity); } - public void addGlue(SuperGlueEntity entity) { - BlockPos pos = entity.getHangingPosition(); - Direction direction = entity.getFacingDirection(); - this.superglue.add(Pair.of(toLocalPos(pos), direction)); - glueToRemove.add(entity); - } - - public BlockPos toLocalPos(BlockPos globalPos) { - return globalPos.subtract(anchor); - } - - public void add(BlockPos pos, Pair pair) { + protected void addBlock(BlockPos pos, Pair pair) { BlockInfo captured = pair.getKey(); BlockPos localPos = pos.subtract(anchor); BlockInfo blockInfo = new BlockInfo(localPos, captured.state, captured.nbt); @@ -437,14 +448,44 @@ public abstract class Contraption { TileEntity te = pair.getValue(); if (te != null && MountedStorage.canUseAsStorage(te)) storage.put(localPos, new MountedStorage(te)); - if (AllMovementBehaviours.hasMovementBehaviour(captured.state.getBlock())) + if (AllMovementBehaviours.contains(captured.state.getBlock())) actors.add(MutablePair.of(blockInfo, null)); } + @Nullable + protected CompoundNBT getTileEntityNBT(World world, BlockPos pos) { + TileEntity tileentity = world.getTileEntity(pos); + if (tileentity == null) + return null; + CompoundNBT nbt = tileentity.write(new CompoundNBT()); + nbt.remove("x"); + nbt.remove("y"); + nbt.remove("z"); + return nbt; + } + + protected void addGlue(SuperGlueEntity entity) { + BlockPos pos = entity.getHangingPosition(); + Direction direction = entity.getFacingDirection(); + this.superglue.add(Pair.of(toLocalPos(pos), direction)); + glueToRemove.add(entity); + } + + protected BlockPos toLocalPos(BlockPos globalPos) { + return globalPos.subtract(anchor); + } + + protected boolean movementAllowed(World world, BlockPos pos) { + return BlockMovementTraits.movementAllowed(world, pos); + } + + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pos.equals(anchor); + } + public void readNBT(World world, CompoundNBT nbt) { blocks.clear(); - renderOrder.clear(); - customRenderTEs.clear(); + renderedTileEntities.clear(); nbt.getList("Blocks", 10) .forEach(c -> { @@ -456,12 +497,8 @@ public abstract class Contraption { if (world.isRemote) { Block block = info.state.getBlock(); - if (RenderTypeLookup.canRenderInLayer(info.state, RenderType.getTranslucent())) - renderOrder.add(info.pos); - else - renderOrder.add(0, info.pos); CompoundNBT tag = info.nbt; - MovementBehaviour movementBehaviour = AllMovementBehaviours.getMovementBehaviour(block); + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(block); if (tag == null || (movementBehaviour != null && movementBehaviour.hasSpecialMovementRenderer())) return; @@ -485,7 +522,7 @@ public abstract class Contraption { if (te instanceof KineticTileEntity) ((KineticTileEntity) te).setSpeed(0); te.getBlockState(); - customRenderTEs.add(te); + renderedTileEntities.add(te); } }); @@ -494,8 +531,7 @@ public abstract class Contraption { .forEach(c -> { CompoundNBT comp = (CompoundNBT) c; BlockInfo info = blocks.get(NBTUtil.readBlockPos(comp.getCompound("Pos"))); - MovementContext context = MovementContext.readNBT(world, info, comp); - context.contraption = this; + MovementContext context = MovementContext.readNBT(world, info, comp, this); getActors().add(MutablePair.of(info, context)); }); @@ -510,6 +546,10 @@ public abstract class Contraption { NBTHelper.iterateCompoundList(nbt.getList("Passengers", NBT.TAG_COMPOUND), c -> seatMapping.put(NBTUtil.readUniqueId(c.getCompound("Id")), c.getInt("Seat"))); + stabilizedSubContraptions.clear(); + NBTHelper.iterateCompoundList(nbt.getList("SubContraptions", NBT.TAG_COMPOUND), c -> stabilizedSubContraptions + .put(NBTUtil.readUniqueId(c.getCompound("Id")), BlockFace.fromNBT(c.getCompound("Location")))); + storage.clear(); NBTHelper.iterateCompoundList(nbt.getList("Storage", NBT.TAG_COMPOUND), c -> storage .put(NBTUtil.readBlockPos(c.getCompound("Pos")), MountedStorage.deserialize(c.getCompound("Data")))); @@ -544,7 +584,8 @@ public abstract class Contraption { for (MutablePair actor : getActors()) { CompoundNBT compound = new CompoundNBT(); compound.put("Pos", NBTUtil.writeBlockPos(actor.left.pos)); - getMovement(actor.left.state).writeExtraData(actor.right); + AllMovementBehaviours.of(actor.left.state) + .writeExtraData(actor.right); actor.right.writeToNBT(compound); actorsNBT.add(compound); } @@ -577,6 +618,14 @@ public abstract class Contraption { return tag; })); + nbt.put("SubContraptions", NBTHelper.writeCompoundList(stabilizedSubContraptions.entrySet(), e -> { + CompoundNBT tag = new CompoundNBT(); + tag.put("Id", NBTUtil.writeUniqueId(e.getKey())); + tag.put("Location", e.getValue() + .serializeNBT()); + return tag; + })); + nbt.put("Blocks", blocksNBT); nbt.put("Actors", actorsNBT); nbt.put("Superglue", superglueNBT); @@ -592,14 +641,6 @@ public abstract class Contraption { return nbt; } - protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) { - return false; - } - - protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { - return false; - } - public void removeBlocksFromWorld(IWorld world, BlockPos offset) { storage.values() .forEach(MountedStorage::removeStorageFromWorld); @@ -732,27 +773,15 @@ public abstract class Contraption { } } - public void initActors(World world) { + public void startMoving(World world) { for (MutablePair pair : actors) { - MovementContext context = new MovementContext(world, pair.left); - context.contraption = this; - getMovement(pair.left.state).startMoving(context); + MovementContext context = new MovementContext(world, pair.left, this); + AllMovementBehaviours.of(pair.left.state) + .startMoving(context); pair.setRight(context); } } - public AxisAlignedBB getBoundingBox() { - return bounds; - } - - public List> getActors() { - return actors; - } - - public BlockPos getAnchor() { - return anchor; - } - public void stop(World world) { foreachActor(world, (behaviour, ctx) -> { behaviour.stopMoving(ctx); @@ -765,7 +794,7 @@ public abstract class Contraption { public void foreachActor(World world, BiConsumer callBack) { for (MutablePair pair : actors) - callBack.accept(getMovement(pair.getLeft().state), pair.getRight()); + callBack.accept(AllMovementBehaviours.of(pair.getLeft().state), pair.getRight()); } public void expandBoundsAroundAxis(Axis axis) { @@ -792,7 +821,13 @@ public abstract class Contraption { bounds = new AxisAlignedBB(min, max); } - public BlockPos getSeat(UUID entityId) { + public void addExtraInventories(Entity entity) {} + + public Map getSeatMapping() { + return seatMapping; + } + + public BlockPos getSeatOf(UUID entityId) { if (!getSeatMapping().containsKey(entityId)) return null; int seatIndex = getSeatMapping().get(entityId); @@ -801,10 +836,11 @@ public abstract class Contraption { return getSeats().get(seatIndex); } - protected abstract AllContraptionTypes getType(); - - public Map getSeatMapping() { - return seatMapping; + public BlockPos getBearingPosOf(UUID subContraptionEntityId) { + if (stabilizedSubContraptions.containsKey(subContraptionEntityId)) + return stabilizedSubContraptions.get(subContraptionEntityId) + .getConnectedPos(); + return null; } public void setSeatMapping(Map seatMapping) { @@ -815,5 +851,12 @@ public abstract class Contraption { return seats; } - public void addExtraInventories(Entity entity) {}; + public Map getBlocks() { + return blocks; + } + + public List> getActors() { + return actors; + } + } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java index ff77620b8..0343a8e6b 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionCollider.java @@ -15,12 +15,12 @@ import com.google.common.collect.ImmutableSet; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.content.contraptions.components.actors.BlockBreakingMovementBehaviour; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity.ContraptionRotationState; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ClientMotionPacket; import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.collision.OrientedBB; import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; @@ -28,7 +28,7 @@ import net.minecraft.block.BlockState; import net.minecraft.block.CocoaBlock; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; +import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.util.Direction; @@ -55,68 +55,58 @@ public class ContraptionCollider { NONE, CLIENT, REMOTE, SERVER } - static void collideEntities(ContraptionEntity contraptionEntity) { + static void collideEntities(AbstractContraptionEntity contraptionEntity) { World world = contraptionEntity.getEntityWorld(); Contraption contraption = contraptionEntity.getContraption(); AxisAlignedBB bounds = contraptionEntity.getBoundingBox(); - Vec3d contraptionPosition = contraptionEntity.getPositionVec(); - Vec3d contraptionRotation = contraptionEntity.getRotationVec(); - Vec3d contraptionMotion = contraptionEntity.stationary ? Vec3d.ZERO - : contraptionPosition.subtract(contraptionEntity.getPrevPositionVec()); - contraptionEntity.collidingEntities.clear(); if (contraption == null) return; if (bounds == null) return; - Vec3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO); - double conRotX = contraptionRotation.x; - double conRotY = contraptionRotation.y + contraptionEntity.getInitialYaw(); - double conRotZ = contraptionRotation.z; + contraptionEntity.collidingEntities.clear(); - double reverseYaw = 0; + Vec3d contraptionPosition = contraptionEntity.getPositionVec(); + Vec3d contraptionMotion = contraptionPosition.subtract(contraptionEntity.getPrevPositionVec()); + Vec3d anchorVec = contraptionEntity.getAnchorVec(); + Vec3d centerOfBlock = VecHelper.CENTER_OF_ORIGIN; + ContraptionRotationState rotation = null; - // Collision algorithm does not support rotation around two axes -> rotate - // entities manually - if (conRotZ != 0 && contraptionRotation.y != 0) { - reverseYaw = contraptionRotation.y; - conRotY = contraptionEntity.getInitialYaw(); - } + // After death, multiple refs to the client player may show up in the area + boolean skipClientPlayer = false; - Vec3d contraptionCentreOffset = contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0); - boolean axisAlignedCollision = contraptionRotation.equals(Vec3d.ZERO); - Matrix3d rotation = null; - - for (Entity entity : world.getEntitiesWithinAABB((EntityType) null, bounds.grow(2) - .expand(0, 32, 0), contraptionEntity::canCollideWith)) { + List entitiesWithinAABB = world.getEntitiesWithinAABB(Entity.class, bounds.grow(2) + .expand(0, 32, 0), contraptionEntity::canCollideWith); + for (Entity entity : entitiesWithinAABB) { PlayerType playerType = getPlayerType(entity); if (playerType == PlayerType.REMOTE) continue; + if (playerType == PlayerType.CLIENT) + if (skipClientPlayer) + continue; + else + skipClientPlayer = true; // Init matrix - if (rotation == null) { - rotation = new Matrix3d().asIdentity(); - if (!axisAlignedCollision) { - rotation.multiply(new Matrix3d().asXRotation(AngleHelper.rad(-conRotX))); - rotation.multiply(new Matrix3d().asYRotation(AngleHelper.rad(conRotY))); - rotation.multiply(new Matrix3d().asZRotation(AngleHelper.rad(-conRotZ))); - } - } + if (rotation == null) + rotation = contraptionEntity.getRotationState(); + Matrix3d rotationMatrix = rotation.asMatrix(); // Transform entity position and motion to local space Vec3d entityPosition = entity.getPositionVec(); AxisAlignedBB entityBounds = entity.getBoundingBox(); Vec3d centerY = new Vec3d(0, entityBounds.getYSize() / 2, 0); Vec3d motion = entity.getMotion(); + float yawOffset = rotation.getYawOffset(); Vec3d position = entityPosition; - position = position.subtract(contraptionCentreOffset); position = position.add(centerY); - position = position.subtract(contraptionPosition); - position = VecHelper.rotate(position, -reverseYaw, Axis.Y); - position = rotation.transform(position); + position = position.subtract(centerOfBlock); + position = position.subtract(anchorVec); + position = VecHelper.rotate(position, -yawOffset, Axis.Y); + position = rotationMatrix.transform(position); position = position.add(centerOfBlock); position = position.subtract(centerY); position = position.subtract(entityPosition); @@ -132,14 +122,10 @@ public class ContraptionCollider { // Prepare entity bounds OrientedBB obb = new OrientedBB(localBB); - obb.setRotation(rotation); - motion = rotation.transform(motion); + obb.setRotation(rotationMatrix); + motion = rotationMatrix.transform(motion); motion = motion.subtract(contraptionMotion); -// Vec3d visualizerOrigin = new Vec3d(10, 64, 0); -// CollisionDebugger.OBB = obb.copy(); -// CollisionDebugger.OBB.move(visualizerOrigin); - MutableObject collisionResponse = new MutableObject<>(Vec3d.ZERO); MutableObject allowedMotion = new MutableObject<>(motion); MutableBoolean futureCollision = new MutableBoolean(false); @@ -152,7 +138,7 @@ public class ContraptionCollider { .forEach(shape -> shape.toBoundingBoxList() .forEach(bbs::add)); - boolean doHorizontalPass = conRotX == 0 && conRotZ == 0; + boolean doHorizontalPass = !rotation.hasVerticalRotation(); for (boolean horizontalPass : Iterate.trueAndFalse) { for (AxisAlignedBB bb : bbs) { @@ -199,14 +185,13 @@ public class ContraptionCollider { Vec3d totalResponse = collisionResponse.getValue(); Vec3d motionResponse = allowedMotion.getValue(); boolean hardCollision = !totalResponse.equals(Vec3d.ZERO); - - rotation.transpose(); - motionResponse = rotation.transform(motionResponse) + rotationMatrix.transpose(); + motionResponse = rotationMatrix.transform(motionResponse) .add(contraptionMotion); - totalResponse = rotation.transform(totalResponse); - totalResponse = VecHelper.rotate(totalResponse, reverseYaw, Axis.Y); - rotation.transpose(); + totalResponse = rotationMatrix.transform(totalResponse); + totalResponse = VecHelper.rotate(totalResponse, yawOffset, Axis.Y); + rotationMatrix.transpose(); if (futureCollision.isTrue() && playerType != PlayerType.SERVER) { if (motionResponse.y != entityMotion.y) { @@ -216,15 +201,6 @@ public class ContraptionCollider { } } - Vec3d contactPointMotion = Vec3d.ZERO; - if (surfaceCollision.isTrue()) { - entity.fallDistance = 0; - entity.onGround = true; - contraptionEntity.collidingEntities.add(entity); - if (playerType != PlayerType.SERVER) - contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition); - } - if (hardCollision) { double motionX = entityMotion.getX(); double motionY = entityMotion.getY(); @@ -250,13 +226,30 @@ public class ContraptionCollider { continue; } - - totalResponse = totalResponse.add(contactPointMotion); +// totalResponse = totalResponse.add(contactPointMotion); Vec3d allowedMovement = getAllowedMovement(totalResponse, entity); contraptionEntity.collidingEntities.add(entity); entity.velocityChanged = true; entity.setPosition(entityPosition.x + allowedMovement.x, entityPosition.y + allowedMovement.y, entityPosition.z + allowedMovement.z); + entityPosition = entity.getPositionVec(); + + Vec3d contactPointMotion = Vec3d.ZERO; + if (surfaceCollision.isTrue()) { + entity.fallDistance = 0; + entity.onGround = true; + contraptionEntity.collidingEntities.add(entity); + if (entity instanceof ItemEntity) + entityMotion = entityMotion.mul(.5f, 1, .5f); + + if (playerType != PlayerType.SERVER) { + contactPointMotion = contraptionEntity.getContactPointMotion(entityPosition); + allowedMovement = getAllowedMovement(contactPointMotion, entity); + entity.setPosition(entityPosition.x + allowedMovement.x, entityPosition.y + allowedMovement.y, + entityPosition.z + allowedMovement.z); + } + } + entity.setMotion(entityMotion); if (playerType != PlayerType.CLIENT) @@ -342,10 +335,12 @@ public class ContraptionCollider { BlockPos max = new BlockPos(blockScanBB.maxX, blockScanBB.maxY, blockScanBB.maxZ); ReuseableStream potentialHits = new ReuseableStream<>(BlockPos.getAllInBox(min, max) - .filter(contraption.blocks::containsKey) + .filter(contraption.getBlocks()::containsKey) .map(p -> { - BlockState blockState = contraption.blocks.get(p).state; - BlockPos pos = contraption.blocks.get(p).pos; + BlockState blockState = contraption.getBlocks() + .get(p).state; + BlockPos pos = contraption.getBlocks() + .get(p).pos; VoxelShape collisionShape = blockState.getCollisionShape(world, p); return collisionShape.withOffset(pos.getX(), pos.getY(), pos.getZ()); }) @@ -354,13 +349,13 @@ public class ContraptionCollider { return potentialHits; } - public static boolean collideBlocks(ContraptionEntity contraptionEntity) { - if (!contraptionEntity.collisionEnabled()) + public static boolean collideBlocks(ControlledContraptionEntity contraptionEntity) { + if (!contraptionEntity.supportsTerrainCollision()) return false; World world = contraptionEntity.getEntityWorld(); Vec3d motion = contraptionEntity.getMotion(); - Contraption contraption = contraptionEntity.getContraption(); + TranslatingContraption contraption = (TranslatingContraption) contraptionEntity.getContraption(); AxisAlignedBB bounds = contraptionEntity.getBoundingBox(); Vec3d position = contraptionEntity.getPositionVec(); BlockPos gridPos = new BlockPos(position); @@ -381,14 +376,14 @@ public class ContraptionCollider { return true; // Other moving Contraptions - for (ContraptionEntity otherContraptionEntity : world.getEntitiesWithinAABB(ContraptionEntity.class, - bounds.grow(1), e -> !e.equals(contraptionEntity))) { + for (ControlledContraptionEntity otherContraptionEntity : world.getEntitiesWithinAABB( + ControlledContraptionEntity.class, bounds.grow(1), e -> !e.equals(contraptionEntity))) { - if (!otherContraptionEntity.collisionEnabled()) + if (!otherContraptionEntity.supportsTerrainCollision()) continue; Vec3d otherMotion = otherContraptionEntity.getMotion(); - Contraption otherContraption = otherContraptionEntity.getContraption(); + TranslatingContraption otherContraption = (TranslatingContraption) otherContraptionEntity.getContraption(); AxisAlignedBB otherBounds = otherContraptionEntity.getBoundingBox(); Vec3d otherPosition = otherContraptionEntity.getPositionVec(); @@ -404,7 +399,8 @@ public class ContraptionCollider { for (BlockPos colliderPos : contraption.getColliders(world, movementDirection)) { colliderPos = colliderPos.add(gridPos) .subtract(new BlockPos(otherPosition)); - if (!otherContraption.blocks.containsKey(colliderPos)) + if (!otherContraption.getBlocks() + .containsKey(colliderPos)) continue; return true; } @@ -413,7 +409,7 @@ public class ContraptionCollider { return false; } - public static boolean isCollidingWithWorld(World world, Contraption contraption, BlockPos anchor, + public static boolean isCollidingWithWorld(World world, TranslatingContraption contraption, BlockPos anchor, Direction movementDirection) { for (BlockPos pos : contraption.getColliders(world, movementDirection)) { BlockPos colliderPos = pos.add(anchor); @@ -422,11 +418,11 @@ public class ContraptionCollider { return true; BlockState collidedState = world.getBlockState(colliderPos); - BlockInfo blockInfo = contraption.blocks.get(pos); + BlockInfo blockInfo = contraption.getBlocks() + .get(pos); - if (AllMovementBehaviours.hasMovementBehaviour(blockInfo.state.getBlock())) { - MovementBehaviour movementBehaviour = - AllMovementBehaviours.getMovementBehaviour(blockInfo.state.getBlock()); + if (AllMovementBehaviours.contains(blockInfo.state.getBlock())) { + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state.getBlock()); if (movementBehaviour instanceof BlockBreakingMovementBehaviour) { BlockBreakingMovementBehaviour behaviour = (BlockBreakingMovementBehaviour) movementBehaviour; if (!behaviour.canBreak(world, colliderPos, collidedState) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java deleted file mode 100644 index 80abce264..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntity.java +++ /dev/null @@ -1,1024 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; -import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngleDiff; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.UUID; - -import javax.annotation.Nullable; - -import org.apache.commons.lang3.tuple.MutablePair; - -import com.simibubi.create.AllEntityTypes; -import com.simibubi.create.content.contraptions.components.actors.SeatEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; -import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; -import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; -import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; -import com.simibubi.create.foundation.item.ItemHelper; -import com.simibubi.create.foundation.networking.AllPackets; -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.block.BlockState; -import net.minecraft.block.material.PushReaction; -import net.minecraft.client.Minecraft; -import net.minecraft.entity.Entity; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.IProjectile; -import net.minecraft.entity.item.HangingEntity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; -import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.ItemStack; -import net.minecraft.item.Items; -import net.minecraft.item.crafting.Ingredient; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; -import net.minecraft.nbt.NBTUtil; -import net.minecraft.network.IPacket; -import net.minecraft.network.PacketBuffer; -import net.minecraft.network.datasync.DataParameter; -import net.minecraft.network.datasync.DataSerializers; -import net.minecraft.network.datasync.EntityDataManager; -import net.minecraft.network.datasync.IDataSerializer; -import net.minecraft.tags.BlockTags; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.DamageSource; -import net.minecraft.util.Direction; -import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Hand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; -import net.minecraft.world.World; -import net.minecraft.world.gen.feature.template.Template.BlockInfo; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; -import net.minecraftforge.fml.network.NetworkHooks; -import net.minecraftforge.fml.network.PacketDistributor; - -public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnData { - - public static final IDataSerializer> OPTIONAL_DIRECTION = - new IDataSerializer>() { - - public void write(PacketBuffer buffer, Optional opt) { - buffer.writeVarInt(opt.map(Direction::ordinal) - .orElse(-1) + 1); - } - - public Optional read(PacketBuffer buffer) { - int i = buffer.readVarInt(); - return i == 0 ? Optional.empty() : Optional.of(Direction.values()[i - 1]); - } - - public Optional copyValue(Optional opt) { - return Optional.ofNullable(opt.orElse(null)); - } - }; - - static { - DataSerializers.registerSerializer(OPTIONAL_DIRECTION); - } - - final List collidingEntities = new ArrayList<>(); - - protected Contraption contraption; - protected BlockPos controllerPos; - protected Vec3d motionBeforeStall; - protected boolean forceAngle; - protected boolean stationary; - protected boolean initialized; - private boolean isSerializingFurnaceCart; - private boolean attachedExtraInventories; - private boolean prevPosInvalid; - - private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL); - - private static final DataParameter STALLED = - EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.BOOLEAN); - private static final DataParameter> COUPLING = - EntityDataManager.createKey(ContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID); - private static final DataParameter> INITIAL_ORIENTATION = - EntityDataManager.createKey(ContraptionEntity.class, ContraptionEntity.OPTIONAL_DIRECTION); - - public float prevYaw; - public float prevPitch; - public float prevRoll; - - public float yaw; - public float pitch; - public float roll; - - // Mounted Contraptions - public float targetYaw; - public float targetPitch; - - public ContraptionEntity(EntityType entityTypeIn, World worldIn) { - super(entityTypeIn, worldIn); - motionBeforeStall = Vec3d.ZERO; - stationary = entityTypeIn == AllEntityTypes.STATIONARY_CONTRAPTION.get(); - isSerializingFurnaceCart = false; - attachedExtraInventories = false; - prevPosInvalid = true; - } - - public static ContraptionEntity createMounted(World world, Contraption contraption, - Optional initialOrientation) { - ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.CONTRAPTION.get(), world); - entity.contraptionCreated(contraption); - initialOrientation.ifPresent(entity::setInitialOrientation); - entity.startAtInitialYaw(); - return entity; - } - - public static ContraptionEntity createStationary(World world, Contraption contraption) { - ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.STATIONARY_CONTRAPTION.get(), world); - entity.contraptionCreated(contraption); - return entity; - } - - public void reOrientate(Direction newInitialAngle) { - setInitialOrientation(newInitialAngle); - } - - protected void contraptionCreated(Contraption contraption) { - this.contraption = contraption; - if (contraption == null) - return; - if (world.isRemote) - return; - contraption.gatherStoredItems(); - } - - protected void contraptionInitialize() { - if (!world.isRemote) - contraption.mountPassengers(this); - initialized = true; - } - - public ContraptionEntity controlledBy(T controller) { - this.controllerPos = controller.getPos(); - return this; - } - - private IControlContraption getController() { - if (controllerPos == null) - return null; - if (!world.isBlockPresent(controllerPos)) - return null; - TileEntity te = world.getTileEntity(controllerPos); - if (!(te instanceof IControlContraption)) - return null; - return (IControlContraption) te; - } - - public boolean collisionEnabled() { - return true; - } - - @Override - protected void addPassenger(Entity passenger) { - super.addPassenger(passenger); - } - - public void addSittingPassenger(Entity passenger, int seatIndex) { - passenger.startRiding(this, true); - if (world.isRemote) - return; - contraption.getSeatMapping() - .put(passenger.getUniqueID(), seatIndex); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new ContraptionSeatMappingPacket(getEntityId(), contraption.getSeatMapping())); - } - - @Override - public void remove() { - super.remove(); - } - - @Override - protected void removePassenger(Entity passenger) { - Vec3d transformedVector = getPassengerPosition(passenger); - super.removePassenger(passenger); - if (world.isRemote) - return; - if (transformedVector != null) - passenger.getPersistentData() - .put("ContraptionDismountLocation", VecHelper.writeNBT(transformedVector)); - contraption.getSeatMapping() - .remove(passenger.getUniqueID()); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new ContraptionSeatMappingPacket(getEntityId(), contraption.getSeatMapping())); - } - - @Override - public void updatePassengerPosition(Entity passenger, IMoveCallback callback) { - if (!isPassenger(passenger)) - return; - Vec3d transformedVector = getPassengerPosition(passenger); - if (transformedVector == null) - return; - callback.accept(passenger, transformedVector.x, transformedVector.y, transformedVector.z); - } - - protected Vec3d getPassengerPosition(Entity passenger) { - AxisAlignedBB bb = passenger.getBoundingBox(); - double ySize = bb.getYSize(); - BlockPos seat = contraption.getSeat(passenger.getUniqueID()); - if (seat == null) - return null; - Vec3d transformedVector = toGlobalVector(new Vec3d(seat).add(.5, passenger.getYOffset() + ySize - .15f, .5), 1) - .add(VecHelper.getCenterOf(BlockPos.ZERO)) - .subtract(0.5, ySize, 0.5); - return transformedVector; - } - - @Override - protected boolean canFitPassenger(Entity p_184219_1_) { - return getPassengers().size() < contraption.getSeats() - .size(); - } - - public boolean handlePlayerInteraction(PlayerEntity player, BlockPos localPos, Direction side, - Hand interactionHand) { - int indexOfSeat = contraption.getSeats() - .indexOf(localPos); - if (indexOfSeat == -1) - return false; - - // Eject potential existing passenger - Entity toDismount = null; - for (Entry entry : contraption.getSeatMapping() - .entrySet()) { - if (entry.getValue() != indexOfSeat) - continue; - for (Entity entity : getPassengers()) { - if (!entry.getKey() - .equals(entity.getUniqueID())) - continue; - if (entity instanceof PlayerEntity) - return false; - toDismount = entity; - } - } - - if (toDismount != null && !world.isRemote) { - Vec3d transformedVector = getPassengerPosition(toDismount); - toDismount.stopRiding(); - if (transformedVector != null) - toDismount.setPositionAndUpdate(transformedVector.x, transformedVector.y, transformedVector.z); - } - - if (world.isRemote) - return true; - addSittingPassenger(player, indexOfSeat); - return true; - } - - public Vec3d toGlobalVector(Vec3d localVec, float partialTicks) { - Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); - localVec = localVec.subtract(rotationOffset); - localVec = applyRotation(localVec, partialTicks); - localVec = localVec.add(rotationOffset) - .add(getAnchorVec()); - return localVec; - } - - public Vec3d toLocalVector(Vec3d globalVec, float partialTicks) { - Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); - globalVec = globalVec.subtract(getAnchorVec()) - .subtract(rotationOffset); - globalVec = reverseRotation(globalVec, partialTicks); - globalVec = globalVec.add(rotationOffset); - return globalVec; - } - - @Override - public void tick() { - if (contraption == null) { - remove(); - return; - } - - prevPosX = getX(); - prevPosY = getY(); - prevPosZ = getZ(); - prevPosInvalid = false; - - if (!initialized) - contraptionInitialize(); - checkController(); - - Entity mountedEntity = getRidingEntity(); - if (mountedEntity != null) { - tickAsPassenger(mountedEntity); - super.tick(); - return; - } - - if (getMotion().length() < 1 / 4098f) - setMotion(Vec3d.ZERO); - move(getMotion().x, getMotion().y, getMotion().z); - if (ContraptionCollider.collideBlocks(this)) - getController().collided(); - - tickActors(); - - prevYaw = yaw; - prevPitch = pitch; - prevRoll = roll; - - super.tick(); - - } - - public void tickAsPassenger(Entity e) { - boolean rotationLock = false; - boolean pauseWhileRotating = false; - boolean rotating = 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.getRidingEntity() != null) - riding = riding.getRidingEntity(); - - boolean isOnCoupling = false; - UUID couplingId = getCouplingId(); - isOnCoupling = couplingId != null && riding instanceof AbstractMinecartEntity; - - if (!attachedExtraInventories) { - attachInventoriesFromRidingCarts(riding, isOnCoupling, couplingId); - attachedExtraInventories = true; - } - - if (isOnCoupling) { - Couple coupledCarts = getCoupledCartsIfPresent(); - if (coupledCarts != null) { - - Vec3d positionVec = coupledCarts.getFirst() - .cart() - .getPositionVec(); - Vec3d coupledVec = coupledCarts.getSecond() - .cart() - .getPositionVec(); - - double diffX = positionVec.x - coupledVec.x; - double diffY = positionVec.y - coupledVec.y; - double diffZ = positionVec.z - coupledVec.z; - - prevYaw = yaw; - prevPitch = pitch; - yaw = (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI); - pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI); - - if (couplingId.equals(riding.getUniqueID())) { - pitch *= -1; - yaw += 180; - } - - } - - } else if (!wasStalled) { - Vec3d movementVector = riding.getMotion(); - if (!(riding instanceof AbstractMinecartEntity)) - movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ); - Vec3d motion = movementVector.normalize(); - - if (!dataManager.get(INITIAL_ORIENTATION) - .isPresent() && !world.isRemote) { - if (motion.length() > 0) { - Direction facingFromVector = Direction.getFacingFromVector(motion.x, motion.y, motion.z); - if (facingFromVector.getAxis() - .isHorizontal()) - setInitialOrientation(facingFromVector); - } - } - - if (!rotationLock) { - if (motion.length() > 0) { - targetYaw = yawFromVector(motion); - if (targetYaw < 0) - targetYaw += 360; - if (yaw < 0) - yaw += 360; - } - - prevYaw = yaw; - yaw = angleLerp(0.4f, yaw, targetYaw); - if (Math.abs(AngleHelper.getShortestAngleDiff(yaw, targetYaw)) < 1f) - yaw = targetYaw; - else - rotating = true; - } - } - - if (!rotating || !pauseWhileRotating) - tickActors(); - boolean isStalled = isStalled(); - - LazyOptional capability = - riding.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); - if (capability.isPresent()) { - if (!world.isRemote()) - capability.orElse(null) - .setStalledExternally(isStalled); - } else { - if (isStalled) { - if (!wasStalled) - motionBeforeStall = riding.getMotion(); - riding.setMotion(0, 0, 0); - } - if (wasStalled && !isStalled) { - riding.setMotion(motionBeforeStall); - motionBeforeStall = Vec3d.ZERO; - } - } - - if (world.isRemote) - return; - - if (!isStalled()) { - if (isOnCoupling) { - Couple coupledCarts = getCoupledCartsIfPresent(); - if (coupledCarts == null) - return; - coupledCarts.map(MinecartController::cart) - .forEach(this::powerFurnaceCartWithFuelFromStorage); - return; - } - powerFurnaceCartWithFuelFromStorage(riding); - } - } - - protected void powerFurnaceCartWithFuelFromStorage(Entity riding) { - if (!(riding instanceof FurnaceMinecartEntity)) - return; - FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding; - - // Notify to not trigger serialization side-effects - isSerializingFurnaceCart = true; - CompoundNBT 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 = MathHelper.floor(furnaceCart.getX()); - int j = MathHelper.floor(furnaceCart.getY()); - int k = MathHelper.floor(furnaceCart.getZ()); - if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k)) - .isIn(BlockTags.RAILS)) - --j; - - BlockPos blockpos = new BlockPos(i, j, k); - BlockState blockstate = this.world.getBlockState(blockpos); - if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS)) - if (fuel > 1) - riding.setMotion(riding.getMotion() - .normalize() - .scale(1)); - if (fuel < 5 && contraption != null) { - ItemStack coal = ItemHelper.extract(contraption.inventory, 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 getCoupledCartsIfPresent() { - UUID couplingId = getCouplingId(); - if (couplingId == null) - return null; - MinecartController controller = CapabilityMinecartController.getIfPresent(world, couplingId); - if (controller == null || !controller.isPresent()) - return null; - UUID coupledCart = controller.getCoupledCart(true); - MinecartController coupledController = CapabilityMinecartController.getIfPresent(world, coupledCart); - if (coupledController == null || !coupledController.isPresent()) - return null; - return Couple.create(controller, coupledController); - } - - protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) { - if (isOnCoupling) { - Couple coupledCarts = getCoupledCartsIfPresent(); - if (coupledCarts == null) - return; - coupledCarts.map(MinecartController::cart) - .forEach(contraption::addExtraInventories); - return; - } - contraption.addExtraInventories(riding); - } - - public Vec3d applyRotation(Vec3d localPos, float partialTicks) { - localPos = VecHelper.rotate(localPos, getRoll(partialTicks), Axis.X); - localPos = VecHelper.rotate(localPos, getInitialYaw(), Axis.Y); - localPos = VecHelper.rotate(localPos, getPitch(partialTicks), Axis.Z); - localPos = VecHelper.rotate(localPos, getYaw(partialTicks), Axis.Y); - return localPos; - } - - public Vec3d reverseRotation(Vec3d localPos, float partialTicks) { - localPos = VecHelper.rotate(localPos, -getYaw(partialTicks), Axis.Y); - localPos = VecHelper.rotate(localPos, -getPitch(partialTicks), Axis.Z); - localPos = VecHelper.rotate(localPos, -getInitialYaw(), Axis.Y); - localPos = VecHelper.rotate(localPos, -getRoll(partialTicks), Axis.X); - return localPos; - } - - public void tickActors() { - boolean stalledPreviously = contraption.stalled; - - if (!world.isRemote) - contraption.stalled = false; - - for (MutablePair pair : contraption.actors) { - MovementContext context = pair.right; - BlockInfo blockInfo = pair.left; - MovementBehaviour actor = Contraption.getMovement(blockInfo.state); - - Vec3d actorPosition = toGlobalVector(VecHelper.getCenterOf(blockInfo.pos) - .add(actor.getActiveAreaOffset(context)), 1); - boolean newPosVisited = false; - BlockPos gridPosition = new BlockPos(actorPosition); - Vec3d oldMotion = context.motion; - - if (!context.stall) { - Vec3d previousPosition = context.position; - if (previousPosition != null) { - context.motion = actorPosition.subtract(previousPosition); - Vec3d relativeMotion = context.motion; - relativeMotion = reverseRotation(relativeMotion, 1); - context.relativeMotion = relativeMotion; - newPosVisited = !new BlockPos(previousPosition).equals(gridPosition) - || context.relativeMotion.length() > 0 && context.firstMovement; - } - - if (getContraption() instanceof BearingContraption) { - BearingContraption bc = (BearingContraption) getContraption(); - Direction facing = bc.getFacing(); - Vec3d activeAreaOffset = actor.getActiveAreaOffset(context); - if (activeAreaOffset.mul(VecHelper.axisAlingedPlaneOf(new Vec3d(facing.getDirectionVec()))) - .equals(Vec3d.ZERO)) { - if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) { - context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis() - .getCoordinate(roll - prevRoll, yaw - prevYaw, pitch - prevPitch)); - context.relativeMotion = context.motion; - int timer = context.data.getInt("StationaryTimer"); - if (timer > 0) { - context.data.putInt("StationaryTimer", timer - 1); - } else { - context.data.putInt("StationaryTimer", 20); - newPosVisited = true; - } - } - } - } - } - - context.rotation = v -> applyRotation(v, 1); - context.position = actorPosition; - - if (actor.isActive(context)) { - if (newPosVisited && !context.stall) { - actor.visitNewPosition(context, gridPosition); - context.firstMovement = false; - } - if (!oldMotion.equals(context.motion)) - actor.onSpeedChanged(context, oldMotion, context.motion); - actor.tick(context); - contraption.stalled |= context.stall; - } - } - - if (!world.isRemote) { - if (!stalledPreviously && contraption.stalled) { - setMotion(Vec3d.ZERO); - if (getController() != null) - getController().onStall(); - AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), - new ContraptionStallPacket(getEntityId(), getX(), getY(), getZ(), yaw, pitch, roll)); - } - dataManager.set(STALLED, contraption.stalled); - } else { - contraption.stalled = isStalled(); - } - } - - public void move(double x, double y, double z) { - setPosition(x + getX(), getY() + y, getZ() + z); - } - - private Vec3d getAnchorVec() { - if (contraption != null && contraption.getType() == AllContraptionTypes.MOUNTED) - return new Vec3d(getX() - .5, getY(), getZ() - .5); - return getPositionVec(); - } - - public void rotateTo(double roll, double yaw, double pitch) { - rotate(getShortestAngleDiff(this.roll, roll), getShortestAngleDiff(this.yaw, yaw), - getShortestAngleDiff(this.pitch, pitch)); - } - - @Override - public void notifyDataManagerChange(DataParameter key) { - super.notifyDataManagerChange(key); - if (key == INITIAL_ORIENTATION) - startAtInitialYaw(); - } - - public void rotate(double roll, double yaw, double pitch) { - this.yaw += yaw; - this.pitch += pitch; - this.roll += roll; - } - - @Override - public void setPosition(double x, double y, double z) { - super.setPosition(x, y, z); - if (contraption != null) { - AxisAlignedBB cbox = contraption.getBoundingBox(); - if (cbox != null) { - Vec3d actualVec = getAnchorVec(); - this.setBoundingBox(cbox.offset(actualVec)); - } - } - } - - @Override - public void stopRiding() { - if (!world.isRemote) - if (isAlive()) - disassemble(); - super.stopRiding(); - } - - public static float yawFromVector(Vec3d vec) { - return (float) ((3 * Math.PI / 2 + Math.atan2(vec.z, vec.x)) / Math.PI * 180); - } - - public static float pitchFromVector(Vec3d vec) { - return (float) ((Math.acos(vec.y)) / Math.PI * 180); - } - - public float getYaw(float partialTicks) { - return (getRidingEntity() == null ? 1 : -1) - * (partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)); - } - - public float getPitch(float partialTicks) { - return partialTicks == 1.0F ? pitch : angleLerp(partialTicks, prevPitch, pitch); - } - - public float getRoll(float partialTicks) { - return partialTicks == 1.0F ? roll : angleLerp(partialTicks, prevRoll, roll); - } - - public static EntityType.Builder build(EntityType.Builder builder) { - @SuppressWarnings("unchecked") - EntityType.Builder entityBuilder = (EntityType.Builder) builder; - return entityBuilder.size(1, 1); - } - - @Override - protected void registerData() { - this.dataManager.register(STALLED, false); - this.dataManager.register(COUPLING, Optional.empty()); - this.dataManager.register(INITIAL_ORIENTATION, Optional.empty()); - } - - @Override - protected void readAdditional(CompoundNBT compound) { - initialized = compound.getBoolean("Initialized"); - contraption = Contraption.fromNBT(world, compound.getCompound("Contraption")); - dataManager.set(STALLED, compound.getBoolean("Stalled")); - - if (compound.contains("InitialOrientation")) - setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class)); - if (compound.contains("ForceYaw")) - startAtYaw(compound.getFloat("ForceYaw")); - - ListNBT vecNBT = compound.getList("CachedMotion", 6); - if (!vecNBT.isEmpty()) { - motionBeforeStall = new Vec3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2)); - if (!motionBeforeStall.equals(Vec3d.ZERO)) - targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall); - setMotion(Vec3d.ZERO); - } - - if (compound.contains("Controller")) - controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller")); - setCouplingId( - compound.contains("OnCoupling") ? NBTUtil.readUniqueId(compound.getCompound("OnCoupling")) : null); - } - - public void startAtInitialYaw() { - startAtYaw(getInitialYaw()); - } - - public void startAtYaw(float yaw) { - targetYaw = this.yaw = prevYaw = yaw; - forceAngle = true; - } - - public void checkController() { - if (controllerPos == null) - return; - if (!world.isBlockPresent(controllerPos)) - return; - IControlContraption controller = getController(); - if (controller == null) { - remove(); - return; - } - if (controller.isAttachedTo(this)) - return; - controller.attach(this); - if (world.isRemote) - setPosition(getX(), getY(), getZ()); - } - - @Override - protected void writeAdditional(CompoundNBT compound) { - if (contraption != null) - compound.put("Contraption", contraption.writeNBT()); - if (!stationary && motionBeforeStall != null) - compound.put("CachedMotion", - newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z)); - if (controllerPos != null) - compound.put("Controller", NBTUtil.writeBlockPos(controllerPos)); - - Optional optional = dataManager.get(INITIAL_ORIENTATION); - if (optional.isPresent()) - NBTHelper.writeEnum(compound, "InitialOrientation", optional.get()); - if (forceAngle) { - compound.putFloat("ForceYaw", yaw); - forceAngle = false; - } - - compound.putBoolean("Stalled", isStalled()); - compound.putBoolean("Initialized", initialized); - - if (getCouplingId() != null) - compound.put("OnCoupling", NBTUtil.writeUniqueId(getCouplingId())); - } - - @Override - public IPacket createSpawnPacket() { - return NetworkHooks.getEntitySpawningPacket(this); - } - - @Override - public void writeSpawnData(PacketBuffer buffer) { - CompoundNBT compound = new CompoundNBT(); - writeAdditional(compound); - buffer.writeCompoundTag(compound); - } - - @Override - public void readSpawnData(PacketBuffer additionalData) { - readAdditional(additionalData.readCompoundTag()); - } - - public void disassemble() { - if (!isAlive()) - return; - if (getContraption() != null) { - remove(); - BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5)); - Vec3d rotation = getRotationVec().add(0, getInitialYaw(), 0); - StructureTransform transform = new StructureTransform(offset, rotation); - contraption.addBlocksToWorld(world, transform); - contraption.addPassengersToWorld(world, transform, getPassengers()); - removePassengers(); - - for (Entity entity : collidingEntities) { - Vec3d positionVec = getPositionVec(); - Vec3d localVec = entity.getPositionVec() - .subtract(positionVec); - localVec = VecHelper.rotate(localVec, rotation.scale(-1)); - Vec3d transformed = transform.apply(localVec); - entity.setPositionAndUpdate(transformed.x, transformed.y, transformed.z); - } - - } - } - - @Override - public void onKillCommand() { - removePassengers(); - super.onKillCommand(); - } - - @Override - protected void outOfWorld() { - removePassengers(); - super.outOfWorld(); - } - - @Override - public void onRemovedFromWorld() { - super.onRemovedFromWorld(); - if (world != null && world.isRemote) - return; - getPassengers().forEach(Entity::remove); - } - - @Override - protected void doWaterSplashEffect() {} - - @SuppressWarnings("deprecation") - @Override - public CompoundNBT writeWithoutTypeId(CompoundNBT nbt) { - if (isSerializingFurnaceCart) - return nbt; - - Vec3d vec = getPositionVec(); - List passengers = getPassengers(); - - for (Entity entity : passengers) { - // setPos has world accessing side-effects when removed == false - entity.removed = true; - - // Gather passengers into same chunk when saving - Vec3d prevVec = entity.getPositionVec(); - entity.setPos(vec.x, prevVec.y, vec.z); - - // Super requires all passengers to not be removed in order to write them to the - // tag - entity.removed = false; - } - - CompoundNBT tag = super.writeWithoutTypeId(nbt); - return tag; - } - - public Contraption getContraption() { - return contraption; - } - - public boolean isStalled() { - return dataManager.get(STALLED); - } - - @OnlyIn(Dist.CLIENT) - @Override - public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, - int posRotationIncrements, boolean teleport) { - // Stationary Anchors are responsible for keeping position and motion in sync - // themselves. - if (stationary) - return; - super.setPositionAndRotationDirect(x, y, z, yaw, pitch, posRotationIncrements, teleport); - } - - @OnlyIn(Dist.CLIENT) - static void handleStallPacket(ContraptionStallPacket packet) { - Entity entity = Minecraft.getInstance().world.getEntityByID(packet.entityID); - if (!(entity instanceof ContraptionEntity)) - return; - ContraptionEntity ce = (ContraptionEntity) entity; - if (ce.getRidingEntity() == null) { - ce.setPos(packet.x, packet.y, packet.z); - } - ce.yaw = packet.yaw; - ce.pitch = packet.pitch; - ce.roll = packet.roll; - } - - @Override - // Make sure nothing can move contraptions out of the way - public void setMotion(Vec3d motionIn) {} - - @Override - public void setPositionAndUpdate(double x, double y, double z) { - if (!stationary) - super.setPositionAndUpdate(x, y, z); - } - - @Override - public PushReaction getPushReaction() { - return PushReaction.IGNORE; - } - - public void setContraptionMotion(Vec3d vec) { - super.setMotion(vec); - } - - @Override - public boolean canBeCollidedWith() { - return false; - } - - @Override - public boolean attackEntityFrom(DamageSource source, float amount) { - return false; - } - - public void setInitialOrientation(Direction direction) { - dataManager.set(INITIAL_ORIENTATION, Optional.of(direction)); - } - - public Optional getInitialOrientation() { - return dataManager.get(INITIAL_ORIENTATION); - } - - public float getInitialYaw() { - return dataManager.get(INITIAL_ORIENTATION) - .orElse(Direction.SOUTH) - .getHorizontalAngle(); - } - - public Vec3d getRotationVec() { - return new Vec3d(getRoll(1), getYaw(1), getPitch(1)); - } - - public Vec3d getPrevRotationVec() { - return new Vec3d(getRoll(0), getYaw(0), getPitch(0)); - } - - public Vec3d getPrevPositionVec() { - return new Vec3d(prevPosX, prevPosY, prevPosZ); - } - - public Vec3d getContactPointMotion(Vec3d globalContactPoint) { - if (prevPosInvalid) - return Vec3d.ZERO; - Vec3d contactPoint = toGlobalVector(toLocalVector(globalContactPoint, 0), 1); - return contactPoint.subtract(globalContactPoint) - .add(getPositionVec().subtract(getPrevPositionVec())); - } - - public boolean canCollideWith(Entity e) { - if (e instanceof PlayerEntity && e.isSpectator()) - return false; - if (e.noClip) - return false; - if (e instanceof HangingEntity) - return false; - if (e instanceof AbstractMinecartEntity) - return false; - if (e instanceof SuperGlueEntity) - return false; - if (e instanceof SeatEntity) - return false; - if (e instanceof IProjectile) - return false; - if (e.getRidingEntity() != null) - return false; - - Entity riding = this.getRidingEntity(); - while (riding != null) { - if (riding == e) - return false; - riding = riding.getRidingEntity(); - } - - return e.getPushReaction() == PushReaction.NORMAL; - } - - @Nullable - public UUID getCouplingId() { - Optional uuid = dataManager.get(COUPLING); - return uuid == null ? null : uuid.isPresent() ? uuid.get() : null; - } - - public void setCouplingId(UUID id) { - dataManager.set(COUPLING, Optional.ofNullable(id)); - } - - @Override - public boolean isOnePlayerRiding() { - return false; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java deleted file mode 100644 index 7d7cbeba9..000000000 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionEntityRenderer.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.simibubi.create.content.contraptions.components.structureMovement; - -import com.mojang.blaze3d.matrix.MatrixStack; -import com.simibubi.create.foundation.utility.MatrixStacker; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.IRenderTypeBuffer; -import net.minecraft.client.renderer.entity.EntityRenderer; -import net.minecraft.client.renderer.entity.EntityRendererManager; -import net.minecraft.entity.Entity; -import net.minecraft.entity.item.minecart.AbstractMinecartEntity; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; - -public class ContraptionEntityRenderer extends EntityRenderer { - - public ContraptionEntityRenderer(EntityRendererManager rendererManager) { - super(rendererManager); - } - - @Override - public ResourceLocation getEntityTexture(ContraptionEntity arg0) { - return null; - } - - @Override - public void render(ContraptionEntity entity, float yaw, float partialTicks, MatrixStack ms, - IRenderTypeBuffer buffers, int overlay) { - if (!entity.isAlive()) - return; - if (entity.getContraption() == null) - return; - if (entity.getContraption() - .getType() == AllContraptionTypes.MOUNTED && entity.getRidingEntity() == null) - return; - - // Keep a copy of the transforms in order to determine correct lighting - MatrixStack msLocal = getLocalTransform(entity); - MatrixStack[] matrixStacks = new MatrixStack[] { ms, msLocal }; - - float angleInitialYaw = entity.getInitialYaw(); - float angleYaw = entity.getYaw(partialTicks); - float anglePitch = entity.getPitch(partialTicks); - float angleRoll = entity.getRoll(partialTicks); - - ms.push(); - Entity ridingEntity = entity.getRidingEntity(); - if (ridingEntity != null && ridingEntity instanceof AbstractMinecartEntity) { - AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; - double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); - double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); - double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); - Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); - - for (MatrixStack stack : matrixStacks) - stack.translate(-.5f, 0, -.5f); - - if (cartPos != null) { - Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); - Vec3d cartPosBack = cart.getPosOffset(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; - - for (MatrixStack stack : matrixStacks) - stack.translate(cartX, cartY, cartZ); - } - } - - for (MatrixStack stack : matrixStacks) - MatrixStacker.of(stack) - .nudge(entity.getEntityId()) - .centre() - .rotateY(angleYaw) - .rotateZ(anglePitch) - .rotateY(angleInitialYaw) - .rotateX(angleRoll) - .unCentre(); - ContraptionRenderer.render(entity.world, entity.getContraption(), ms, msLocal, buffers); - ms.pop(); - - super.render(entity, yaw, partialTicks, ms, buffers, overlay); - } - - protected MatrixStack getLocalTransform(ContraptionEntity entity) { - double pt = Minecraft.getInstance() - .getRenderPartialTicks(); - MatrixStack matrixStack = new MatrixStack(); - double x = MathHelper.lerp(pt, entity.lastTickPosX, entity.getX()); - double y = MathHelper.lerp(pt, entity.lastTickPosY, entity.getY()); - double z = MathHelper.lerp(pt, entity.lastTickPosZ, entity.getZ()); - matrixStack.translate(x, y, z); - return matrixStack; - } - -} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java index 3b2723f78..21664ce2e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandler.java @@ -1,9 +1,11 @@ package com.simibubi.create.content.contraptions.components.structureMovement; import java.lang.ref.WeakReference; -import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.WorldAttached; @@ -21,25 +23,26 @@ public class ContraptionHandler { /* Global map of loaded contraptions */ - public static WorldAttached>> loadedContraptions; - static WorldAttached> queuedAdditions; + public static WorldAttached>> loadedContraptions; + static WorldAttached> queuedAdditions; static { - loadedContraptions = new WorldAttached<>(ArrayList::new); + loadedContraptions = new WorldAttached<>(HashMap::new); queuedAdditions = new WorldAttached<>(() -> ObjectLists.synchronize(new ObjectArrayList<>())); } public static void tick(World world) { - List> list = loadedContraptions.get(world); - List queued = queuedAdditions.get(world); + Map> map = loadedContraptions.get(world); + List queued = queuedAdditions.get(world); - for (ContraptionEntity contraptionEntity : queued) - list.add(new WeakReference<>(contraptionEntity)); + for (AbstractContraptionEntity contraptionEntity : queued) + map.put(contraptionEntity.getEntityId(), new WeakReference<>(contraptionEntity)); queued.clear(); - for (Iterator> iterator = list.iterator(); iterator.hasNext();) { - WeakReference weakReference = iterator.next(); - ContraptionEntity contraptionEntity = weakReference.get(); + Collection> values = map.values(); + for (Iterator> iterator = values.iterator(); iterator.hasNext();) { + WeakReference weakReference = iterator.next(); + AbstractContraptionEntity contraptionEntity = weakReference.get(); if (contraptionEntity == null || !contraptionEntity.isAlive()) { iterator.remove(); continue; @@ -49,9 +52,9 @@ public class ContraptionHandler { } public static void addSpawnedContraptionsToCollisionList(Entity entity, World world) { - if (entity instanceof ContraptionEntity) + if (entity instanceof AbstractContraptionEntity) queuedAdditions.get(world) - .add((ContraptionEntity) entity); + .add((AbstractContraptionEntity) entity); } public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingEntity entityLiving, World world) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java index 82fa74d47..1d164de1c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionHandlerClient.java @@ -75,7 +75,7 @@ public class ContraptionHandlerClient { .distanceTo(origin), reach); Vec3d target = RaycastHelper.getTraceTarget(player, reach, origin); - for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class, + for (AbstractContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(AbstractContraptionEntity.class, new AxisAlignedBB(origin, target))) { Vec3d localOrigin = contraptionEntity.toLocalVector(origin, 1); @@ -84,7 +84,7 @@ public class ContraptionHandlerClient { MutableObject mutableResult = new MutableObject<>(); PredicateTraceResult predicateResult = RaycastHelper.rayTraceUntil(localOrigin, localTarget, p -> { - BlockInfo blockInfo = contraption.blocks.get(p); + BlockInfo blockInfo = contraption.getBlocks().get(p); if (blockInfo == null) return false; BlockState state = blockInfo.state; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java index 45049327f..1308d6270 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionRenderer.java @@ -7,6 +7,7 @@ import org.apache.commons.lang3.tuple.Pair; import org.lwjgl.opengl.GL11; import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllMovementBehaviours; import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.SuperByteBuffer; @@ -70,7 +71,7 @@ public class ContraptionRenderer { private static void renderTileEntities(World world, Contraption c, MatrixStack ms, MatrixStack msLocal, IRenderTypeBuffer buffer) { - TileEntityRenderHelper.renderTileEntities(world, c.customRenderTEs, ms, msLocal, buffer); + TileEntityRenderHelper.renderTileEntities(world, c.renderedTileEntities, ms, msLocal, buffer); } private static SuperByteBuffer buildStructureBuffer(Contraption c, RenderType layer) { @@ -86,17 +87,16 @@ public class ContraptionRenderer { BufferBuilder builder = new BufferBuilder(DefaultVertexFormats.BLOCK.getIntegerSize()); builder.begin(GL11.GL_QUADS, DefaultVertexFormats.BLOCK); - for (BlockInfo info : c.blocks.values()) + for (BlockInfo info : c.getBlocks().values()) renderWorld.setBlockState(info.pos, info.state); - for (BlockPos pos : c.renderOrder) { - BlockInfo info = c.blocks.get(pos); + for (BlockInfo info : c.getBlocks().values()) { BlockState state = info.state; if (state.getRenderType() == BlockRenderType.ENTITYBLOCK_ANIMATED) continue; if (!RenderTypeLookup.canRenderInLayer(state, layer)) continue; - + IBakedModel originalModel = dispatcher.getModelForState(state); ms.push(); ms.translate(info.pos.getX(), info.pos.getY(), info.pos.getZ()); @@ -126,7 +126,7 @@ public class ContraptionRenderer { .translate(blockInfo.pos); } - MovementBehaviour movementBehaviour = Contraption.getMovement(blockInfo.state); + MovementBehaviour movementBehaviour = AllMovementBehaviours.of(blockInfo.state); if (movementBehaviour != null) movementBehaviour.renderInContraption(context, ms, msLocal, buffer); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java index 4564236c2..1909dd3ca 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionStallPacket.java @@ -15,18 +15,14 @@ public class ContraptionStallPacket extends SimplePacketBase { float x; float y; float z; - float yaw; - float pitch; - float roll; + float angle; - public ContraptionStallPacket(int entityID, double posX, double posY, double posZ, float yaw, float pitch, float roll) { + public ContraptionStallPacket(int entityID, double posX, double posY, double posZ, float angle) { this.entityID = entityID; this.x = (float) posX; this.y = (float) posY; this.z = (float) posZ; - this.yaw = yaw; - this.pitch = pitch; - this.roll = roll; + this.angle = angle; } public ContraptionStallPacket(PacketBuffer buffer) { @@ -34,21 +30,19 @@ public class ContraptionStallPacket extends SimplePacketBase { x = buffer.readFloat(); y = buffer.readFloat(); z = buffer.readFloat(); - yaw = buffer.readFloat(); - pitch = buffer.readFloat(); - roll = buffer.readFloat(); + angle = buffer.readFloat(); } @Override public void write(PacketBuffer buffer) { buffer.writeInt(entityID); - writeAll(buffer, x, y, z, yaw, pitch, roll); + writeAll(buffer, x, y, z, angle); } @Override public void handle(Supplier context) { context.get().enqueueWork( - () -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> ContraptionEntity.handleStallPacket(this))); + () -> DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> AbstractContraptionEntity.handleStallPacket(this))); context.get().setPacketHandled(true); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java new file mode 100644 index 000000000..e3cf6aab1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntity.java @@ -0,0 +1,221 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; + +import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption; +import com.simibubi.create.foundation.utility.NBTHelper; +import com.simibubi.create.foundation.utility.VecHelper; + +import net.minecraft.entity.EntityType; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +/** + * Ex: Pistons, bearings
+ * Controlled Contraption Entities can rotate around one axis and translate. + *
+ * They are bound to an {@link IControlContraption} + */ +public class ControlledContraptionEntity extends AbstractContraptionEntity { + + protected BlockPos controllerPos; + protected Axis rotationAxis; + protected float prevAngle; + protected float angle; + + public ControlledContraptionEntity(EntityType type, World world) { + super(type, world); + } + + public static ControlledContraptionEntity create(World world, IControlContraption controller, + Contraption contraption) { + ControlledContraptionEntity entity = + new ControlledContraptionEntity(AllEntityTypes.CONTROLLED_CONTRAPTION.get(), world); + entity.controllerPos = controller.getBlockPosition(); + entity.setContraption(contraption); + return entity; + } + + public boolean supportsTerrainCollision() { + return contraption instanceof TranslatingContraption; + } + + @Override + protected void setContraption(Contraption contraption) { + super.setContraption(contraption); + if (contraption instanceof BearingContraption) + rotationAxis = ((BearingContraption) contraption).getFacing() + .getAxis(); + + } + + @Override + protected void readAdditional(CompoundNBT compound) { + super.readAdditional(compound); + controllerPos = NBTUtil.readBlockPos(compound.getCompound("Controller")); + if (compound.contains("Axis")) + rotationAxis = NBTHelper.readEnum(compound, "Axis", Axis.class); + angle = compound.getFloat("Angle"); + } + + @Override + protected void writeAdditional(CompoundNBT compound) { + super.writeAdditional(compound); + compound.put("Controller", NBTUtil.writeBlockPos(controllerPos)); + if (rotationAxis != null) + NBTHelper.writeEnum(compound, "Axis", rotationAxis); + compound.putFloat("Angle", angle); + } + + @Override + public ContraptionRotationState getRotationState() { + ContraptionRotationState crs = new ContraptionRotationState(); + if (rotationAxis == Axis.X) + crs.xRotation = angle; + if (rotationAxis == Axis.Y) + crs.yRotation = angle; + if (rotationAxis == Axis.Z) + crs.zRotation = angle; + return crs; + } + + @Override + public Vec3d applyRotation(Vec3d localPos, float partialTicks) { + localPos = VecHelper.rotate(localPos, getAngle(partialTicks), rotationAxis); + return localPos; + } + + @Override + public Vec3d reverseRotation(Vec3d localPos, float partialTicks) { + localPos = VecHelper.rotate(localPos, -getAngle(partialTicks), rotationAxis); + return localPos; + } + + public void setAngle(float angle) { + this.angle = angle; + } + + public float getAngle(float partialTicks) { + return partialTicks == 1.0F ? angle : angleLerp(partialTicks, prevAngle, angle); + } + + public void setRotationAxis(Axis rotationAxis) { + this.rotationAxis = rotationAxis; + } + + public Axis getRotationAxis() { + return rotationAxis; + } + + @Override + public void setPositionAndUpdate(double p_70634_1_, double p_70634_3_, double p_70634_5_) {} + + @Override + @OnlyIn(Dist.CLIENT) + public void setPositionAndRotationDirect(double x, double y, double z, float yw, float pt, int inc, boolean t) {} + + protected void tickContraption() { + prevAngle = angle; + tickActors(); + + if (controllerPos == null) + return; + if (!world.isBlockPresent(controllerPos)) + return; + IControlContraption controller = getController(); + if (controller == null) { + remove(); + return; + } + if (!controller.isAttachedTo(this)) { + controller.attach(this); + if (world.isRemote) + setPosition(getX(), getY(), getZ()); + } + + Vec3d motion = getMotion(); + if (motion.length() < 1 / 4098f) + setMotion(Vec3d.ZERO); + move(motion.x, motion.y, motion.z); + if (ContraptionCollider.collideBlocks(this)) + getController().collided(); + } + + @Override + protected boolean shouldActorTrigger(MovementContext context, BlockInfo blockInfo, MovementBehaviour actor, + Vec3d actorPosition, BlockPos gridPosition) { + if (super.shouldActorTrigger(context, blockInfo, actor, actorPosition, gridPosition)) + return true; + + // Special activation timer for actors in the center of a bearing contraption + if (!(contraption instanceof BearingContraption)) + return false; + BearingContraption bc = (BearingContraption) contraption; + Direction facing = bc.getFacing(); + Vec3d activeAreaOffset = actor.getActiveAreaOffset(context); + if (!activeAreaOffset.mul(VecHelper.axisAlingedPlaneOf(new Vec3d(facing.getDirectionVec()))) + .equals(Vec3d.ZERO)) + return false; + if (!VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) + return false; + context.motion = new Vec3d(facing.getDirectionVec()).scale(angle - prevAngle); + context.relativeMotion = context.motion; + int timer = context.data.getInt("StationaryTimer"); + if (timer > 0) { + context.data.putInt("StationaryTimer", timer - 1); + return false; + } + + context.data.putInt("StationaryTimer", 20); + return true; + } + + protected IControlContraption getController() { + if (controllerPos == null) + return null; + if (!world.isBlockPresent(controllerPos)) + return null; + TileEntity te = world.getTileEntity(controllerPos); + if (!(te instanceof IControlContraption)) + return null; + return (IControlContraption) te; + } + + @Override + protected StructureTransform makeStructureTransform() { + BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5)); + float xRot = rotationAxis == Axis.X ? angle : 0; + float yRot = rotationAxis == Axis.Y ? angle : 0; + float zRot = rotationAxis == Axis.Z ? angle : 0; + return new StructureTransform(offset, xRot, yRot, zRot); + } + + @Override + protected void onContraptionStalled() { + IControlContraption controller = getController(); + if (controller != null) + controller.onStall(); + super.onContraptionStalled(); + } + + @Override + protected float getStalledAngle() { + return angle; + } + + @Override + protected void handleStallInformation(float x, float y, float z, float angle) { + setPos(x, y, z); + this.angle = angle; + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java new file mode 100644 index 000000000..6567b0419 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ControlledContraptionEntityRenderer.java @@ -0,0 +1,29 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.util.Direction.Axis; + +public class ControlledContraptionEntityRenderer extends AbstractContraptionEntityRenderer { + + public ControlledContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { + super(p_i46179_1_); + } + + @Override + protected void transform(ControlledContraptionEntity entity, float partialTicks, + MatrixStack[] matrixStacks) { + float angle = entity.getAngle(partialTicks); + Axis axis = entity.getRotationAxis(); + + for (MatrixStack stack : matrixStacks) + MatrixStacker.of(stack) + .nudge(entity.getEntityId()) + .centre() + .rotate(angle, axis) + .unCentre(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java index 07a7fde89..e5d8c1c9f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/IControlContraption.java @@ -4,15 +4,21 @@ import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.INamedIconOptions; import com.simibubi.create.foundation.utility.Lang; +import net.minecraft.util.math.BlockPos; + public interface IControlContraption { - public boolean isAttachedTo(ContraptionEntity contraption); + public boolean isAttachedTo(AbstractContraptionEntity contraption); - public void attach(ContraptionEntity contraption); + public void attach(ControlledContraptionEntity contraption); public void onStall(); public boolean isValid(); + + public void collided(); + + public BlockPos getBlockPosition(); static enum MovementMode implements INamedIconOptions { @@ -70,6 +76,4 @@ public interface IControlContraption { } - public void collided(); - } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java new file mode 100644 index 000000000..0617a77e1 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedFluidStorage.java @@ -0,0 +1,5 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +public class MountedFluidStorage { + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java index e64dfc2df..e1b17a9e0 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MountedStorage.java @@ -20,7 +20,6 @@ import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.ItemStackHandler; -//FIXME: More dynamic mounted storage in .4 public class MountedStorage { private static final ItemStackHandler dummyHandler = new ItemStackHandler(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java index def5748e9..109c67c29 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovementContext.java @@ -29,10 +29,11 @@ public class MovementContext { public Contraption contraption; public Object temporaryData; - public MovementContext(World world, BlockInfo info) { + public MovementContext(World world, BlockInfo info, Contraption contraption) { this.world = world; this.state = info.state; this.tileData = info.nbt; + this.contraption = contraption; localPos = info.pos; firstMovement = true; @@ -54,8 +55,8 @@ public class MovementContext { return (((int) (length * modifier + 100 * Math.signum(length))) / 100) * 100; } - public static MovementContext readNBT(World world, BlockInfo info, CompoundNBT nbt) { - MovementContext context = new MovementContext(world, info); + public static MovementContext readNBT(World world, BlockInfo info, CompoundNBT nbt, Contraption contraption) { + MovementContext context = new MovementContext(world, info, contraption); context.motion = VecHelper.readNBT(nbt.getList("Motion", NBT.TAG_DOUBLE)); context.relativeMotion = VecHelper.readNBT(nbt.getList("RelativeMotion", NBT.TAG_DOUBLE)); if (nbt.contains("Position")) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java new file mode 100644 index 000000000..fc1c04a42 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntity.java @@ -0,0 +1,493 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import static com.simibubi.create.foundation.utility.AngleHelper.angleLerp; + +import java.util.Optional; +import java.util.UUID; + +import javax.annotation.Nullable; + +import com.simibubi.create.AllEntityTypes; +import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; +import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; +import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; +import com.simibubi.create.foundation.entity.CreateDataSerializers; +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.block.BlockState; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.entity.item.minecart.FurnaceMinecartEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.nbt.ListNBT; +import net.minecraft.nbt.NBTUtil; +import net.minecraft.network.datasync.DataParameter; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.EntityDataManager; +import net.minecraft.tags.BlockTags; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; +import net.minecraftforge.common.util.LazyOptional; + +/** + * Ex: Minecarts, Couplings
+ * Oriented Contraption Entities can rotate freely around two axes + * simultaneously. + */ +public class OrientedContraptionEntity extends AbstractContraptionEntity { + + private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL); + + private static final DataParameter> COUPLING = + EntityDataManager.createKey(OrientedContraptionEntity.class, DataSerializers.OPTIONAL_UNIQUE_ID); + private static final DataParameter> INITIAL_ORIENTATION = + EntityDataManager.createKey(OrientedContraptionEntity.class, CreateDataSerializers.OPTIONAL_DIRECTION); + + protected Vec3d motionBeforeStall; + protected boolean forceAngle; + private boolean isSerializingFurnaceCart; + private boolean attachedExtraInventories; + + public float prevYaw; + public float yaw; + public float targetYaw; + + public float prevPitch; + public float pitch; + public float targetPitch; + + // When placed using a contraption item + private float initialYawOffset; + + public OrientedContraptionEntity(EntityType type, World world) { + super(type, world); + motionBeforeStall = Vec3d.ZERO; + attachedExtraInventories = false; + isSerializingFurnaceCart = false; + initialYawOffset = -1; + } + + public static OrientedContraptionEntity create(World world, Contraption contraption, + Optional initialOrientation) { + OrientedContraptionEntity entity = + new OrientedContraptionEntity(AllEntityTypes.ORIENTED_CONTRAPTION.get(), world); + entity.setContraption(contraption); + initialOrientation.ifPresent(entity::setInitialOrientation); + entity.startAtInitialYaw(); + return entity; + } + + public void setInitialOrientation(Direction direction) { + dataManager.set(INITIAL_ORIENTATION, Optional.of(direction)); + } + + public Optional getInitialOrientation() { + return dataManager.get(INITIAL_ORIENTATION); + } + + public void deferOrientation(Direction newInitialAngle) { + dataManager.set(INITIAL_ORIENTATION, Optional.empty()); + yaw = initialYawOffset = newInitialAngle.getHorizontalAngle(); + } + + @Override + public float getYawOffset() { + return getInitialYaw(); + } + + public float getInitialYaw() { + return dataManager.get(INITIAL_ORIENTATION) + .orElse(Direction.SOUTH) + .getHorizontalAngle(); + } + + @Override + protected void registerData() { + super.registerData(); + dataManager.register(COUPLING, Optional.empty()); + dataManager.register(INITIAL_ORIENTATION, Optional.empty()); + } + + @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 (!world.isRemote && isAlive()) + disassemble(); + super.stopRiding(); + } + + @Override + protected void readAdditional(CompoundNBT compound) { + super.readAdditional(compound); + + if (compound.contains("InitialOrientation")) + setInitialOrientation(NBTHelper.readEnum(compound, "InitialOrientation", Direction.class)); + if (compound.contains("ForceYaw")) + startAtYaw(compound.getFloat("ForceYaw")); + + ListNBT vecNBT = compound.getList("CachedMotion", 6); + if (!vecNBT.isEmpty()) { + motionBeforeStall = new Vec3d(vecNBT.getDouble(0), vecNBT.getDouble(1), vecNBT.getDouble(2)); + if (!motionBeforeStall.equals(Vec3d.ZERO)) + targetYaw = prevYaw = yaw += yawFromVector(motionBeforeStall); + setMotion(Vec3d.ZERO); + } + + yaw = compound.getFloat("Yaw"); + pitch = compound.getFloat("Pitch"); + + setCouplingId( + compound.contains("OnCoupling") ? NBTUtil.readUniqueId(compound.getCompound("OnCoupling")) : null); + } + + @Override + protected void writeAdditional(CompoundNBT compound) { + super.writeAdditional(compound); + + if (motionBeforeStall != null) + compound.put("CachedMotion", + newDoubleNBTList(motionBeforeStall.x, motionBeforeStall.y, motionBeforeStall.z)); + + Optional optional = dataManager.get(INITIAL_ORIENTATION); + if (optional.isPresent()) + NBTHelper.writeEnum(compound, "InitialOrientation", optional.get()); + if (forceAngle) { + compound.putFloat("ForceYaw", yaw); + forceAngle = false; + } + + compound.putFloat("Yaw", yaw); + compound.putFloat("Pitch", pitch); + + if (getCouplingId() != null) + compound.put("OnCoupling", NBTUtil.writeUniqueId(getCouplingId())); + } + + @Override + public void notifyDataManagerChange(DataParameter key) { + super.notifyDataManagerChange(key); + if (key == INITIAL_ORIENTATION && dataManager.get(INITIAL_ORIENTATION) + .isPresent()) + startAtInitialYaw(); + } + + public void startAtInitialYaw() { + startAtYaw(getInitialYaw()); + } + + public void startAtYaw(float yaw) { + targetYaw = this.yaw = prevYaw = yaw; + forceAngle = true; + } + + @Override + public Vec3d applyRotation(Vec3d localPos, float partialTicks) { + localPos = VecHelper.rotate(localPos, getInitialYaw(), Axis.Y); + localPos = VecHelper.rotate(localPos, getPitch(partialTicks), Axis.Z); + localPos = VecHelper.rotate(localPos, getYaw(partialTicks), Axis.Y); + return localPos; + } + + @Override + public Vec3d reverseRotation(Vec3d localPos, float partialTicks) { + localPos = VecHelper.rotate(localPos, -getYaw(partialTicks), Axis.Y); + localPos = VecHelper.rotate(localPos, -getPitch(partialTicks), Axis.Z); + localPos = VecHelper.rotate(localPos, -getInitialYaw(), Axis.Y); + return localPos; + } + + public float getYaw(float partialTicks) { + return -(partialTicks == 1.0F ? yaw : angleLerp(partialTicks, prevYaw, yaw)); + } + + public float getPitch(float partialTicks) { + return partialTicks == 1.0F ? pitch : angleLerp(partialTicks, prevPitch, pitch); + } + + @Override + protected void tickContraption() { + Entity e = getRidingEntity(); + 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.getRidingEntity() != null && !(contraption instanceof StabilizedContraption)) + riding = riding.getRidingEntity(); + + boolean isOnCoupling = false; + UUID couplingId = getCouplingId(); + isOnCoupling = couplingId != null && riding instanceof AbstractMinecartEntity; + + if (!attachedExtraInventories) { + attachInventoriesFromRidingCarts(riding, isOnCoupling, couplingId); + attachedExtraInventories = true; + } + + boolean rotating = updateOrientation(rotationLock, wasStalled, riding, isOnCoupling); + if (!rotating || !pauseWhileRotating) + tickActors(); + boolean isStalled = isStalled(); + + LazyOptional capability = + riding.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); + if (capability.isPresent()) { + if (!world.isRemote()) + capability.orElse(null) + .setStalledExternally(isStalled); + } else { + if (isStalled) { + if (!wasStalled) + motionBeforeStall = riding.getMotion(); + riding.setMotion(0, 0, 0); + } + if (wasStalled && !isStalled) { + riding.setMotion(motionBeforeStall); + motionBeforeStall = Vec3d.ZERO; + } + } + + if (world.isRemote) + return; + + if (!isStalled()) { + if (isOnCoupling) { + Couple 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 coupledCarts = getCoupledCartsIfPresent(); + if (coupledCarts == null) + return false; + + Vec3d positionVec = coupledCarts.getFirst() + .cart() + .getPositionVec(); + Vec3d coupledVec = coupledCarts.getSecond() + .cart() + .getPositionVec(); + + double diffX = positionVec.x - coupledVec.x; + double diffY = positionVec.y - coupledVec.y; + double diffZ = positionVec.z - coupledVec.z; + + prevYaw = yaw; + prevPitch = pitch; + yaw = (float) (MathHelper.atan2(diffZ, diffX) * 180 / Math.PI); + pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI); + + if (getCouplingId().equals(riding.getUniqueID())) { + 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.getYaw(1); + return false; + } + + if (wasStalled) + return false; + + boolean rotating = false; + Vec3d movementVector = riding.getMotion(); + + if (!(riding instanceof AbstractMinecartEntity)) + movementVector = getPositionVec().subtract(prevPosX, prevPosY, prevPosZ); + Vec3d motion = movementVector.normalize(); + + if (!dataManager.get(INITIAL_ORIENTATION) + .isPresent() && !world.isRemote) { + if (motion.length() > 0) { + Direction facingFromVector = Direction.getFacingFromVector(motion.x, motion.y, motion.z); + if (initialYawOffset != -1) + facingFromVector = Direction.fromAngle(facingFromVector.getHorizontalAngle() - initialYawOffset); + if (facingFromVector.getAxis() + .isHorizontal()) + setInitialOrientation(facingFromVector); + } + } + + if (!rotationLock) { + if (motion.length() > 0) { + targetYaw = yawFromVector(motion); + if (targetYaw < 0) + targetYaw += 360; + if (yaw < 0) + yaw += 360; + } + + prevYaw = yaw; + yaw = angleLerp(0.4f, yaw, targetYaw); + if (Math.abs(AngleHelper.getShortestAngleDiff(yaw, targetYaw)) < 1f) + yaw = targetYaw; + else + rotating = true; + } + return rotating; + } + + protected void powerFurnaceCartWithFuelFromStorage(Entity riding) { + if (!(riding instanceof FurnaceMinecartEntity)) + return; + FurnaceMinecartEntity furnaceCart = (FurnaceMinecartEntity) riding; + + // Notify to not trigger serialization side-effects + isSerializingFurnaceCart = true; + CompoundNBT 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 = MathHelper.floor(furnaceCart.getX()); + int j = MathHelper.floor(furnaceCart.getY()); + int k = MathHelper.floor(furnaceCart.getZ()); + if (furnaceCart.world.getBlockState(new BlockPos(i, j - 1, k)) + .isIn(BlockTags.RAILS)) + --j; + + BlockPos blockpos = new BlockPos(i, j, k); + BlockState blockstate = this.world.getBlockState(blockpos); + if (furnaceCart.canUseRail() && blockstate.isIn(BlockTags.RAILS)) + if (fuel > 1) + riding.setMotion(riding.getMotion() + .normalize() + .scale(1)); + if (fuel < 5 && contraption != null) { + ItemStack coal = ItemHelper.extract(contraption.inventory, 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 getCoupledCartsIfPresent() { + UUID couplingId = getCouplingId(); + if (couplingId == null) + return null; + MinecartController controller = CapabilityMinecartController.getIfPresent(world, couplingId); + if (controller == null || !controller.isPresent()) + return null; + UUID coupledCart = controller.getCoupledCart(true); + MinecartController coupledController = CapabilityMinecartController.getIfPresent(world, coupledCart); + if (coupledController == null || !coupledController.isPresent()) + return null; + return Couple.create(controller, coupledController); + } + + protected void attachInventoriesFromRidingCarts(Entity riding, boolean isOnCoupling, UUID couplingId) { + if (isOnCoupling) { + Couple coupledCarts = getCoupledCartsIfPresent(); + if (coupledCarts == null) + return; + coupledCarts.map(MinecartController::cart) + .forEach(contraption::addExtraInventories); + return; + } + contraption.addExtraInventories(riding); + } + + @Override + public CompoundNBT writeWithoutTypeId(CompoundNBT nbt) { + return isSerializingFurnaceCart ? nbt : super.writeWithoutTypeId(nbt); + } + + @Nullable + public UUID getCouplingId() { + Optional uuid = dataManager.get(COUPLING); + return uuid == null ? null : uuid.isPresent() ? uuid.get() : null; + } + + public void setCouplingId(UUID id) { + dataManager.set(COUPLING, Optional.ofNullable(id)); + } + + @Override + public Vec3d getAnchorVec() { + return new Vec3d(getX() - .5, getY(), getZ() - .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(float x, float y, float z, float angle) { + yaw = angle; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java new file mode 100644 index 000000000..78604cfb8 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/OrientedContraptionEntityRenderer.java @@ -0,0 +1,96 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.foundation.utility.MatrixStacker; + +import net.minecraft.client.renderer.culling.ClippingHelperImpl; +import net.minecraft.client.renderer.entity.EntityRendererManager; +import net.minecraft.entity.Entity; +import net.minecraft.entity.item.minecart.AbstractMinecartEntity; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Vec3d; + +public class OrientedContraptionEntityRenderer extends AbstractContraptionEntityRenderer { + + public OrientedContraptionEntityRenderer(EntityRendererManager p_i46179_1_) { + super(p_i46179_1_); + } + + @Override + public boolean shouldRender(OrientedContraptionEntity entity, ClippingHelperImpl p_225626_2_, double p_225626_3_, + double p_225626_5_, double p_225626_7_) { + if (!super.shouldRender(entity, p_225626_2_, p_225626_3_, p_225626_5_, p_225626_7_)) + return false; + if (entity.getContraption() + .getType() == AllContraptionTypes.MOUNTED && entity.getRidingEntity() == null) + return false; + return true; + } + + @Override + protected void transform(OrientedContraptionEntity entity, float partialTicks, MatrixStack[] matrixStacks) { + float angleInitialYaw = entity.getInitialYaw(); + float angleYaw = entity.getYaw(partialTicks); + float anglePitch = entity.getPitch(partialTicks); + + for (MatrixStack stack : matrixStacks) + stack.translate(-.5f, 0, -.5f); + + Entity ridingEntity = entity.getRidingEntity(); + if (ridingEntity instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity); + if (ridingEntity instanceof AbstractContraptionEntity) { + if (ridingEntity.getRidingEntity() instanceof AbstractMinecartEntity) + repositionOnCart(partialTicks, matrixStacks, ridingEntity.getRidingEntity()); + else + repositionOnContraption(entity, partialTicks, matrixStacks, ridingEntity); + } + + for (MatrixStack stack : matrixStacks) + MatrixStacker.of(stack) + .nudge(entity.getEntityId()) + .centre() + .rotateY(angleYaw) + .rotateZ(anglePitch) + .rotateY(angleInitialYaw) + .unCentre(); + } + + private void repositionOnContraption(OrientedContraptionEntity entity, float partialTicks, + MatrixStack[] matrixStacks, Entity ridingEntity) { + AbstractContraptionEntity parent = (AbstractContraptionEntity) ridingEntity; + Vec3d passengerPosition = parent.getPassengerPosition(entity, partialTicks); + double x = passengerPosition.x - MathHelper.lerp(partialTicks, entity.lastTickPosX, entity.getX()); + double y = passengerPosition.y - MathHelper.lerp(partialTicks, entity.lastTickPosY, entity.getY()); + double z = passengerPosition.z - MathHelper.lerp(partialTicks, entity.lastTickPosZ, entity.getZ()); + for (MatrixStack stack : matrixStacks) + stack.translate(x, y, z); + } + + // Minecarts do not always render at their exact location, so the contraption + // has to adjust aswell + private void repositionOnCart(float partialTicks, MatrixStack[] matrixStacks, Entity ridingEntity) { + AbstractMinecartEntity cart = (AbstractMinecartEntity) ridingEntity; + double cartX = MathHelper.lerp(partialTicks, cart.lastTickPosX, cart.getX()); + double cartY = MathHelper.lerp(partialTicks, cart.lastTickPosY, cart.getY()); + double cartZ = MathHelper.lerp(partialTicks, cart.lastTickPosZ, cart.getZ()); + Vec3d cartPos = cart.getPos(cartX, cartY, cartZ); + + if (cartPos != null) { + Vec3d cartPosFront = cart.getPosOffset(cartX, cartY, cartZ, (double) 0.3F); + Vec3d cartPosBack = cart.getPosOffset(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; + + for (MatrixStack stack : matrixStacks) + stack.translate(cartX, cartY, cartZ); + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java index ded55dfad..ab0363569 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java @@ -40,19 +40,19 @@ public class StructureTransform { Axis rotationAxis; BlockPos offset; - public StructureTransform(BlockPos offset, Vec3d rotation) { + public StructureTransform(BlockPos offset, float xRotation, float yRotation, float zRotation) { this.offset = offset; - if (rotation.x != 0) { + if (xRotation != 0) { rotationAxis = Axis.X; - angle = (int) (Math.round(rotation.x / 90) * 90); + angle = (int) (Math.round(xRotation / 90) * 90); } - if (rotation.y != 0) { + if (yRotation != 0) { rotationAxis = Axis.Y; - angle = (int) (Math.round(rotation.y / 90) * 90); + angle = (int) (Math.round(yRotation / 90) * 90); } - if (rotation.z != 0) { + if (zRotation != 0) { rotationAxis = Axis.Z; - angle = (int) (Math.round(rotation.z / 90) * 90); + angle = (int) (Math.round(zRotation / 90) * 90); } angle %= 360; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java new file mode 100644 index 000000000..58d77be16 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/TranslatingContraption.java @@ -0,0 +1,45 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.HashSet; +import java.util.Set; + +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.template.Template.BlockInfo; + +public abstract class TranslatingContraption extends Contraption { + + protected Set cachedColliders; + protected Direction cachedColliderDirection; + + public Set getColliders(World world, Direction movementDirection) { + if (getBlocks() == null) + return null; + if (cachedColliders == null || cachedColliderDirection != movementDirection) { + cachedColliders = new HashSet<>(); + cachedColliderDirection = movementDirection; + + for (BlockInfo info : getBlocks().values()) { + BlockPos offsetPos = info.pos.offset(movementDirection); + if (info.state.getCollisionShape(world, offsetPos) + .isEmpty()) + continue; + if (getBlocks().containsKey(offsetPos) + && !getBlocks().get(offsetPos).state.getCollisionShape(world, offsetPos) + .isEmpty()) + continue; + cachedColliders.add(info.pos); + } + + } + return cachedColliders; + } + + @Override + protected boolean canAxisBeStabilized(Axis axis) { + return false; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java index a29da4fa1..8614d6c60 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java @@ -6,9 +6,11 @@ import com.simibubi.create.AllTags.AllBlockTags; import com.simibubi.create.content.contraptions.components.structureMovement.AllContraptionTypes; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import net.minecraft.client.renderer.FaceDirection; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; @@ -17,41 +19,53 @@ public class BearingContraption extends Contraption { protected int sailBlocks; protected Direction facing; + + private boolean isWindmill; + + public BearingContraption() {} + + public BearingContraption(boolean isWindmill, Direction facing) { + this.isWindmill = isWindmill; + this.facing = facing; + } + + @Override + public boolean assemble(World world, BlockPos pos) { + BlockPos offset = pos.offset(facing); + if (!searchMovedStructure(world, offset, null)) + return false; + startMoving(world); + expandBoundsAroundAxis(facing.getAxis()); + if (isWindmill && sailBlocks == 0) + return false; + if (blocks.isEmpty()) + return false; + return true; + } @Override protected AllContraptionTypes getType() { return AllContraptionTypes.BEARING; } - public static BearingContraption assembleBearingAt(World world, BlockPos pos, Direction direction) { - BearingContraption construct = new BearingContraption(); - construct.facing = direction; - BlockPos offset = pos.offset(direction); - if (!construct.searchMovedStructure(world, offset, null)) - return null; - construct.initActors(world); - construct.expandBoundsAroundAxis(direction.getAxis()); - return construct; - } - @Override protected boolean isAnchoringBlockAt(BlockPos pos) { return pos.equals(anchor.offset(facing.getOpposite())); } @Override - public void add(BlockPos pos, Pair capture) { + public void addBlock(BlockPos pos, Pair capture) { BlockPos localPos = pos.subtract(anchor); - if (!blocks.containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state)) + if (!getBlocks().containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state)) sailBlocks++; - super.add(pos, capture); + super.addBlock(pos, capture); } @Override public CompoundNBT writeNBT() { CompoundNBT tag = super.writeNBT(); tag.putInt("Sails", sailBlocks); - tag.putInt("facing", facing.getIndex()); + tag.putInt("Facing", facing.getIndex()); return tag; } @@ -70,4 +84,9 @@ public class BearingContraption extends Contraption { return facing; } + @Override + protected boolean canAxisBeStabilized(Axis axis) { + return axis == facing.getAxis(); + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java index 7c89c3e20..85a712499 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkBearingTileEntity.java @@ -5,7 +5,8 @@ import java.util.List; import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption.HandType; import com.simibubi.create.foundation.gui.AllIcons; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; @@ -15,20 +16,19 @@ import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.ServerSpeedProvider; +import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; public class ClockworkBearingTileEntity extends KineticTileEntity implements IBearingTileEntity { - protected ContraptionEntity hourHand; - protected ContraptionEntity minuteHand; + protected ControlledContraptionEntity hourHand; + protected ControlledContraptionEntity minuteHand; protected float hourAngle; protected float minuteAngle; protected float clientHourAngleDiff; @@ -71,7 +71,9 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe assembleNextTick = false; if (running) { boolean canDisassemble = true; - if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption().blocks.isEmpty())) { + if (speed == 0 && (canDisassemble || hourHand == null || hourHand.getContraption() + .getBlocks() + .isEmpty())) { if (hourHand != null) hourHand.getContraption() .stop(world); @@ -103,19 +105,18 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } protected void applyRotations() { - Axis axis = getBlockState().get(BlockStateProperties.FACING) - .getAxis(); - Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); - Vec3d directionVec = new Vec3d(direction.getDirectionVec()); + BlockState blockState = getBlockState(); + Axis axis = Axis.X; + if (blockState.has(BlockStateProperties.FACING)) + axis = blockState.get(BlockStateProperties.FACING).getAxis(); + if (hourHand != null) { - Vec3d vec = new Vec3d(1, 1, 1).scale(hourAngle) - .mul(directionVec); - hourHand.rotateTo(vec.x, vec.y, vec.z); + hourHand.setAngle(hourAngle); + hourHand.setRotationAxis(axis); } if (minuteHand != null) { - Vec3d vec = new Vec3d(1, 1, 1).scale(minuteAngle) - .mul(directionVec); - minuteHand.rotateTo(vec.x, vec.y, vec.z); + minuteHand.setAngle(minuteAngle); + minuteHand.setRotationAxis(axis); } } @@ -202,24 +203,26 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe return; if (contraption.getLeft() == null) return; - if (contraption.getLeft().blocks.isEmpty()) + if (contraption.getLeft() + .getBlocks() + .isEmpty()) return; BlockPos anchor = pos.offset(direction); contraption.getLeft() .removeBlocksFromWorld(world, BlockPos.ZERO); - hourHand = ContraptionEntity.createStationary(world, contraption.getLeft()) - .controlledBy(this); + hourHand = ControlledContraptionEntity.create(world, this, contraption.getLeft()); hourHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); + hourHand.setRotationAxis(direction.getAxis()); world.addEntity(hourHand); if (contraption.getRight() != null) { anchor = pos.offset(direction, contraption.getRight().offset + 1); contraption.getRight() .removeBlocksFromWorld(world, BlockPos.ZERO); - minuteHand = ContraptionEntity.createStationary(world, contraption.getRight()) - .controlledBy(this); + minuteHand = ControlledContraptionEntity.create(world, this, contraption.getRight()); minuteHand.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); + minuteHand.setRotationAxis(direction.getAxis()); world.addEntity(minuteHand); } @@ -251,7 +254,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } @Override - public void attach(ContraptionEntity contraption) { + public void attach(ControlledContraptionEntity contraption) { if (!(contraption.getContraption() instanceof ClockworkContraption)) return; @@ -339,7 +342,7 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe public void collided() {} @Override - public boolean isAttachedTo(ContraptionEntity contraption) { + public boolean isAttachedTo(AbstractContraptionEntity contraption) { if (!(contraption.getContraption() instanceof ClockworkContraption)) return false; ClockworkContraption cc = (ClockworkContraption) contraption.getContraption(); @@ -381,4 +384,9 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe } + @Override + public BlockPos getBlockPosition() { + return pos; + } + } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java index 7cc15d761..7a772108d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/ClockworkContraption.java @@ -12,6 +12,7 @@ import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -38,7 +39,7 @@ public class ClockworkContraption extends Contraption { } public static Pair assembleClockworkAt(World world, BlockPos pos, - Direction direction) { + Direction direction) { int hourArmBlocks = 0; ClockworkContraption hourArm = new ClockworkContraption(); @@ -46,11 +47,12 @@ public class ClockworkContraption extends Contraption { hourArm.facing = direction; hourArm.handType = HandType.HOUR; - if (!hourArm.searchMovedStructure(world, pos, direction)) + if (!hourArm.assemble(world, pos)) return null; for (int i = 0; i < 16; i++) { BlockPos offsetPos = BlockPos.ZERO.offset(direction, i); - if (hourArm.blocks.containsKey(offsetPos)) + if (hourArm.getBlocks() + .containsKey(offsetPos)) continue; hourArmBlocks = i; break; @@ -61,21 +63,28 @@ public class ClockworkContraption extends Contraption { minuteArm.facing = direction; minuteArm.handType = HandType.MINUTE; minuteArm.offset = hourArmBlocks; - minuteArm.ignoreBlocks(hourArm.blocks.keySet(), hourArm.anchor); - if (!minuteArm.searchMovedStructure(world, pos, direction)) + minuteArm.ignoreBlocks(hourArm.getBlocks() + .keySet(), hourArm.anchor); + if (!minuteArm.assemble(world, pos)) return null; - if (minuteArm.blocks.isEmpty()) + if (minuteArm.getBlocks() + .isEmpty()) minuteArm = null; } - hourArm.initActors(world); + hourArm.startMoving(world); hourArm.expandBoundsAroundAxis(direction.getAxis()); if (minuteArm != null) { - minuteArm.initActors(world); + minuteArm.startMoving(world); minuteArm.expandBoundsAroundAxis(direction.getAxis()); } return Pair.of(hourArm, minuteArm); } + + @Override + public boolean assemble(World world, BlockPos pos) { + return searchMovedStructure(world, pos, facing); + } @Override public boolean searchMovedStructure(World world, BlockPos pos, Direction direction) { @@ -84,7 +93,7 @@ public class ClockworkContraption extends Contraption { @Override protected boolean moveBlock(World world, BlockPos pos, Direction direction, List frontier, - Set visited) { + Set visited) { if (ignoreBlocks.contains(pos)) return true; return super.moveBlock(world, pos, direction, frontier, visited); @@ -107,6 +116,11 @@ public class ClockworkContraption extends Contraption { super.readNBT(world, tag); } + @Override + protected boolean canAxisBeStabilized(Axis axis) { + return axis == facing.getAxis(); + } + public static enum HandType { HOUR, MINUTE } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java index b64162e31..2c8ffb149 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/MechanicalBearingTileEntity.java @@ -5,7 +5,8 @@ import static net.minecraft.state.properties.BlockStateProperties.FACING; import java.util.List; import com.simibubi.create.content.contraptions.base.GeneratingKineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollOptionBehaviour; @@ -15,18 +16,16 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider; import net.minecraft.block.BlockState; import net.minecraft.nbt.CompoundNBT; +import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; -import net.minecraft.util.Direction.Axis; -import net.minecraft.util.Direction.AxisDirection; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.Vec3d; public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity implements IBearingTileEntity { protected ScrollOptionBehaviour movementMode; - protected ContraptionEntity movedContraption; + protected ControlledContraptionEntity movedContraption; protected float angle; protected boolean running; protected boolean assembleNextTick; @@ -108,30 +107,28 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp return false; } + @Override + public BlockPos getBlockPosition() { + return pos; + } + public void assemble() { if (!(world.getBlockState(pos) .getBlock() instanceof BearingBlock)) return; Direction direction = getBlockState().get(FACING); + BearingContraption contraption = new BearingContraption(isWindmill(), direction); + if (!contraption.assemble(world, pos)) + return; - // Collect Construct - BearingContraption contraption = BearingContraption.assembleBearingAt(world, pos, direction); - if (contraption == null) - return; - if (isWindmill() && contraption.getSailBlocks() == 0) - return; - if (contraption.blocks.isEmpty()) - return; contraption.removeBlocksFromWorld(world, BlockPos.ZERO); - - movedContraption = ContraptionEntity.createStationary(world, contraption) - .controlledBy(this); + movedContraption = ControlledContraptionEntity.create(world, this, contraption); BlockPos anchor = pos.offset(direction); movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); + movedContraption.setRotationAxis(direction.getAxis()); world.addEntity(movedContraption); - // Run running = true; angle = 0; sendData(); @@ -166,8 +163,9 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp if (running) { boolean canDisassemble = movementMode.get() == RotationMode.ROTATE_PLACE || (isNearInitialAngle() && movementMode.get() == RotationMode.ROTATE_PLACE_RETURNED); - if (speed == 0 && (canDisassemble || movedContraption == null - || movedContraption.getContraption().blocks.isEmpty())) { + if (speed == 0 && (canDisassemble || movedContraption == null || movedContraption.getContraption() + .getBlocks() + .isEmpty())) { if (movedContraption != null) movedContraption.getContraption() .stop(world); @@ -206,18 +204,17 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp } protected void applyRotation() { - if (movedContraption != null) { - Axis axis = getBlockState().get(FACING) - .getAxis(); - Direction direction = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis); - Vec3d vec = new Vec3d(1, 1, 1).scale(angle) - .mul(new Vec3d(direction.getDirectionVec())); - movedContraption.rotateTo(vec.x, vec.y, vec.z); - } + if (movedContraption == null) + return; + movedContraption.setAngle(angle); + BlockState blockState = getBlockState(); + if (blockState.has(BlockStateProperties.FACING)) + movedContraption.setRotationAxis(blockState.get(BlockStateProperties.FACING) + .getAxis()); } @Override - public void attach(ContraptionEntity contraption) { + public void attach(ControlledContraptionEntity contraption) { BlockState blockState = getBlockState(); if (!(contraption.getContraption() instanceof BearingContraption)) return; @@ -249,7 +246,7 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp public void collided() {} @Override - public boolean isAttachedTo(ContraptionEntity contraption) { + public boolean isAttachedTo(AbstractContraptionEntity contraption) { return movedContraption == contraption; } @@ -263,15 +260,14 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp return true; if (isPlayerSneaking) return false; - if (isWindmill()) - return false; - if (getSpeed() == 0) + if (!isWindmill() && getSpeed() == 0) return false; if (running) return false; BlockState state = getBlockState(); if (!(state.getBlock() instanceof BearingBlock)) return false; + BlockState attachedState = world.getBlockState(pos.offset(state.get(BearingBlock.FACING))); if (attachedState.getMaterial() .isReplaceable()) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java new file mode 100644 index 000000000..598c84a12 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedBearingMovementBehaviour.java @@ -0,0 +1,73 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import java.util.Optional; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.simibubi.create.AllBlockPartials; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; +import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.SuperByteBuffer; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.IRenderTypeBuffer; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.state.properties.BlockStateProperties; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +public class StabilizedBearingMovementBehaviour extends MovementBehaviour { + + @Override + @OnlyIn(Dist.CLIENT) + public void renderInContraption(MovementContext context, MatrixStack ms, MatrixStack msLocal, + IRenderTypeBuffer buffer) { + Direction facing = context.state.get(BlockStateProperties.FACING); + AllBlockPartials top = AllBlockPartials.BEARING_TOP; + SuperByteBuffer superBuffer = top.renderOn(context.state); + float renderPartialTicks = Minecraft.getInstance() + .getRenderPartialTicks(); + + // rotate to match blockstate + Axis axis = facing.getAxis(); + if (axis.isHorizontal()) + superBuffer.rotateCentered(Direction.UP, + AngleHelper.rad(AngleHelper.horizontalAngle(facing.getOpposite()))); + superBuffer.rotateCentered(Direction.EAST, AngleHelper.rad(-90 - AngleHelper.verticalAngle(facing))); + + // rotate against parent + float offset = 0; + int offsetMultiplier = facing.getAxisDirection().getOffset(); + + AbstractContraptionEntity entity = context.contraption.entity; + if (entity instanceof ControlledContraptionEntity) { + ControlledContraptionEntity controlledCE = (ControlledContraptionEntity) entity; + if (controlledCE.getRotationAxis() == axis) + offset = -controlledCE.getAngle(renderPartialTicks); + + } else if (entity instanceof OrientedContraptionEntity) { + OrientedContraptionEntity orientedCE = (OrientedContraptionEntity) entity; + if (axis.isVertical()) + offset = -orientedCE.getYaw(renderPartialTicks); + else { + Optional initialOrientation = orientedCE.getInitialOrientation(); + if (initialOrientation.isPresent() && initialOrientation.get() + .getAxis() == axis) + offset = -orientedCE.getPitch(renderPartialTicks); + } + } + if (offset != 0) + superBuffer.rotateCentered(Direction.UP, AngleHelper.rad(offset * offsetMultiplier)); + + // render + superBuffer.light(msLocal.peek() + .getModel()); + superBuffer.renderInto(ms, buffer.getBuffer(RenderType.getSolid())); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java new file mode 100644 index 000000000..2e70f6f92 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/StabilizedContraption.java @@ -0,0 +1,66 @@ +package com.simibubi.create.content.contraptions.components.structureMovement.bearing; + +import com.simibubi.create.content.contraptions.components.structureMovement.AllContraptionTypes; +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; + +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.util.Direction; +import net.minecraft.util.Direction.Axis; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class StabilizedContraption extends Contraption { + + private Direction facing; + + public StabilizedContraption() {} + + public StabilizedContraption(Direction facing) { + this.facing = facing; + } + + @Override + public boolean assemble(World world, BlockPos pos) { + BlockPos offset = pos.offset(facing); + if (!searchMovedStructure(world, offset, null)) + return false; + startMoving(world); + expandBoundsAroundAxis(Axis.Y); + if (blocks.isEmpty()) + return false; + return true; + } + + @Override + protected boolean isAnchoringBlockAt(BlockPos pos) { + return false; + } + + @Override + protected AllContraptionTypes getType() { + return AllContraptionTypes.STABILIZED; + } + + @Override + public CompoundNBT writeNBT() { + CompoundNBT tag = super.writeNBT(); + tag.putInt("Facing", facing.getIndex()); + return tag; + } + + @Override + public void readNBT(World world, CompoundNBT tag) { + facing = Direction.byIndex(tag.getInt("Facing")); + super.readNBT(world, tag); + } + + @Override + protected boolean canAxisBeStabilized(Axis axis) { + return false; + } + + public Direction getFacing() { + return facing; + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java index 249e4e84f..9186c3b20 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/CartAssemblerBlock.java @@ -11,7 +11,7 @@ import javax.annotation.Nullable; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.AllTileEntities; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.CartAssemblerTileEntity.CartMovementMode; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; @@ -225,13 +225,13 @@ public class CartAssemblerBlock extends AbstractRailBlock .isCoupledThroughContraption()) return; - MountedContraption contraption = MountedContraption.assembleMinecart(world, pos); - if (contraption == null) - return; - if (contraption.blocks.size() == 1) - return; + CartMovementMode mode = + getTileEntityOptional(world, pos).map(te -> CartMovementMode.values()[te.movementMode.value]) + .orElse(CartMovementMode.ROTATE); - withTileEntityDo(world, pos, te -> contraption.rotationMode = CartMovementMode.values()[te.movementMode.value]); + MountedContraption contraption = new MountedContraption(mode); + if (!contraption.assemble(world, pos)) + return; boolean couplingFound = contraption.connectedCart != null; Optional initialOrientation = cart.getMotion() @@ -245,7 +245,7 @@ public class CartAssemblerBlock extends AbstractRailBlock } contraption.removeBlocksFromWorld(world, BlockPos.ZERO); - contraption.initActors(world); + contraption.startMoving(world); contraption.expandBoundsAroundAxis(Axis.Y); if (couplingFound) { @@ -254,7 +254,7 @@ public class CartAssemblerBlock extends AbstractRailBlock initialOrientation = Optional.of(Direction.fromAngle(MathHelper.atan2(diff.z, diff.x) * 180 / Math.PI)); } - ContraptionEntity entity = ContraptionEntity.createMounted(world, contraption, initialOrientation); + OrientedContraptionEntity entity = OrientedContraptionEntity.create(world, contraption, initialOrientation); if (couplingFound) entity.setCouplingId(cart.getUniqueID()); entity.setPosition(pos.getX(), pos.getY(), pos.getZ()); @@ -275,9 +275,9 @@ public class CartAssemblerBlock extends AbstractRailBlock return; Entity entity = cart.getPassengers() .get(0); - if (!(entity instanceof ContraptionEntity)) + if (!(entity instanceof OrientedContraptionEntity)) return; - ContraptionEntity contraption = (ContraptionEntity) entity; + OrientedContraptionEntity contraption = (OrientedContraptionEntity) entity; UUID couplingId = contraption.getCouplingId(); if (couplingId == null) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java index 191de2638..b3822ff1c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MinecartContraptionItem.java @@ -6,8 +6,9 @@ import java.util.Optional; import javax.annotation.Nullable; import com.simibubi.create.AllItems; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.foundation.utility.NBTHelper; import net.minecraft.block.AbstractRailBlock; @@ -29,7 +30,6 @@ import net.minecraft.state.properties.RailShape; import net.minecraft.tags.BlockTags; import net.minecraft.util.ActionResultType; import net.minecraft.util.Direction; -import net.minecraft.util.Direction.Axis; import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; @@ -162,16 +162,14 @@ public class MinecartContraptionItem extends Item { if (tag.contains("Contraption")) { CompoundNBT contraptionTag = tag.getCompound("Contraption"); - Direction initialOrientation = Direction.SOUTH; + Optional intialOrientation = Optional.empty(); if (contraptionTag.contains("InitialOrientation")) - initialOrientation = NBTHelper.readEnum(contraptionTag, "InitialOrientation", Direction.class); + intialOrientation = + Optional.of(NBTHelper.readEnum(contraptionTag, "InitialOrientation", Direction.class)); Contraption mountedContraption = Contraption.fromNBT(world, contraptionTag); - ContraptionEntity contraptionEntity = - ContraptionEntity.createMounted(world, mountedContraption, Optional.of(initialOrientation)); - - if (newFacing != null) - contraptionEntity.reOrientate(newFacing.getAxis() == Axis.X ? newFacing : newFacing.getOpposite()); + OrientedContraptionEntity contraptionEntity = + OrientedContraptionEntity.create(world, mountedContraption, intialOrientation); contraptionEntity.startRiding(cart); contraptionEntity.setPosition(cart.getX(), cart.getY(), cart.getZ()); @@ -197,7 +195,7 @@ public class MinecartContraptionItem extends Item { ItemStack wrench = player.getHeldItem(event.getHand()); if (!AllItems.WRENCH.isIn(wrench)) return; - if (entity instanceof ContraptionEntity) + if (entity instanceof AbstractContraptionEntity) entity = entity.getRidingEntity(); if (!(entity instanceof AbstractMinecartEntity)) return; @@ -206,9 +204,9 @@ public class MinecartContraptionItem extends Item { if (type != Type.RIDEABLE && type != Type.FURNACE && type != Type.CHEST) return; List passengers = cart.getPassengers(); - if (passengers.isEmpty() || !(passengers.get(0) instanceof ContraptionEntity)) + if (passengers.isEmpty() || !(passengers.get(0) instanceof OrientedContraptionEntity)) return; - ContraptionEntity contraption = (ContraptionEntity) passengers.get(0); + OrientedContraptionEntity contraption = (OrientedContraptionEntity) passengers.get(0); if (!event.getWorld().isRemote) { player.inventory.placeItemBackInInventory(event.getWorld(), create(type, contraption)); @@ -220,21 +218,26 @@ public class MinecartContraptionItem extends Item { event.setCanceled(true); } - public static ItemStack create(Type type, ContraptionEntity entity) { + public static ItemStack create(Type type, OrientedContraptionEntity entity) { ItemStack stack = ItemStack.EMPTY; + switch (type) { - case RIDEABLE: - stack = AllItems.MINECART_CONTRAPTION.asStack(); - break; - case FURNACE: - stack = AllItems.FURNACE_MINECART_CONTRAPTION.asStack(); - break; - case CHEST: - stack = AllItems.CHEST_MINECART_CONTRAPTION.asStack(); - break; + case RIDEABLE: + stack = AllItems.MINECART_CONTRAPTION.asStack(); + break; + case FURNACE: + stack = AllItems.FURNACE_MINECART_CONTRAPTION.asStack(); + break; + case CHEST: + stack = AllItems.CHEST_MINECART_CONTRAPTION.asStack(); + break; + default: + break; } - if (stack == ItemStack.EMPTY) + + if (stack.isEmpty()) return stack; + CompoundNBT tag = entity.getContraption() .writeNBT(); tag.remove("UUID"); @@ -243,7 +246,7 @@ public class MinecartContraptionItem extends Item { Optional initialOrientation = entity.getInitialOrientation(); if (initialOrientation.isPresent()) - NBTHelper.writeEnum(tag, "InitialOrientation", initialOrientation.orElse(null)); + NBTHelper.writeEnum(tag, "InitialOrientation", initialOrientation.get()); stack.getOrCreateTag() .put("Contraption", tag); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java index 82b11e8a8..47c47f5f1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/mounted/MountedContraption.java @@ -39,29 +39,36 @@ public class MountedContraption extends Contraption { public AbstractMinecartEntity connectedCart; public MountedContraption() { - rotationMode = CartMovementMode.ROTATE; + this(CartMovementMode.ROTATE); + } + + public MountedContraption(CartMovementMode mode) { + rotationMode = mode; } @Override protected AllContraptionTypes getType() { return AllContraptionTypes.MOUNTED; } - - public static MountedContraption assembleMinecart(World world, BlockPos pos) { + + @Override + public boolean assemble(World world, BlockPos pos) { BlockState state = world.getBlockState(pos); if (!state.has(RAIL_SHAPE)) - return null; - - MountedContraption contraption = new MountedContraption(); - if (!contraption.searchMovedStructure(world, pos, null)) - return null; - + return false; + if (!searchMovedStructure(world, pos, null)) + return false; + Axis axis = state.get(RAIL_SHAPE) == RailShape.EAST_WEST ? Axis.X : Axis.Z; - contraption.add(pos, Pair.of(new BlockInfo(pos, AllBlocks.MINECART_ANCHOR.getDefaultState() + addBlock(pos, Pair.of(new BlockInfo(pos, AllBlocks.MINECART_ANCHOR.getDefaultState() .with(BlockStateProperties.HORIZONTAL_AXIS, axis), null), null)); - return contraption; + + if (blocks.size() == 1) + return false; + + return true; } - + @Override protected boolean addToInitialFrontier(World world, BlockPos pos, Direction direction, List frontier) { frontier.clear(); @@ -140,7 +147,12 @@ public class MountedContraption extends Contraption { protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { return AllBlocks.MINECART_ANCHOR.has(state); } - + + @Override + protected boolean canAxisBeStabilized(Axis axis) { + return true; + } + @Override public void addExtraInventories(Entity cart) { if (!(cart instanceof IInventory)) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java index c7148ec54..1a63715bb 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/LinearActuatorTileEntity.java @@ -3,7 +3,8 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pi import java.util.List; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.IControlContraption; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; @@ -13,6 +14,7 @@ import com.simibubi.create.foundation.utility.ServerSpeedProvider; import net.minecraft.nbt.CompoundNBT; import net.minecraft.tileentity.TileEntityType; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; @@ -21,7 +23,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme public float offset; public boolean running; public boolean assembleNextTick; - public ContraptionEntity movedContraption; + public AbstractContraptionEntity movedContraption; protected boolean forceMove; protected ScrollOptionBehaviour movementMode; protected boolean waitingForSpeedChange; @@ -267,7 +269,7 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme } @Override - public void attach(ContraptionEntity contraption) { + public void attach(ControlledContraptionEntity contraption) { this.movedContraption = contraption; if (!world.isRemote) { this.running = true; @@ -276,8 +278,13 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme } @Override - public boolean isAttachedTo(ContraptionEntity contraption) { + public boolean isAttachedTo(AbstractContraptionEntity contraption) { return movedContraption == contraption; } + + @Override + public BlockPos getBlockPosition() { + return pos; + } } \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java index 74720c617..f84a04b97 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/MechanicalPistonTileEntity.java @@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pi import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.base.IRotate; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.DirectionalExtenderScrollOptionSlot; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform; @@ -49,20 +49,17 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { Direction direction = getBlockState().get(BlockStateProperties.FACING); // Collect Construct - PistonContraption contraption = PistonContraption.movePistonAt(world, pos, direction, getMovementSpeed() < 0); + PistonContraption contraption = new PistonContraption(direction, getMovementSpeed() < 0); + if (!contraption.assemble(world, pos)) + return; + Direction positive = Direction.getFacingFromAxis(AxisDirection.POSITIVE, direction.getAxis()); Direction movementDirection = getSpeed() > 0 ^ direction.getAxis() != Axis.Z ? positive : positive.getOpposite(); - if (contraption != null) { - BlockPos anchor = contraption.getAnchor() - .offset(direction, contraption.initialExtensionProgress); - if (ContraptionCollider.isCollidingWithWorld(world, contraption, anchor.offset(movementDirection), - movementDirection)) - contraption = null; - } - - if (contraption == null) + BlockPos anchor = contraption.anchor.offset(direction, contraption.initialExtensionProgress); + if (ContraptionCollider.isCollidingWithWorld(world, contraption, anchor.offset(movementDirection), + movementDirection)) return; // Check if not at limit already @@ -80,8 +77,7 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { BlockPos startPos = BlockPos.ZERO.offset(direction, contraption.initialExtensionProgress); contraption.removeBlocksFromWorld(world, startPos); - movedContraption = ContraptionEntity.createStationary(getWorld(), contraption) - .controlledBy(this); + movedContraption = ControlledContraptionEntity.create(getWorld(), this, contraption); applyContraptionPosition(); forceMove = true; world.addEntity(movedContraption); @@ -147,8 +143,7 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity { protected Vec3d toPosition(float offset) { Vec3d position = new Vec3d(getBlockState().get(BlockStateProperties.FACING) .getDirectionVec()).scale(offset); - return position.add(new Vec3d(movedContraption.getContraption() - .getAnchor())); + return position.add(new Vec3d(movedContraption.getContraption().anchor)); } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java index 79b69b36f..9e0e0972d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/piston/PistonContraption.java @@ -15,16 +15,14 @@ import org.apache.commons.lang3.tuple.Pair; import com.simibubi.create.content.contraptions.components.structureMovement.AllContraptionTypes; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.PistonState; import com.simibubi.create.foundation.config.AllConfigs; -import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; import net.minecraft.block.CarpetBlock; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.nbt.ListNBT; import net.minecraft.state.properties.BlockStateProperties; import net.minecraft.state.properties.PistonType; import net.minecraft.tileentity.TileEntity; @@ -35,28 +33,36 @@ import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; -public class PistonContraption extends Contraption { - - protected AxisAlignedBB pistonExtensionCollisionBox; +public class PistonContraption extends TranslatingContraption { protected int extensionLength; protected int initialExtensionProgress; protected Direction orientation; + private AxisAlignedBB pistonExtensionCollisionBox; + private boolean retract; + @Override protected AllContraptionTypes getType() { return AllContraptionTypes.PISTON; } - public static PistonContraption movePistonAt(World world, BlockPos pos, Direction direction, boolean retract) { - PistonContraption construct = new PistonContraption(); - construct.orientation = direction; - if (!construct.collectExtensions(world, pos, direction)) - return null; - if (!construct.searchMovedStructure(world, construct.anchor, retract ? direction.getOpposite() : direction)) - return null; - construct.initActors(world); - return construct; + public PistonContraption() {} + + public PistonContraption(Direction direction, boolean retract) { + orientation = direction; + this.retract = retract; + } + + @Override + public boolean assemble(World world, BlockPos pos) { + if (!collectExtensions(world, pos, orientation)) + return false; + if (!searchMovedStructure(world, anchor, retract ? orientation.getOpposite() : orientation)) + return false; + bounds = bounds.union(pistonExtensionCollisionBox); + startMoving(world); + return true; } private boolean collectExtensions(World world, BlockPos pos, Direction direction) { @@ -123,7 +129,7 @@ public class PistonContraption extends Contraption { for (BlockInfo pole : poles) { BlockPos relPos = pole.pos.offset(direction, -extensionsInFront); BlockPos localPos = relPos.subtract(anchor); - blocks.put(localPos, new BlockInfo(localPos, pole.state, null)); + getBlocks().put(localPos, new BlockInfo(localPos, pole.state, null)); pistonExtensionCollisionBox = pistonExtensionCollisionBox.union(new AxisAlignedBB(localPos)); } @@ -165,8 +171,8 @@ public class PistonContraption extends Contraption { } @Override - public void add(BlockPos pos, Pair capture) { - super.add(pos.offset(orientation, -initialExtensionProgress), capture); + public void addBlock(BlockPos pos, Pair capture) { + super.addBlock(pos.offset(orientation, -initialExtensionProgress), capture); } @Override @@ -205,30 +211,18 @@ public class PistonContraption extends Contraption { @Override public void readNBT(World world, CompoundNBT nbt) { super.readNBT(world, nbt); - extensionLength = nbt.getInt("ExtensionLength"); initialExtensionProgress = nbt.getInt("InitialLength"); + extensionLength = nbt.getInt("ExtensionLength"); orientation = Direction.byIndex(nbt.getInt("Orientation")); - if (nbt.contains("BoundsBack")) - pistonExtensionCollisionBox = NBTHelper.readAABB(nbt.getList("BoundsBack", 5)); } @Override public CompoundNBT writeNBT() { CompoundNBT nbt = super.writeNBT(); - - if (pistonExtensionCollisionBox != null) { - ListNBT bb = NBTHelper.writeAABB(pistonExtensionCollisionBox); - nbt.put("BoundsBack", bb); - } nbt.putInt("InitialLength", initialExtensionProgress); nbt.putInt("ExtensionLength", extensionLength); nbt.putInt("Orientation", orientation.getIndex()); - return nbt; } - @Override - public AxisAlignedBB getBoundingBox() { - return super.getBoundingBox().union(pistonExtensionCollisionBox); - } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java index 32b8b3a3f..021206c24 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyContraption.java @@ -1,13 +1,13 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pulley; import com.simibubi.create.content.contraptions.components.structureMovement.AllContraptionTypes; -import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.TranslatingContraption; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; -public class PulleyContraption extends Contraption { +public class PulleyContraption extends TranslatingContraption { int initialOffset; @@ -16,13 +16,18 @@ public class PulleyContraption extends Contraption { return AllContraptionTypes.PULLEY; } - public static PulleyContraption assemblePulleyAt(World world, BlockPos pos, int initialOffset) { - PulleyContraption construct = new PulleyContraption(); - construct.initialOffset = initialOffset; - if (!construct.searchMovedStructure(world, pos, null)) - return null; - construct.initActors(world); - return construct; + public PulleyContraption() {} + + public PulleyContraption(int initialOffset) { + this.initialOffset = initialOffset; + } + + @Override + public boolean assemble(World world, BlockPos pos) { + if (!searchMovedStructure(world, pos, null)) + return false; + startMoving(world); + return true; } @Override diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java index 01b88c2c3..0922e6ba1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyRenderer.java @@ -4,7 +4,7 @@ import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlocks; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.base.KineticTileEntity; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.foundation.utility.SuperByteBuffer; import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher; @@ -19,7 +19,8 @@ public class PulleyRenderer extends AbstractPulleyRenderer { @Override protected Axis getShaftAxis(KineticTileEntity te) { - return te.getBlockState().get(PulleyBlock.HORIZONTAL_AXIS); + return te.getBlockState() + .get(PulleyBlock.HORIZONTAL_AXIS); } @Override @@ -43,15 +44,14 @@ public class PulleyRenderer extends AbstractPulleyRenderer { boolean running = pulley.running; boolean moving = running && (pulley.movedContraption == null || !pulley.movedContraption.isStalled()); float offset = pulley.getInterpolatedOffset(moving ? partialTicks : 0.5f); - + if (pulley.movedContraption != null) { - ContraptionEntity e = pulley.movedContraption; + AbstractContraptionEntity e = pulley.movedContraption; PulleyContraption c = (PulleyContraption) pulley.movedContraption.getContraption(); double entityPos = MathHelper.lerp(partialTicks, e.lastTickPosY, e.getY()); - offset = (float) -(entityPos - c.getAnchor() - .getY() - c.initialOffset); + offset = (float) -(entityPos - c.anchor.getY() - c.initialOffset); } - + return offset; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java index 7e9fd847c..44e2335e9 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/pulley/PulleyTileEntity.java @@ -3,7 +3,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.pu import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementTraits; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.piston.LinearActuatorTileEntity; import com.simibubi.create.foundation.config.AllConfigs; import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform; @@ -20,184 +20,191 @@ import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; public class PulleyTileEntity extends LinearActuatorTileEntity { - protected int initialOffset; + protected int initialOffset; - public PulleyTileEntity(TileEntityType type) { - super(type); - } + public PulleyTileEntity(TileEntityType type) { + super(type); + } - @Override - public AxisAlignedBB getRenderBoundingBox() { - return super.getRenderBoundingBox().expand(0, -offset, 0); - } + @Override + public AxisAlignedBB getRenderBoundingBox() { + return super.getRenderBoundingBox().expand(0, -offset, 0); + } - @Override - public double getMaxRenderDistanceSquared() { - return super.getMaxRenderDistanceSquared() + offset * offset; - } - - @Override - protected void assemble() { - if (!(world.getBlockState(pos) - .getBlock() instanceof PulleyBlock)) - return; - if (speed == 0) - return; - if (offset >= getExtensionRange() && getSpeed() > 0) - return; - if (offset <= 0 && getSpeed() < 0) - return; + @Override + public double getMaxRenderDistanceSquared() { + return super.getMaxRenderDistanceSquared() + offset * offset; + } - // Collect Construct - if (!world.isRemote) { - BlockPos anchor = pos.down((int) (offset + 1)); - initialOffset = (int) (offset); - PulleyContraption contraption = PulleyContraption.assemblePulleyAt(world, anchor, (int) offset); + @Override + protected void assemble() { + if (!(world.getBlockState(pos) + .getBlock() instanceof PulleyBlock)) + return; + if (speed == 0) + return; + if (offset >= getExtensionRange() && getSpeed() > 0) + return; + if (offset <= 0 && getSpeed() < 0) + return; - if (contraption != null) { - Direction movementDirection = getSpeed() > 0 ? Direction.DOWN : Direction.UP; - if (ContraptionCollider.isCollidingWithWorld(world, contraption, anchor.offset(movementDirection), - movementDirection)) - contraption = null; - } + // Collect Construct + if (!world.isRemote) { + BlockPos anchor = pos.down(MathHelper.floor(offset + 1)); + initialOffset = MathHelper.floor(offset); + PulleyContraption contraption = new PulleyContraption(initialOffset); + boolean canAssembleStructure = contraption.assemble(world, anchor); - if (contraption == null && getSpeed() > 0) - return; + if (canAssembleStructure) { + Direction movementDirection = getSpeed() > 0 ? Direction.DOWN : Direction.UP; + if (ContraptionCollider.isCollidingWithWorld(world, contraption, anchor.offset(movementDirection), + movementDirection)) + canAssembleStructure = false; + } - for (int i = ((int) offset); i > 0; i--) { - BlockPos offset = pos.down(i); - BlockState oldState = world.getBlockState(offset); - if (oldState.getBlock() instanceof IWaterLoggable && oldState.has(BlockStateProperties.WATERLOGGED) && oldState.get(BlockStateProperties.WATERLOGGED)) { - world.setBlockState(offset, Blocks.WATER.getDefaultState(), 66); - continue; - } - world.setBlockState(offset, Blocks.AIR.getDefaultState(), 66); - } + if (!canAssembleStructure && getSpeed() > 0) + return; - if (contraption != null && !contraption.blocks.isEmpty()) { - contraption.removeBlocksFromWorld(world, BlockPos.ZERO); - movedContraption = ContraptionEntity.createStationary(world, contraption) - .controlledBy(this); - movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); - world.addEntity(movedContraption); - forceMove = true; - } - } + for (int i = ((int) offset); i > 0; i--) { + BlockPos offset = pos.down(i); + BlockState oldState = world.getBlockState(offset); + if (oldState.getBlock() instanceof IWaterLoggable && oldState.has(BlockStateProperties.WATERLOGGED) + && oldState.get(BlockStateProperties.WATERLOGGED)) { + world.setBlockState(offset, Blocks.WATER.getDefaultState(), 66); + continue; + } + world.setBlockState(offset, Blocks.AIR.getDefaultState(), 66); + } - clientOffsetDiff = 0; - running = true; - sendData(); - } + if (contraption != null && !contraption.getBlocks() + .isEmpty()) { + contraption.removeBlocksFromWorld(world, BlockPos.ZERO); + movedContraption = ControlledContraptionEntity.create(world, this, contraption); + movedContraption.setPosition(anchor.getX(), anchor.getY(), anchor.getZ()); + world.addEntity(movedContraption); + forceMove = true; + } + } - @Override - public void disassemble() { - if (!running && movedContraption == null) - return; - offset = getGridOffset(offset); - if (movedContraption != null) - applyContraptionPosition(); + clientOffsetDiff = 0; + running = true; + sendData(); + } - if (!world.isRemote) { - if (!removed) { - if (offset > 0) { - BlockPos magnetPos = pos.down((int) offset); - IFluidState ifluidstate = world.getFluidState(magnetPos); - world.destroyBlock(magnetPos, world.getBlockState(magnetPos) - .getCollisionShape(world, magnetPos) - .isEmpty()); - world.setBlockState(magnetPos, AllBlocks.PULLEY_MAGNET.getDefaultState().with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)), 66); - } + @Override + public void disassemble() { + if (!running && movedContraption == null) + return; + offset = getGridOffset(offset); + if (movedContraption != null) + applyContraptionPosition(); - boolean[] waterlog = new boolean[(int) offset]; + if (!world.isRemote) { + if (!removed) { + if (offset > 0) { + BlockPos magnetPos = pos.down((int) offset); + IFluidState ifluidstate = world.getFluidState(magnetPos); + world.destroyBlock(magnetPos, world.getBlockState(magnetPos) + .getCollisionShape(world, magnetPos) + .isEmpty()); + world.setBlockState(magnetPos, AllBlocks.PULLEY_MAGNET.getDefaultState() + .with(BlockStateProperties.WATERLOGGED, + Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)), + 66); + } - for (int i = 1; i <= ((int) offset) - 1; i++) { - BlockPos ropePos = pos.down(i); - IFluidState ifluidstate = world.getFluidState(ropePos); - waterlog[i] = ifluidstate.getFluid() == Fluids.WATER; - world.destroyBlock(ropePos, world.getBlockState(ropePos) - .getCollisionShape(world, ropePos) - .isEmpty()); - } - for (int i = 1; i <= ((int) offset) - 1; i++) - world.setBlockState(pos.down(i), AllBlocks.ROPE.getDefaultState().with(BlockStateProperties.WATERLOGGED, waterlog[i]), 66); - } + boolean[] waterlog = new boolean[(int) offset]; - if (movedContraption != null) - movedContraption.disassemble(); - } + for (int i = 1; i <= ((int) offset) - 1; i++) { + BlockPos ropePos = pos.down(i); + IFluidState ifluidstate = world.getFluidState(ropePos); + waterlog[i] = ifluidstate.getFluid() == Fluids.WATER; + world.destroyBlock(ropePos, world.getBlockState(ropePos) + .getCollisionShape(world, ropePos) + .isEmpty()); + } + for (int i = 1; i <= ((int) offset) - 1; i++) + world.setBlockState(pos.down(i), AllBlocks.ROPE.getDefaultState() + .with(BlockStateProperties.WATERLOGGED, waterlog[i]), 66); + } - if (movedContraption != null) - movedContraption.remove(); - movedContraption = null; - initialOffset = 0; - running = false; - sendData(); - } + if (movedContraption != null) + movedContraption.disassemble(); + } - @Override - protected Vec3d toPosition(float offset) { - if (movedContraption.getContraption() instanceof PulleyContraption) { - PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption(); - return new Vec3d(contraption.getAnchor()).add(0, contraption.initialOffset - offset, 0); + if (movedContraption != null) + movedContraption.remove(); + movedContraption = null; + initialOffset = 0; + running = false; + sendData(); + } - } - return Vec3d.ZERO; - } + @Override + protected Vec3d toPosition(float offset) { + if (movedContraption.getContraption() instanceof PulleyContraption) { + PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption(); + return new Vec3d(contraption.anchor).add(0, contraption.initialOffset - offset, 0); - @Override - protected void visitNewPosition() { - super.visitNewPosition(); - if (world.isRemote) - return; - if (movedContraption != null) - return; - if (getSpeed() <= 0) - return; + } + return Vec3d.ZERO; + } - BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1); - if (!BlockMovementTraits.movementNecessary(world, posBelow)) - return; - if (BlockMovementTraits.isBrittle(world.getBlockState(posBelow))) - return; + @Override + protected void visitNewPosition() { + super.visitNewPosition(); + if (world.isRemote) + return; + if (movedContraption != null) + return; + if (getSpeed() <= 0) + return; - disassemble(); - assembleNextTick = true; - } + BlockPos posBelow = pos.down((int) (offset + getMovementSpeed()) + 1); + if (!BlockMovementTraits.movementNecessary(world, posBelow)) + return; + if (BlockMovementTraits.isBrittle(world.getBlockState(posBelow))) + return; - @Override - protected void read(CompoundNBT compound, boolean clientPacket) { - initialOffset = compound.getInt("InitialOffset"); - super.read(compound, clientPacket); - } + disassemble(); + assembleNextTick = true; + } - @Override - public void write(CompoundNBT compound, boolean clientPacket) { - compound.putInt("InitialOffset", initialOffset); - super.write(compound, clientPacket); - } + @Override + protected void read(CompoundNBT compound, boolean clientPacket) { + initialOffset = compound.getInt("InitialOffset"); + super.read(compound, clientPacket); + } - @Override - protected int getExtensionRange() { - return Math.max(0, Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), pos.getY() - 1)); - } + @Override + public void write(CompoundNBT compound, boolean clientPacket) { + compound.putInt("InitialOffset", initialOffset); + super.write(compound, clientPacket); + } - @Override - protected int getInitialOffset() { - return initialOffset; - } + @Override + protected int getExtensionRange() { + return Math.max(0, Math.min(AllConfigs.SERVER.kinetics.maxRopeLength.get(), pos.getY() - 1)); + } - @Override - protected Vec3d toMotionVector(float speed) { - return new Vec3d(0, -speed, 0); - } + @Override + protected int getInitialOffset() { + return initialOffset; + } - @Override - protected ValueBoxTransform getMovementModeSlot() { - return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); - } + @Override + protected Vec3d toMotionVector(float speed) { + return new Vec3d(0, -speed, 0); + } + + @Override + protected ValueBoxTransform getMovementModeSlot() { + return new CenteredSideValueBoxTransform((state, d) -> d == Direction.UP); + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java index 731c791e4..5960d43fc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionInteractionPacket.java @@ -2,7 +2,7 @@ package com.simibubi.create.content.contraptions.components.structureMovement.sy import java.util.function.Supplier; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.entity.Entity; @@ -20,7 +20,7 @@ public class ContraptionInteractionPacket extends SimplePacketBase { private BlockPos localPos; private Direction face; - public ContraptionInteractionPacket(ContraptionEntity target, Hand hand, BlockPos localPos, Direction side) { + public ContraptionInteractionPacket(AbstractContraptionEntity target, Hand hand, BlockPos localPos, Direction side) { this.interactionHand = hand; this.localPos = localPos; this.target = target.getEntityId(); @@ -53,9 +53,9 @@ public class ContraptionInteractionPacket extends SimplePacketBase { return; Entity entityByID = sender.getServerWorld() .getEntityByID(target); - if (!(entityByID instanceof ContraptionEntity)) + if (!(entityByID instanceof AbstractContraptionEntity)) return; - ContraptionEntity contraptionEntity = (ContraptionEntity) entityByID; + AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; if (contraptionEntity.handlePlayerInteraction(sender, localPos, face, interactionHand)) sender.swingHand(interactionHand, true); }); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java index 4596dbd28..6d6ce8d8f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/sync/ContraptionSeatMappingPacket.java @@ -5,7 +5,7 @@ import java.util.Map; import java.util.UUID; import java.util.function.Supplier; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.foundation.networking.SimplePacketBase; import net.minecraft.client.Minecraft; @@ -46,9 +46,9 @@ public class ContraptionSeatMappingPacket extends SimplePacketBase { context.get() .enqueueWork(() -> { Entity entityByID = Minecraft.getInstance().world.getEntityByID(entityID); - if (!(entityByID instanceof ContraptionEntity)) + if (!(entityByID instanceof AbstractContraptionEntity)) return; - ContraptionEntity contraptionEntity = (ContraptionEntity) entityByID; + AbstractContraptionEntity contraptionEntity = (AbstractContraptionEntity) entityByID; contraptionEntity.getContraption() .setSeatMapping(mapping); }); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java index 2cdbb52d6..6c2fe387a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/CouplingHandler.java @@ -8,7 +8,7 @@ import javax.annotation.Nullable; import com.simibubi.create.AllItems; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController; import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.MinecartController; import com.simibubi.create.foundation.config.AllConfigs; @@ -38,7 +38,7 @@ public class CouplingHandler { LazyOptional optional = e.getCapability(CapabilityMinecartController.MINECART_CONTROLLER_CAPABILITY); if (!optional.isPresent()) return; - if (event.getEntityMounting() instanceof ContraptionEntity) + if (event.getEntityMounting() instanceof AbstractContraptionEntity) return; MinecartController controller = optional.orElse(null); if (controller.isCoupledThroughContraption()) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java index 7d0c87a91..121d1fa61 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartController.java @@ -11,7 +11,8 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableBoolean; import com.simibubi.create.Create; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandler; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Couple; @@ -131,8 +132,8 @@ public class MinecartController implements INBTSerializable { List passengers = cart().getPassengers(); if (!passengers.isEmpty()) { Entity entity = passengers.get(0); - if (entity instanceof ContraptionEntity) - ((ContraptionEntity) entity).disassemble(); + if (entity instanceof AbstractContraptionEntity) + ((AbstractContraptionEntity) entity).disassemble(); } } @@ -172,9 +173,9 @@ public class MinecartController implements INBTSerializable { if (passengers.isEmpty()) return; Entity entity = passengers.get(0); - if (!(entity instanceof ContraptionEntity)) + if (!(entity instanceof OrientedContraptionEntity)) return; - ContraptionEntity contraption = (ContraptionEntity) entity; + OrientedContraptionEntity contraption = (OrientedContraptionEntity) entity; UUID couplingId = contraption.getCouplingId(); if (couplingId == cd.mainCartID) { contraption.setCouplingId(cd.connectedCartID); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java index 3390058fa..5b399ffcc 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/train/capability/MinecartControllerUpdatePacket.java @@ -32,7 +32,7 @@ public class MinecartControllerUpdatePacket extends SimplePacketBase { @Override public void write(PacketBuffer buffer) { - buffer.writeInt(entityID); + buffer.writeInt(entityID); buffer.writeCompoundTag(nbt); } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java index cc76a74f1..ba5788b1c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinMovementBehaviour.java @@ -51,7 +51,7 @@ public class BasinMovementBehaviour extends MovementBehaviour { } context.tileData.put(key, itemStackHandler.serializeNBT()); }); - context.contraption.customRenderTEs.stream() + context.contraption.renderedTileEntities.stream() .filter(te -> te.getPos() .equals(context.localPos) && te instanceof BasinTileEntity) .forEach(te -> ((BasinTileEntity) te).readOnlyItems(context.tileData)); diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java index 2d18780d1..5902bb44a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/belt/transport/BeltMovementHandler.java @@ -7,7 +7,7 @@ import static net.minecraft.util.Direction.AxisDirection.POSITIVE; import java.util.List; import com.simibubi.create.AllBlocks; -import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity; +import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity; import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; import com.simibubi.create.content.contraptions.relays.belt.BeltPart; import com.simibubi.create.content.contraptions.relays.belt.BeltSlope; @@ -184,7 +184,7 @@ public class BeltMovementHandler { } public static boolean shouldIgnoreBlocking(Entity me, Entity other) { - if (other instanceof ContraptionEntity) + if (other instanceof AbstractContraptionEntity) return true; if (other instanceof HangingEntity) return true; diff --git a/src/main/java/com/simibubi/create/foundation/block/ITE.java b/src/main/java/com/simibubi/create/foundation/block/ITE.java index c6290f434..c96c81191 100644 --- a/src/main/java/com/simibubi/create/foundation/block/ITE.java +++ b/src/main/java/com/simibubi/create/foundation/block/ITE.java @@ -1,5 +1,6 @@ package com.simibubi.create.foundation.block; +import java.util.Optional; import java.util.function.Consumer; import com.simibubi.create.Create; @@ -22,6 +23,13 @@ public interface ITE { action.accept(getTileEntity(world, pos)); } catch (TileEntityException e) {} } + + default Optional getTileEntityOptional(IBlockReader world, BlockPos pos) { + try { + return Optional.of(getTileEntity(world, pos)); + } catch (TileEntityException e) {} + return Optional.empty(); + } @SuppressWarnings("unchecked") default T getTileEntity(IBlockReader worldIn, BlockPos pos) throws TileEntityException { diff --git a/src/main/java/com/simibubi/create/foundation/entity/CreateDataSerializers.java b/src/main/java/com/simibubi/create/foundation/entity/CreateDataSerializers.java new file mode 100644 index 000000000..46defb307 --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/entity/CreateDataSerializers.java @@ -0,0 +1,34 @@ +package com.simibubi.create.foundation.entity; + +import java.util.Optional; + +import net.minecraft.network.PacketBuffer; +import net.minecraft.network.datasync.DataSerializers; +import net.minecraft.network.datasync.IDataSerializer; +import net.minecraft.util.Direction; + +public class CreateDataSerializers { + + public static final IDataSerializer> OPTIONAL_DIRECTION = + new IDataSerializer>() { + + public void write(PacketBuffer buffer, Optional opt) { + buffer.writeVarInt(opt.map(Direction::ordinal) + .orElse(-1) + 1); + } + + public Optional read(PacketBuffer buffer) { + int i = buffer.readVarInt(); + return i == 0 ? Optional.empty() : Optional.of(Direction.values()[i - 1]); + } + + public Optional copyValue(Optional opt) { + return Optional.ofNullable(opt.orElse(null)); + } + }; + + static { + DataSerializers.registerSerializer(OPTIONAL_DIRECTION); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java index 5e7e973ea..46555224c 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java +++ b/src/main/java/com/simibubi/create/foundation/utility/MatrixStacker.java @@ -3,6 +3,7 @@ package com.simibubi.create.foundation.utility; import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.renderer.Vector3f; +import net.minecraft.util.Direction.Axis; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3i; @@ -21,6 +22,12 @@ public class MatrixStacker { return instance; } + public MatrixStacker rotate(double angle, Axis axis) { + Vector3f vec = + axis == Axis.X ? Vector3f.POSITIVE_X : axis == Axis.Y ? Vector3f.POSITIVE_Y : Vector3f.POSITIVE_Z; + return multiply(vec, angle); + } + public MatrixStacker rotateX(double angle) { return multiply(Vector3f.POSITIVE_X, angle); }