From b4e047c5e491b152f270f543686b82b06668e063 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 1 Jun 2022 20:32:16 +0200 Subject: [PATCH] Sliding into motion - Contraptions now send block changes to other clients when doors are opened - Train doors now have special behaviour on contraptions - Train doors no longer require solid ground --- .../java/com/simibubi/create/AllBlocks.java | 2 + .../AbstractContraptionEntity.java | 41 +++++-- .../BlockMovementChecks.java | 3 + .../structureMovement/Contraption.java | 19 +++- .../ContraptionBlockChangedPacket.java | 49 ++++++++ .../ContraptionHandlerClient.java | 34 +++--- .../MovingInteractionBehaviour.java | 6 +- .../interaction/DoorMovingInteraction.java | 43 +++++-- .../deco/SlidingDoorMovementBehaviour.java | 107 ++++++++++++++++++ .../curiosities/deco/SlidingDoorRenderer.java | 2 +- .../deco/SlidingDoorTileEntity.java | 8 ++ .../curiosities/deco/TrainDoorBlock.java | 50 +++++++- .../entity/CarriageContraptionEntity.java | 17 ++- .../foundation/networking/AllPackets.java | 2 + 14 files changed, 339 insertions(+), 44 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index c222c2cfc..0e46e8e03 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -137,6 +137,7 @@ import com.simibubi.create.content.curiosities.bell.HauntedBellMovementBehaviour import com.simibubi.create.content.curiosities.bell.PeculiarBellBlock; import com.simibubi.create.content.curiosities.deco.MetalLadderBlock; import com.simibubi.create.content.curiosities.deco.PlacardBlock; +import com.simibubi.create.content.curiosities.deco.SlidingDoorMovementBehaviour; import com.simibubi.create.content.curiosities.deco.TrainDoorBlock; import com.simibubi.create.content.curiosities.deco.TrainTrapdoorBlock; import com.simibubi.create.content.curiosities.girder.ConnectedGirderModel; @@ -1567,6 +1568,7 @@ public class AllBlocks { .addLayer(() -> RenderType::cutoutMipped) .transform(pickaxeOnly()) .onRegister(addInteractionBehaviour(new DoorMovingInteraction())) + .onRegister(addMovementBehaviour(new SlidingDoorMovementBehaviour())) .tag(BlockTags.DOORS) .tag(BlockTags.WOODEN_DOORS) // for villager AI .loot((lr, block) -> lr.add(block, BlockLoot.createDoorTable(block))) 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 index 228c37a87..28d3cef60 100644 --- 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 @@ -27,7 +27,9 @@ 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.interaction.controls.ControlsStopControllingPacket; import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption; +import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionSeatMappingPacket; +import com.simibubi.create.content.curiosities.deco.TrainDoorBlock; import com.simibubi.create.content.logistics.trains.entity.CarriageContraption; import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; import com.simibubi.create.content.logistics.trains.entity.Train; @@ -62,6 +64,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.Projectile; import net.minecraft.world.entity.vehicle.AbstractMinecart; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.phys.AABB; @@ -69,6 +72,7 @@ import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.entity.IEntityAdditionalSpawnData; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.network.NetworkHooks; import net.minecraftforge.network.PacketDistributor; @@ -340,6 +344,12 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit living.setYRot(angle); } + public void setBlock(BlockPos localPos, StructureBlockInfo newInfo) { + contraption.blocks.put(localPos, newInfo); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionBlockChangedPacket(getId(), localPos, newInfo.state)); + } + protected abstract void tickContraption(); public abstract Vec3 applyRotation(Vec3 localPos, float partialTicks); @@ -653,26 +663,37 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit @OnlyIn(Dist.CLIENT) static void handleStallPacket(ContraptionStallPacket packet) { - Entity entity = Minecraft.getInstance().level.getEntity(packet.entityID); - if (!(entity instanceof AbstractContraptionEntity)) - return; - AbstractContraptionEntity ce = (AbstractContraptionEntity) entity; - ce.handleStallInformation(packet.x, packet.y, packet.z, packet.angle); + if (Minecraft.getInstance().level.getEntity(packet.entityID) instanceof AbstractContraptionEntity ce) + ce.handleStallInformation(packet.x, packet.y, packet.z, packet.angle); + } + + @OnlyIn(Dist.CLIENT) + static void handleBlockChangedPacket(ContraptionBlockChangedPacket packet) { + if (Minecraft.getInstance().level.getEntity(packet.entityID) instanceof AbstractContraptionEntity ce) + ce.handleBlockChange(packet.localPos, packet.newState); } @OnlyIn(Dist.CLIENT) static void handleDisassemblyPacket(ContraptionDisassemblyPacket packet) { - Entity entity = Minecraft.getInstance().level.getEntity(packet.entityID); - if (!(entity instanceof AbstractContraptionEntity)) - return; - AbstractContraptionEntity ce = (AbstractContraptionEntity) entity; - ce.moveCollidedEntitiesOnDisassembly(packet.transform); + if (Minecraft.getInstance().level.getEntity(packet.entityID) instanceof AbstractContraptionEntity ce) + ce.moveCollidedEntitiesOnDisassembly(packet.transform); } protected abstract float getStalledAngle(); protected abstract void handleStallInformation(float x, float y, float z, float angle); + @OnlyIn(Dist.CLIENT) + protected void handleBlockChange(BlockPos localPos, BlockState newState) { + if (contraption == null || !contraption.blocks.containsKey(localPos)) + return; + StructureBlockInfo info = contraption.blocks.get(localPos); + contraption.blocks.put(localPos, new StructureBlockInfo(info.pos, newState, info.nbt)); + if (info.state != newState && !(newState.getBlock() instanceof TrainDoorBlock)) + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> ContraptionRenderDispatcher.invalidate(contraption)); + contraption.invalidateColliders(); + } + @Override public CompoundTag saveWithoutId(CompoundTag nbt) { Vec3 vec = position(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java index feda09279..a11cd49a1 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/BlockMovementChecks.java @@ -29,6 +29,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyBlock; import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity; import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock; +import com.simibubi.create.content.curiosities.deco.TrainDoorBlock; import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultBlock; import com.simibubi.create.content.logistics.trains.IBogeyBlock; @@ -388,6 +389,8 @@ public class BlockMovementChecks { .getAxis(); if (AllBlocks.STICKER.has(state) && !state.getValue(StickerBlock.EXTENDED)) return facing == state.getValue(StickerBlock.FACING); + if (state.getBlock() instanceof TrainDoorBlock) + return false; return isBrittle(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 8669df9c5..d9d1a6833 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 @@ -56,6 +56,7 @@ import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity; import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock; import com.simibubi.create.content.contraptions.relays.belt.BeltBlock; import com.simibubi.create.content.contraptions.relays.elementary.ShaftBlock; +import com.simibubi.create.content.curiosities.deco.TrainDoorBlock; import com.simibubi.create.content.logistics.block.inventories.CreativeCrateTileEntity; import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock; import com.simibubi.create.content.logistics.block.vault.ItemVaultTileEntity; @@ -105,6 +106,7 @@ import net.minecraft.world.level.material.PushReaction; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; import net.minecraftforge.api.distmarker.Dist; @@ -590,6 +592,8 @@ public abstract class Contraption { blockstate = BlockHelper.copyProperties(blockstate, AllBlocks.SHAFT.getDefaultState()); if (AllBlocks.CONTROLS.has(blockstate)) blockstate = blockstate.setValue(ControlsBlock.OPEN, true); + if (blockstate.hasProperty(TrainDoorBlock.VISIBLE)) + blockstate = blockstate.setValue(TrainDoorBlock.VISIBLE, false); if (blockstate.getBlock() instanceof ButtonBlock) { blockstate = blockstate.setValue(ButtonBlock.POWERED, false); world.scheduleTick(pos, blockstate.getBlock(), -1); @@ -673,6 +677,8 @@ public abstract class Contraption { .forEach(c -> { CompoundTag comp = (CompoundTag) c; StructureBlockInfo info = this.blocks.get(NbtUtils.readBlockPos(comp.getCompound("Pos"))); + if (info == null) + return; MovementContext context = MovementContext.readNBT(world, info, comp, this); getActors().add(MutablePair.of(info, context)); }); @@ -695,7 +701,10 @@ public abstract class Contraption { interactors.clear(); NBTHelper.iterateCompoundList(nbt.getList("Interactors", Tag.TAG_COMPOUND), c -> { BlockPos pos = NbtUtils.readBlockPos(c.getCompound("Pos")); - MovingInteractionBehaviour behaviour = AllInteractionBehaviours.of(getBlocks().get(pos).state.getBlock()); + StructureBlockInfo structureBlockInfo = getBlocks().get(pos); + if (structureBlockInfo == null) + return; + MovingInteractionBehaviour behaviour = AllInteractionBehaviours.of(structureBlockInfo.state.getBlock()); if (behaviour != null) interactors.put(pos, behaviour); }); @@ -1013,6 +1022,9 @@ public abstract class Contraption { if (AllBlocks.SHAFT.has(state)) state = ShaftBlock.pickCorrectShaftType(state, world, targetPos); + if (state.hasProperty(TrainDoorBlock.VISIBLE)) + state = state.setValue(TrainDoorBlock.VISIBLE, !state.getValue(TrainDoorBlock.OPEN)) + .setValue(TrainDoorBlock.POWERED, false); world.setBlock(targetPos, state, Block.UPDATE_MOVE_BY_PISTON | Block.UPDATE_ALL); @@ -1024,6 +1036,7 @@ public abstract class Contraption { } BlockEntity tileEntity = world.getBlockEntity(targetPos); + CompoundTag tag = block.nbt; if (tileEntity != null) tag = NBTProcessors.process(tileEntity, tag, false); @@ -1112,6 +1125,8 @@ public abstract class Contraption { if (PoiType.forState(info.state) .isPresent()) return false; + if (info.state.getBlock() instanceof TrainDoorBlock) + return false; return true; } @@ -1199,7 +1214,7 @@ public abstract class Contraption { for (Entry entry : blocks.entrySet()) { StructureBlockInfo info = entry.getValue(); BlockPos localPos = entry.getKey(); - VoxelShape collisionShape = info.state.getCollisionShape(world, localPos); + VoxelShape collisionShape = info.state.getCollisionShape(world, localPos, CollisionContext.empty()); if (collisionShape.isEmpty()) continue; combinedShape = Shapes.joinUnoptimized(combinedShape, diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java new file mode 100644 index 000000000..b66d4a2c9 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionBlockChangedPacket.java @@ -0,0 +1,49 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.NbtUtils; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.fml.DistExecutor; +import net.minecraftforge.network.NetworkEvent.Context; + +public class ContraptionBlockChangedPacket extends SimplePacketBase { + + int entityID; + BlockPos localPos; + BlockState newState; + + public ContraptionBlockChangedPacket(int id, BlockPos pos, BlockState state) { + entityID = id; + localPos = pos; + newState = state; + } + + @Override + public void write(FriendlyByteBuf buffer) { + buffer.writeInt(entityID); + buffer.writeBlockPos(localPos); + buffer.writeNbt(NbtUtils.writeBlockState(newState)); + } + + public ContraptionBlockChangedPacket(FriendlyByteBuf buffer) { + entityID = buffer.readInt(); + localPos = buffer.readBlockPos(); + newState = NbtUtils.readBlockState(buffer.readNbt()); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT, + () -> () -> AbstractContraptionEntity.handleBlockChangedPacket(this))); + context.get() + .setPacketHandled(true); + } + +} 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 0243d9566..beca5f07c 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 @@ -12,6 +12,7 @@ import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEn import com.simibubi.create.content.logistics.trains.entity.TrainRelocator; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Couple; +import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; import com.simibubi.create.foundation.utility.VecHelper; @@ -135,20 +136,25 @@ public class ContraptionHandlerClient { MutableObject mutableResult = new MutableObject<>(); PredicateTraceResult predicateResult = RaycastHelper.rayTraceUntil(localOrigin, localTarget, p -> { - StructureBlockInfo blockInfo = contraption.getBlocks() - .get(p); - if (blockInfo == null) - return false; - BlockState state = blockInfo.state; - VoxelShape raytraceShape = state.getShape(Minecraft.getInstance().level, BlockPos.ZERO.below()); - if (raytraceShape.isEmpty()) - return false; - if (contraption.isHiddenInPortal(p)) - return false; - BlockHitResult rayTrace = raytraceShape.clip(localOrigin, localTarget, p); - if (rayTrace != null) { - mutableResult.setValue(rayTrace); - return true; + for (Direction d : Iterate.directions) { + if (d == Direction.UP) + continue; + BlockPos pos = d == Direction.DOWN ? p : p.relative(d); + StructureBlockInfo blockInfo = contraption.getBlocks() + .get(pos); + if (blockInfo == null) + continue; + BlockState state = blockInfo.state; + VoxelShape raytraceShape = state.getShape(contraption.getContraptionWorld(), BlockPos.ZERO.below()); + if (raytraceShape.isEmpty()) + continue; + if (contraption.isHiddenInPortal(pos)) + continue; + BlockHitResult rayTrace = raytraceShape.clip(localOrigin, localTarget, pos); + if (rayTrace != null) { + mutableResult.setValue(rayTrace); + return true; + } } return false; }); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java index 557b2ad8a..9f2796e04 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/MovingInteractionBehaviour.java @@ -27,9 +27,9 @@ public abstract class MovingInteractionBehaviour { protected void setContraptionBlockData(AbstractContraptionEntity contraptionEntity, BlockPos pos, StructureBlockInfo info) { - contraptionEntity.contraption.blocks.put(pos, info); - if (contraptionEntity.level.isClientSide) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> invalidate(contraptionEntity.contraption)); + if (contraptionEntity.level.isClientSide()) + return; + contraptionEntity.setBlock(pos, info); } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java index 0cafcc223..e0aa63e0a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/DoorMovingInteraction.java @@ -1,13 +1,17 @@ package com.simibubi.create.content.contraptions.components.structureMovement.interaction; import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.curiosities.deco.TrainDoorBlock; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.DoorBlock; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoorHingeSide; import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; @@ -15,19 +19,42 @@ public class DoorMovingInteraction extends SimpleBlockMovingInteraction { @Override protected BlockState handle(Player player, Contraption contraption, BlockPos pos, BlockState currentState) { - SoundEvent sound = - currentState.getValue(DoorBlock.OPEN) ? SoundEvents.WOODEN_DOOR_CLOSE : SoundEvents.WOODEN_DOOR_OPEN; + if (!(currentState.getBlock() instanceof DoorBlock)) + return currentState; + + boolean trainDoor = currentState.getBlock() instanceof TrainDoorBlock; + SoundEvent sound = currentState.getValue(DoorBlock.OPEN) ? trainDoor ? null : SoundEvents.WOODEN_DOOR_CLOSE + : trainDoor ? SoundEvents.IRON_DOOR_OPEN : SoundEvents.WOODEN_DOOR_OPEN; BlockPos otherPos = currentState.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? pos.above() : pos.below(); StructureBlockInfo info = contraption.getBlocks() .get(otherPos); - if (info.state.hasProperty(DoorBlock.OPEN)) - setContraptionBlockData(contraption.entity, otherPos, - new StructureBlockInfo(info.pos, info.state.cycle(DoorBlock.OPEN), info.nbt)); + if (info.state.hasProperty(DoorBlock.OPEN)) { + BlockState newState = info.state.cycle(DoorBlock.OPEN); + setContraptionBlockData(contraption.entity, otherPos, new StructureBlockInfo(info.pos, newState, info.nbt)); + } - float pitch = player.level.random.nextFloat() * 0.1F + 0.9F; - playSound(player, sound, pitch); - return currentState.cycle(DoorBlock.OPEN); + currentState = currentState.cycle(DoorBlock.OPEN); + + if (player != null) { + + if (trainDoor) { + DoorHingeSide hinge = currentState.getValue(TrainDoorBlock.HINGE); + Direction facing = currentState.getValue(TrainDoorBlock.FACING); + BlockPos doublePos = + pos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise()); + StructureBlockInfo doubleInfo = contraption.getBlocks() + .get(doublePos); + if (doubleInfo != null && TrainDoorBlock.isDoubleDoor(currentState, hinge, facing, doubleInfo.state)) + handlePlayerInteraction(null, InteractionHand.MAIN_HAND, doublePos, contraption.entity); + } + + float pitch = player.level.random.nextFloat() * 0.1F + 0.9F; + if (sound != null) + playSound(player, sound, pitch); + } + + return currentState; } @Override diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java new file mode 100644 index 000000000..354539f56 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorMovementBehaviour.java @@ -0,0 +1,107 @@ +package com.simibubi.create.content.curiosities.deco; + +import java.util.Map; + +import com.simibubi.create.content.contraptions.components.structureMovement.Contraption; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; +import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity; +import com.simibubi.create.content.logistics.trains.entity.CarriageSyncData; +import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser; + +import net.minecraft.core.BlockPos; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.level.block.DoorBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.DoubleBlockHalf; +import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo; + +public class SlidingDoorMovementBehaviour implements MovementBehaviour { + + @Override + public boolean renderAsNormalTileEntity() { + return true; + } + + @Override + public void tick(MovementContext context) { + StructureBlockInfo structureBlockInfo = context.contraption.getBlocks() + .get(context.localPos); + if (structureBlockInfo == null) + return; + boolean open = SlidingDoorTileEntity.isOpen(structureBlockInfo.state); + + if (!context.world.isClientSide()) + tickOpen(context, open); + + Map tes = context.contraption.presentTileEntities; + if (!(tes.get(context.localPos) instanceof SlidingDoorTileEntity doorTE)) + return; + boolean wasSettled = doorTE.animation.settled(); + doorTE.animation.chase(open ? 1 : 0, .15f, Chaser.LINEAR); + doorTE.animation.tickChaser(); + + if (!wasSettled && doorTE.animation.settled() && !open) + context.world.playLocalSound(context.position.x, context.position.y, context.position.z, + SoundEvents.IRON_DOOR_CLOSE, SoundSource.BLOCKS, .5f, 1, false); + } + + protected void tickOpen(MovementContext context, boolean currentlyOpen) { + boolean shouldOpen = shouldOpen(context); + if (!shouldUpdate(context, shouldOpen)) + return; + if (currentlyOpen == shouldOpen) + return; + + BlockPos pos = context.localPos; + Contraption contraption = context.contraption; + + StructureBlockInfo info = contraption.getBlocks() + .get(pos); + if (info == null || !info.state.hasProperty(DoorBlock.OPEN)) + return; + + toggleDoor(pos, contraption, info); + + if (shouldOpen) + context.world.playSound(null, new BlockPos(context.position), SoundEvents.IRON_DOOR_OPEN, + SoundSource.BLOCKS, .5f, 1); + } + + private void toggleDoor(BlockPos pos, Contraption contraption, StructureBlockInfo info) { + BlockState newState = info.state.cycle(DoorBlock.OPEN); + contraption.entity.setBlock(pos, new StructureBlockInfo(info.pos, newState, info.nbt)); + + BlockPos otherPos = newState.getValue(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? pos.above() : pos.below(); + info = contraption.getBlocks() + .get(otherPos); + if (info != null && info.state.hasProperty(DoorBlock.OPEN)) { + newState = info.state.cycle(DoorBlock.OPEN); + contraption.entity.setBlock(otherPos, new StructureBlockInfo(info.pos, newState, info.nbt)); + } + } + + protected boolean shouldUpdate(MovementContext context, boolean shouldOpen) { + if (context.firstMovement && shouldOpen) + return false; + if (!context.data.contains("Open")) { + context.data.putBoolean("Open", shouldOpen); + return true; + } + boolean wasOpen = context.data.getBoolean("Open"); + context.data.putBoolean("Open", shouldOpen); + return wasOpen != shouldOpen; + } + + protected boolean shouldOpen(MovementContext context) { + if (context.contraption.entity instanceof CarriageContraptionEntity cce) { + CarriageSyncData carriageData = cce.getCarriageData(); + if (Math.abs(carriageData.distanceToDestination) > 1) + return false; + } + return context.motion.length() < 1 / 128f && !context.contraption.entity.isStalled(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java index d2c16c03a..0b9ca3d86 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/deco/SlidingDoorRenderer.java @@ -45,7 +45,7 @@ public class SlidingDoorRenderer extends SafeTileEntityRenderer type, BlockPos pos, BlockState state) { super(type, pos, state); @@ -27,6 +29,12 @@ public class SlidingDoorTileEntity extends SmartTileEntity { @Override public void tick() { + if (deferUpdate && !level.isClientSide()) { + deferUpdate = false; + BlockState blockState = getBlockState(); + blockState.neighborChanged(level, worldPosition, Blocks.AIR, worldPosition, false); + } + super.tick(); boolean open = isOpen(getBlockState()); boolean wasSettled = animation.settled(); diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainDoorBlock.java b/src/main/java/com/simibubi/create/content/curiosities/deco/TrainDoorBlock.java index 4332f662d..636161492 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainDoorBlock.java +++ b/src/main/java/com/simibubi/create/content/curiosities/deco/TrainDoorBlock.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.curiosities.deco; import javax.annotation.Nullable; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionWorld; import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; @@ -16,6 +17,7 @@ import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.DoorBlock; @@ -59,7 +61,7 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE sdte.deferUpdate = true); + } + + public static boolean isDoubleDoor(BlockState pState, DoorHingeSide hinge, Direction facing, BlockState otherDoor) { return otherDoor.getBlock() == pState.getBlock() && otherDoor.getValue(HINGE) != hinge && otherDoor.getValue(FACING) == facing && otherDoor.getValue(OPEN) != pState.getValue(OPEN) && otherDoor.getValue(HALF) == pState.getValue(HALF); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java index d55c4ae3e..f6daa65a7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java @@ -16,6 +16,7 @@ import com.simibubi.create.AllEntityDataSerializers; import com.simibubi.create.AllEntityTypes; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionBlockChangedPacket; 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; @@ -26,6 +27,7 @@ import com.simibubi.create.content.logistics.trains.entity.Carriage.DimensionalC import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; import com.simibubi.create.foundation.config.AllConfigs; +import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Color; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Lang; @@ -52,6 +54,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.network.PacketDistributor; public class CarriageContraptionEntity extends OrientedContraptionEntity { @@ -127,7 +130,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { } } - private CarriageSyncData getCarriageData() { + public CarriageSyncData getCarriageData() { return entityData.get(CARRIAGE_DATA); } @@ -184,6 +187,18 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity { } } + @Override + public void setBlock(BlockPos localPos, StructureBlockInfo newInfo) { + if (carriage == null) + return; + carriage.forEachPresentEntity(cce -> { + cce.contraption.getBlocks() + .put(localPos, newInfo); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> cce), + new ContraptionBlockChangedPacket(cce.getId(), localPos, newInfo.state)); + }); + } + @Override protected void tickContraption() { if (nonDamageTicks > 0) diff --git a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java index d8af33e12..b85e84673 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -8,6 +8,7 @@ import java.util.function.Function; import java.util.function.Supplier; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionBlockChangedPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionDisassemblyPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket; import com.simibubi.create.content.contraptions.components.structureMovement.TrainCollisionPacket; @@ -142,6 +143,7 @@ public enum AllPackets { S_CONFIGURE_CONFIG(SConfigureConfigPacket.class, SConfigureConfigPacket::new, PLAY_TO_CLIENT), CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new, PLAY_TO_CLIENT), CONTRAPTION_DISASSEMBLE(ContraptionDisassemblyPacket.class, ContraptionDisassemblyPacket::new, PLAY_TO_CLIENT), + CONTRAPTION_BLOCK_CHANGED(ContraptionBlockChangedPacket.class, ContraptionBlockChangedPacket::new, PLAY_TO_CLIENT), GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new, PLAY_TO_CLIENT), CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new, PLAY_TO_CLIENT), LIMBSWING_UPDATE(LimbSwingUpdatePacket.class, LimbSwingUpdatePacket::new, PLAY_TO_CLIENT),