mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-11-18 16:02:19 +01:00
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
This commit is contained in:
parent
8ab66b8da6
commit
b4e047c5e4
14 changed files with 339 additions and 44 deletions
|
@ -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)))
|
||||
|
|
|
@ -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,19 +663,19 @@ 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;
|
||||
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;
|
||||
if (Minecraft.getInstance().level.getEntity(packet.entityID) instanceof AbstractContraptionEntity ce)
|
||||
ce.moveCollidedEntitiesOnDisassembly(packet.transform);
|
||||
}
|
||||
|
||||
|
@ -673,6 +683,17 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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<BlockPos, StructureBlockInfo> 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,
|
||||
|
|
|
@ -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) {
|
||||
context.get()
|
||||
.enqueueWork(() -> DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
|
||||
() -> () -> AbstractContraptionEntity.handleBlockChangedPacket(this)));
|
||||
context.get()
|
||||
.setPacketHandled(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -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,21 +136,26 @@ public class ContraptionHandlerClient {
|
|||
|
||||
MutableObject<BlockHitResult> mutableResult = new MutableObject<>();
|
||||
PredicateTraceResult predicateResult = RaycastHelper.rayTraceUntil(localOrigin, localTarget, p -> {
|
||||
for (Direction d : Iterate.directions) {
|
||||
if (d == Direction.UP)
|
||||
continue;
|
||||
BlockPos pos = d == Direction.DOWN ? p : p.relative(d);
|
||||
StructureBlockInfo blockInfo = contraption.getBlocks()
|
||||
.get(p);
|
||||
.get(pos);
|
||||
if (blockInfo == null)
|
||||
return false;
|
||||
continue;
|
||||
BlockState state = blockInfo.state;
|
||||
VoxelShape raytraceShape = state.getShape(Minecraft.getInstance().level, BlockPos.ZERO.below());
|
||||
VoxelShape raytraceShape = state.getShape(contraption.getContraptionWorld(), BlockPos.ZERO.below());
|
||||
if (raytraceShape.isEmpty())
|
||||
return false;
|
||||
if (contraption.isHiddenInPortal(p))
|
||||
return false;
|
||||
BlockHitResult rayTrace = raytraceShape.clip(localOrigin, localTarget, p);
|
||||
continue;
|
||||
if (contraption.isHiddenInPortal(pos))
|
||||
continue;
|
||||
BlockHitResult rayTrace = raytraceShape.clip(localOrigin, localTarget, pos);
|
||||
if (rayTrace != null) {
|
||||
mutableResult.setValue(rayTrace);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
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.cycle(DoorBlock.OPEN);
|
||||
}
|
||||
|
||||
return currentState;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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<BlockPos, BlockEntity> 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();
|
||||
}
|
||||
|
||||
}
|
|
@ -45,7 +45,7 @@ public class SlidingDoorRenderer extends SafeTileEntityRenderer<SlidingDoorTileE
|
|||
for (DoubleBlockHalf half : DoubleBlockHalf.values()) {
|
||||
CachedBufferer.block(blockState.setValue(DoorBlock.OPEN, false)
|
||||
.setValue(DoorBlock.HALF, half))
|
||||
.translate(0, half == DoubleBlockHalf.UPPER ? 1 : 0, 0)
|
||||
.translate(0, half == DoubleBlockHalf.UPPER ? 1 - 1 / 512f : 0, 0)
|
||||
.translate(offset)
|
||||
.light(light)
|
||||
.renderInto(ms, vb);
|
||||
|
|
|
@ -10,6 +10,7 @@ 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.Blocks;
|
||||
import net.minecraft.world.level.block.DoorBlock;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -18,6 +19,7 @@ public class SlidingDoorTileEntity extends SmartTileEntity {
|
|||
|
||||
LerpedFloat animation;
|
||||
int bridgeTicks;
|
||||
boolean deferUpdate;
|
||||
|
||||
public SlidingDoorTileEntity(BlockEntityType<?> 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();
|
||||
|
|
|
@ -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<Slidin
|
|||
|
||||
@Override
|
||||
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
|
||||
if (!pState.getValue(OPEN) && pState.getValue(VISIBLE))
|
||||
if (!pState.getValue(OPEN) && (pState.getValue(VISIBLE) || pLevel instanceof ContraptionWorld))
|
||||
return super.getShape(pState, pLevel, pPos, pContext);
|
||||
|
||||
Direction direction = pState.getValue(FACING);
|
||||
|
@ -73,6 +75,12 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSurvive(BlockState pState, LevelReader pLevel, BlockPos pPos) {
|
||||
return pState.getValue(HALF) == DoubleBlockHalf.LOWER || pLevel.getBlockState(pPos.below())
|
||||
.is(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VoxelShape getInteractionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos) {
|
||||
return getShape(pState, pLevel, pPos, CollisionContext.empty());
|
||||
|
@ -82,10 +90,17 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
|
||||
BlockState stateForPlacement = super.getStateForPlacement(pContext);
|
||||
if (stateForPlacement != null && stateForPlacement.getValue(OPEN))
|
||||
return stateForPlacement.setValue(VISIBLE, false);
|
||||
return stateForPlacement.setValue(OPEN, false)
|
||||
.setValue(POWERED, false);
|
||||
return stateForPlacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
|
||||
if (!pOldState.is(this))
|
||||
deferUpdate(pLevel, pPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState updateShape(BlockState pState, Direction pFacing, BlockState pFacingState, LevelAccessor pLevel,
|
||||
BlockPos pCurrentPos, BlockPos pFacingPos) {
|
||||
|
@ -128,13 +143,17 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
@Override
|
||||
public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos,
|
||||
boolean pIsMoving) {
|
||||
boolean isPowered = pLevel.hasNeighborSignal(pPos) || pLevel.hasNeighborSignal(
|
||||
pPos.relative(pState.getValue(HALF) == DoubleBlockHalf.LOWER ? Direction.UP : Direction.DOWN));
|
||||
boolean lower = pState.getValue(HALF) == DoubleBlockHalf.LOWER;
|
||||
boolean isPowered = isDoorPowered(pLevel, pPos, pState);
|
||||
if (defaultBlockState().is(pBlock))
|
||||
return;
|
||||
if (isPowered == pState.getValue(POWERED))
|
||||
return;
|
||||
|
||||
SlidingDoorTileEntity te = getTileEntity(pLevel, lower ? pPos : pPos.below());
|
||||
if (te != null && te.deferUpdate)
|
||||
return;
|
||||
|
||||
BlockState changedState = pState.setValue(POWERED, Boolean.valueOf(isPowered))
|
||||
.setValue(OPEN, Boolean.valueOf(isPowered));
|
||||
if (isPowered)
|
||||
|
@ -149,6 +168,7 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
BlockPos otherPos =
|
||||
pPos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
|
||||
BlockState otherDoor = pLevel.getBlockState(otherPos);
|
||||
|
||||
if (isDoubleDoor(changedState, hinge, facing, otherDoor)) {
|
||||
otherDoor = otherDoor.setValue(POWERED, Boolean.valueOf(isPowered))
|
||||
.setValue(OPEN, Boolean.valueOf(isPowered));
|
||||
|
@ -161,6 +181,22 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
pLevel.setBlock(pPos, changedState, 2);
|
||||
}
|
||||
|
||||
public static boolean isDoorPowered(Level pLevel, BlockPos pPos, BlockState state) {
|
||||
boolean lower = state.getValue(HALF) == DoubleBlockHalf.LOWER;
|
||||
DoorHingeSide hinge = state.getValue(HINGE);
|
||||
Direction facing = state.getValue(FACING);
|
||||
BlockPos otherPos =
|
||||
pPos.relative(hinge == DoorHingeSide.LEFT ? facing.getClockWise() : facing.getCounterClockWise());
|
||||
BlockState otherDoor = pLevel.getBlockState(otherPos);
|
||||
|
||||
if (isDoubleDoor(state.cycle(OPEN), hinge, facing, otherDoor) && (pLevel.hasNeighborSignal(otherPos)
|
||||
|| pLevel.hasNeighborSignal(otherPos.relative(lower ? Direction.UP : Direction.DOWN))))
|
||||
return true;
|
||||
|
||||
return pLevel.hasNeighborSignal(pPos)
|
||||
|| pLevel.hasNeighborSignal(pPos.relative(lower ? Direction.UP : Direction.DOWN));
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
|
||||
BlockHitResult pHit) {
|
||||
|
@ -184,7 +220,11 @@ public class TrainDoorBlock extends DoorBlock implements IWrenchable, ITE<Slidin
|
|||
return InteractionResult.sidedSuccess(pLevel.isClientSide);
|
||||
}
|
||||
|
||||
private boolean isDoubleDoor(BlockState pState, DoorHingeSide hinge, Direction facing, BlockState otherDoor) {
|
||||
public void deferUpdate(LevelAccessor level, BlockPos pos) {
|
||||
withTileEntityDo(level, pos, sdte -> 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);
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
|
Loading…
Reference in a new issue