From 7994835cb012a1568ad761be2c93dc9c423c8b75 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 22 Jul 2020 01:18:09 +0200 Subject: [PATCH] Seats, part II - Any living entity can now use seats - Fix client sync issues with seats - Fixed contraptions double-reversing roll and pitch values when communicating to the collision engine - Seats now transfer their passengers to a contraption when moved and back when disassembled - Attempted further refinements to the collision response of horizontally rotated contraptions - Set up a hook to inject custom interaction between players and contraption mounted blocks on right-click - Seats can now by mounted by players while assembled to a contraption - Minor refactors to the contraption class --- .../java/ContraptionInteractionHandler.java | 89 ++ .../com/simibubi/create/AllEntityTypes.java | 2 +- .../components/actors/SeatBlock.java | 75 +- .../components/actors/SeatEntity.java | 53 +- .../actors/SeatMovementBehaviour.java | 9 + .../structureMovement/Contraption.java | 1233 +++++++++-------- .../ContraptionCollider.java | 100 +- .../structureMovement/ContraptionEntity.java | 170 ++- .../ContraptionInteractionPacket.java | 65 + .../ContraptionSeatMappingPacket.java | 58 + .../bearing/ClockworkBearingTileEntity.java | 4 - .../bearing/MechanicalBearingTileEntity.java | 2 - .../mounted/MountedContraption.java | 11 +- .../piston/LinearActuatorTileEntity.java | 1 - .../piston/PistonContraption.java | 54 +- .../collision/CollisionDebugger.java | 2 - .../foundation/networking/AllPackets.java | 4 + .../create/foundation/utility/VecHelper.java | 4 + .../create/textures/block/seat/bottom.png | Bin 304 -> 306 bytes .../create/textures/block/seat/side_black.png | Bin 387 -> 379 bytes .../create/textures/block/seat/side_blue.png | Bin 389 -> 392 bytes .../create/textures/block/seat/side_brown.png | Bin 385 -> 389 bytes .../create/textures/block/seat/side_cyan.png | Bin 389 -> 401 bytes .../create/textures/block/seat/side_gray.png | Bin 385 -> 375 bytes .../create/textures/block/seat/side_green.png | Bin 387 -> 390 bytes .../textures/block/seat/side_light_blue.png | Bin 391 -> 398 bytes .../textures/block/seat/side_light_gray.png | Bin 407 -> 412 bytes .../create/textures/block/seat/side_lime.png | Bin 390 -> 403 bytes .../textures/block/seat/side_magenta.png | Bin 386 -> 398 bytes .../textures/block/seat/side_orange.png | Bin 387 -> 404 bytes .../create/textures/block/seat/side_pink.png | Bin 404 -> 408 bytes .../textures/block/seat/side_purple.png | Bin 407 -> 413 bytes .../create/textures/block/seat/side_red.png | Bin 387 -> 399 bytes .../create/textures/block/seat/side_white.png | Bin 400 -> 416 bytes .../textures/block/seat/side_yellow.png | Bin 387 -> 404 bytes 35 files changed, 1231 insertions(+), 705 deletions(-) create mode 100644 src/main/java/ContraptionInteractionHandler.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionPacket.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionSeatMappingPacket.java diff --git a/src/main/java/ContraptionInteractionHandler.java b/src/main/java/ContraptionInteractionHandler.java new file mode 100644 index 000000000..8ae1d08c5 --- /dev/null +++ b/src/main/java/ContraptionInteractionHandler.java @@ -0,0 +1,89 @@ +import org.apache.commons.lang3.mutable.MutableObject; + +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.ContraptionInteractionPacket; +import com.simibubi.create.foundation.networking.AllPackets; +import com.simibubi.create.foundation.utility.RaycastHelper; +import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; + +import net.minecraft.block.BlockState; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +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.BlockRayTraceResult; +import net.minecraft.util.math.Vec3d; +import net.minecraft.util.math.shapes.VoxelShape; +import net.minecraft.world.gen.feature.template.Template.BlockInfo; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.client.event.InputEvent.ClickInputEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod.EventBusSubscriber; + +@EventBusSubscriber +public class ContraptionInteractionHandler { + + @SubscribeEvent + @OnlyIn(Dist.CLIENT) + public static void rightClickingOnContraptionsGetsHandledLocally(ClickInputEvent event) { + Minecraft mc = Minecraft.getInstance(); + ClientPlayerEntity player = mc.player; + if (player == null) + return; + if (mc.world == null) + return; + if (!event.isUseItem()) + return; + Vec3d origin = RaycastHelper.getTraceOrigin(player); + + double reach = mc.playerController.getBlockReachDistance(); + if (mc.objectMouseOver != null && mc.objectMouseOver.getHitVec() != null) + reach = Math.min(mc.objectMouseOver.getHitVec().distanceTo(origin), reach); + + Vec3d target = RaycastHelper.getTraceTarget(player, reach, origin); + for (ContraptionEntity contraptionEntity : mc.world.getEntitiesWithinAABB(ContraptionEntity.class, + new AxisAlignedBB(origin, target))) { + + Vec3d localOrigin = contraptionEntity.toLocalVector(origin); + Vec3d localTarget = contraptionEntity.toLocalVector(target); + Contraption contraption = contraptionEntity.getContraption(); + + MutableObject mutableResult = new MutableObject<>(); + PredicateTraceResult predicateResult = RaycastHelper.rayTraceUntil(localOrigin, localTarget, p -> { + BlockInfo blockInfo = contraption.blocks.get(p); + if (blockInfo == null) + return false; + BlockState state = blockInfo.state; + VoxelShape raytraceShape = state.getShape(Minecraft.getInstance().world, BlockPos.ZERO.down()); + if (raytraceShape.isEmpty()) + return false; + BlockRayTraceResult rayTrace = raytraceShape.rayTrace(localOrigin, localTarget, p); + if (rayTrace != null) { + mutableResult.setValue(rayTrace); + return true; + } + return false; + }); + + if (predicateResult == null || predicateResult.missed()) + return; + + BlockRayTraceResult rayTraceResult = mutableResult.getValue(); + Hand hand = event.getHand(); + Direction face = rayTraceResult.getFace(); + BlockPos pos = rayTraceResult.getPos(); + + if (!contraptionEntity.handlePlayerInteraction(player, pos, face, hand)) + return; + AllPackets.channel.sendToServer(new ContraptionInteractionPacket(contraptionEntity, hand, + pos, face)); + event.setCanceled(true); + event.setSwingHand(false); + } + } + +} diff --git a/src/main/java/com/simibubi/create/AllEntityTypes.java b/src/main/java/com/simibubi/create/AllEntityTypes.java index 0e2e5b593..13d75af47 100644 --- a/src/main/java/com/simibubi/create/AllEntityTypes.java +++ b/src/main/java/com/simibubi/create/AllEntityTypes.java @@ -26,7 +26,7 @@ public class AllEntityTypes { 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, 5, Integer.MAX_VALUE, false, SeatEntity::build); private static RegistryEntry> register(String name, IFactory factory, EntityClassification group, int range, int updateFrequency, boolean sendVelocity, 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 93c502916..b5df0a8c2 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 @@ -1,17 +1,25 @@ package com.simibubi.create.content.contraptions.components.actors; +import java.util.List; + import com.simibubi.create.AllShapes; +import com.simibubi.create.content.contraptions.components.structureMovement.IPortableBlock; +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.MobEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; +import net.minecraft.pathfinding.PathNodeType; import net.minecraft.util.ActionResultType; import net.minecraft.util.Hand; import net.minecraft.util.NonNullList; +import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.shapes.ISelectionContext; @@ -19,15 +27,16 @@ import net.minecraft.util.math.shapes.VoxelShape; import net.minecraft.world.IBlockReader; import net.minecraft.world.World; -public class SeatBlock extends Block { +public class SeatBlock extends Block implements IPortableBlock { + public static MovementBehaviour MOVEMENT = new SeatMovementBehaviour(); private boolean inCreativeTab; public SeatBlock(Properties p_i48440_1_, boolean inCreativeTab) { super(p_i48440_1_); this.inCreativeTab = inCreativeTab; } - + @Override public void fillItemGroup(ItemGroup group, NonNullList p_149666_2_) { if (group != ItemGroup.SEARCH && !inCreativeTab) @@ -41,8 +50,21 @@ public class SeatBlock extends Block { } @Override - public void onLanded(IBlockReader p_176216_1_, Entity p_176216_2_) { - Blocks.PINK_BED.onLanded(p_176216_1_, p_176216_2_); + public void onLanded(IBlockReader reader, Entity entity) { + BlockPos pos = entity.getPosition(); + if (entity instanceof PlayerEntity || !(entity instanceof LivingEntity) || isSeatOccupied(entity.world, pos)) { + Blocks.PINK_BED.onLanded(reader, entity); + return; + } + if (reader.getBlockState(pos) + .getBlock() != this) + return; + sitDown(entity.world, pos, entity); + } + + @Override + public PathNodeType getAiPathNodeType(BlockState state, IBlockReader world, BlockPos pos, MobEntity entity) { + return PathNodeType.RAIL; } @Override @@ -52,17 +74,46 @@ public class SeatBlock extends Block { } @Override - public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player, Hand p_225533_5_, BlockRayTraceResult p_225533_6_) { - if (SeatEntity.TAKEN.containsKey(pos)) - return ActionResultType.FAIL; + public ActionResultType onUse(BlockState p_225533_1_, World world, BlockPos pos, PlayerEntity player, + Hand p_225533_5_, BlockRayTraceResult p_225533_6_) { + if (player.isSneaking()) + return ActionResultType.PASS; + + List seats = world.getEntitiesWithinAABB(SeatEntity.class, new AxisAlignedBB(pos)); + if (!seats.isEmpty()) { + SeatEntity seatEntity = seats.get(0); + List passengers = seatEntity.getPassengers(); + if (!passengers.isEmpty() && passengers.get(0) instanceof PlayerEntity) + return ActionResultType.PASS; + if (!world.isRemote) { + seatEntity.removePassengers(); + player.startRiding(seatEntity); + } + return ActionResultType.SUCCESS; + } if (world.isRemote) return ActionResultType.SUCCESS; - - SeatEntity seat = new SeatEntity(world, pos); - world.addEntity(seat); - player.startRiding(seat); - + sitDown(world, pos, player); return ActionResultType.SUCCESS; } + + public static boolean isSeatOccupied(World world, BlockPos pos) { + return !world.getEntitiesWithinAABB(SeatEntity.class, new AxisAlignedBB(pos)) + .isEmpty(); + } + + public static void sitDown(World world, BlockPos pos, Entity entity) { + if (world.isRemote) + return; + SeatEntity seat = new SeatEntity(world, pos); + seat.setPos(pos.getX() + .5f, pos.getY(), pos.getZ() + .5f); + world.addEntity(seat); + entity.startRiding(seat, true); + } + + @Override + public MovementBehaviour getMovementBehaviour() { + return MOVEMENT; + } } diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java index 9e5cab53a..18e8cd48f 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatEntity.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.components.actors; import com.simibubi.create.AllEntityTypes; + import net.minecraft.client.renderer.culling.ClippingHelperImpl; import net.minecraft.client.renderer.entity.EntityRenderer; import net.minecraft.client.renderer.entity.EntityRendererManager; @@ -8,18 +9,16 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.IPacket; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; +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.minecraftforge.fml.common.registry.IEntityAdditionalSpawnData; import net.minecraftforge.fml.network.NetworkHooks; -import java.util.HashMap; -import java.util.Map; - -public class SeatEntity extends Entity { - - public static final Map TAKEN = new HashMap<>(); +public class SeatEntity extends Entity implements IEntityAdditionalSpawnData { public SeatEntity(EntityType p_i48580_1_, World p_i48580_2_) { super(p_i48580_1_, p_i48580_2_); @@ -27,28 +26,39 @@ public class SeatEntity extends Entity { public SeatEntity(World world, BlockPos pos) { this(AllEntityTypes.SEAT.get(), world); - this.setPos(pos.getX() + 0.5, pos.getY() + 0.30, pos.getZ() + 0.5); noClip = true; - TAKEN.put(pos, this); - } public static EntityType.Builder build(EntityType.Builder builder) { @SuppressWarnings("unchecked") EntityType.Builder entityBuilder = (EntityType.Builder) builder; - return entityBuilder.size(0, 0); + return entityBuilder.size(0.25f, 0.35f); } + @Override + public AxisAlignedBB getBoundingBox() { + return super.getBoundingBox(); + } + + @Override + public void setPos(double x, double y, double z) { + super.setPos(x, y, z); + AxisAlignedBB bb = getBoundingBox(); + Vec3d diff = new Vec3d(x, y, z).subtract(bb.getCenter()); + setBoundingBox(bb.offset(diff)); + } + + @Override + public void setMotion(Vec3d p_213317_1_) {} + @Override public void tick() { - if (world.isRemote) + if (world.isRemote) return; - - BlockPos blockPos = new BlockPos(getX(), getY(), getZ()); - if (isBeingRidden() && world.getBlockState(blockPos).getBlock() instanceof SeatBlock) + boolean blockPresent = world.getBlockState(getPosition()) + .getBlock() instanceof SeatBlock; + if (isBeingRidden() && blockPresent) return; - - TAKEN.remove(blockPos); this.remove(); } @@ -61,7 +71,7 @@ public class SeatEntity extends Entity { protected void removePassenger(Entity entity) { super.removePassenger(entity); Vec3d pos = entity.getPositionVec(); - entity.setPosition(pos.x, pos.y + 0.7, pos.z); + entity.setPosition(pos.x, pos.y + 0.85f, pos.z); } @Override @@ -85,7 +95,8 @@ public class SeatEntity extends Entity { } @Override - public boolean shouldRender(SeatEntity p_225626_1_, ClippingHelperImpl p_225626_2_, double p_225626_3_, double p_225626_5_, double p_225626_7_) { + public boolean shouldRender(SeatEntity p_225626_1_, ClippingHelperImpl p_225626_2_, double p_225626_3_, + double p_225626_5_, double p_225626_7_) { return false; } @@ -94,4 +105,10 @@ public class SeatEntity extends Entity { return null; } } + + @Override + public void writeSpawnData(PacketBuffer buffer) {} + + @Override + public void readSpawnData(PacketBuffer additionalData) {} } 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 new file mode 100644 index 000000000..21d1b545c --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/actors/SeatMovementBehaviour.java @@ -0,0 +1,9 @@ +package com.simibubi.create.content.contraptions.components.actors; + +import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; + +public class SeatMovementBehaviour extends MovementBehaviour { + + + +} 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 f89f05aa0..6ad59f9b2 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 @@ -1,7 +1,29 @@ package com.simibubi.create.content.contraptions.components.structureMovement; +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; +import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + +import javax.annotation.Nullable; + +import org.apache.commons.lang3.tuple.MutablePair; +import org.apache.commons.lang3.tuple.Pair; + import com.simibubi.create.AllBlocks; 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.saw.SawBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.AbstractChassisBlock; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisTileEntity; @@ -22,9 +44,19 @@ import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.worldWrappers.WrappedWorld; -import net.minecraft.block.*; + +import net.minecraft.block.AbstractButtonBlock; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.ChestBlock; +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; import net.minecraft.nbt.CompoundNBT; @@ -45,668 +77,733 @@ import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; import net.minecraftforge.common.util.Constants.BlockFlags; +import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.CombinedInvWrapper; -import org.apache.commons.lang3.tuple.MutablePair; -import org.apache.commons.lang3.tuple.Pair; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.BiPredicate; -import java.util.stream.Collectors; - -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isExtensionPole; -import static com.simibubi.create.content.contraptions.components.structureMovement.piston.MechanicalPistonBlock.isPistonHead; public abstract class Contraption { - public Map blocks; - public Map storage; - public List> actors; - public CombinedInvWrapper inventory; - public List customRenderTEs; - public Set> superglue; + public Map blocks; + public Map storage; + public List> actors; + public CombinedInvWrapper inventory; + public List customRenderTEs; + public Set> superglue; - public AxisAlignedBB bounds; - public boolean stalled; + public AxisAlignedBB bounds; + public boolean stalled; - protected Set cachedColliders; - protected Direction cachedColliderDirection; - protected BlockPos anchor; - protected List glueToRemove; - List renderOrder; + protected List seats; + protected Map seatMapping; + protected Map initialPassengers; - public Contraption() { - blocks = new HashMap<>(); - storage = new HashMap<>(); - actors = new ArrayList<>(); - superglue = new HashSet<>(); - renderOrder = new ArrayList<>(); - customRenderTEs = new ArrayList<>(); - glueToRemove = new ArrayList<>(); - } + protected Set cachedColliders; + protected Direction cachedColliderDirection; + protected BlockPos anchor; + protected List glueToRemove; + List renderOrder; - protected static boolean isChassis(BlockState state) { - return state.getBlock() instanceof AbstractChassisBlock; - } + public Contraption() { + blocks = new HashMap<>(); + storage = new HashMap<>(); + actors = new ArrayList<>(); + seats = new ArrayList<>(); + seatMapping = new HashMap<>(); + initialPassengers = new HashMap<>(); + superglue = new HashSet<>(); + renderOrder = new ArrayList<>(); + customRenderTEs = new ArrayList<>(); + glueToRemove = new ArrayList<>(); + } - 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 static boolean isChassis(BlockState state) { + return state.getBlock() instanceof AbstractChassisBlock; + } - public static Contraption fromNBT(World world, CompoundNBT nbt) { - String type = nbt.getString("Type"); - Contraption contraption = AllContraptionTypes.fromType(type); - contraption.readNBT(world, nbt); - return contraption; - } + 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; + } - public static boolean isFrozen() { - return AllConfigs.SERVER.control.freezeContraptions.get(); - } + public static Contraption fromNBT(World world, CompoundNBT nbt) { + String type = nbt.getString("Type"); + Contraption contraption = AllContraptionTypes.fromType(type); + contraption.readNBT(world, nbt); + return contraption; + } - protected static MovementBehaviour getMovement(BlockState state) { - Block block = state.getBlock(); - if (!(block instanceof IPortableBlock)) - return null; - return ((IPortableBlock) block).getMovementBehaviour(); - } + public static boolean isFrozen() { + return AllConfigs.SERVER.control.freezeContraptions.get(); + } - public Set getColliders(World world, Direction movementDirection) { - if (blocks == null) - return null; - if (cachedColliders == null || cachedColliderDirection != movementDirection) { - cachedColliders = new HashSet<>(); - cachedColliderDirection = movementDirection; + protected static MovementBehaviour getMovement(BlockState state) { + Block block = state.getBlock(); + if (!(block instanceof IPortableBlock)) + return null; + return ((IPortableBlock) block).getMovementBehaviour(); + } - 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); - } + public Set getColliders(World world, Direction movementDirection) { + if (blocks == null) + return null; + if (cachedColliders == null || cachedColliderDirection != movementDirection) { + cachedColliders = new HashSet<>(); + cachedColliderDirection = movementDirection; - } - return cachedColliders; - } + 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); + } - public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) { - List frontier = new ArrayList<>(); - Set visited = new HashSet<>(); - anchor = pos; + } + return cachedColliders; + } - if (bounds == null) - bounds = new AxisAlignedBB(BlockPos.ZERO); + public boolean searchMovedStructure(World world, BlockPos pos, @Nullable Direction forcedDirection) { + initialPassengers.clear(); + List frontier = new ArrayList<>(); + Set visited = new HashSet<>(); + anchor = pos; - if (!BlockMovementTraits.isBrittle(world.getBlockState(pos))) - frontier.add(pos); - if (!addToInitialFrontier(world, pos, forcedDirection, frontier)) - return false; - for (int limit = 100000; limit > 0; limit--) { - if (frontier.isEmpty()) - return true; - if (!moveBlock(world, frontier.remove(0), forcedDirection, frontier, visited)) - return false; - } - return false; - } + if (bounds == null) + bounds = new AxisAlignedBB(BlockPos.ZERO); - public void gatherStoredItems() { - List list = storage.values() - .stream() - .map(MountedStorage::getItemHandler) - .collect(Collectors.toList()); - inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); - } + if (!BlockMovementTraits.isBrittle(world.getBlockState(pos))) + frontier.add(pos); + if (!addToInitialFrontier(world, pos, forcedDirection, frontier)) + return false; + for (int limit = 100000; limit > 0; limit--) { + if (frontier.isEmpty()) + return true; + if (!moveBlock(world, frontier.remove(0), forcedDirection, frontier, visited)) + return false; + } + return false; + } - protected boolean addToInitialFrontier(World world, BlockPos pos, Direction forcedDirection, - List frontier) { - return true; - } + public void gatherStoredItems() { + List list = storage.values() + .stream() + .map(MountedStorage::getItemHandler) + .collect(Collectors.toList()); + inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); + } - protected boolean moveBlock(World world, BlockPos pos, Direction forcedDirection, List frontier, - Set visited) { - visited.add(pos); - frontier.remove(pos); + public void mountPassengers(ContraptionEntity contraptionEntity) { + if (contraptionEntity.world.isRemote) + return; + for (BlockPos seatPos : seats) { + Entity passenger = initialPassengers.get(seatPos); + if (passenger == null) + continue; + int seatIndex = seats.indexOf(seatPos); + if (seatIndex == -1) + continue; + contraptionEntity.addSittingPassenger(passenger, seatIndex); + } + } - if (!world.isBlockPresent(pos)) - return false; - if (isAnchoringBlockAt(pos)) - return true; - if (!BlockMovementTraits.movementNecessary(world, pos)) - return true; - if (!BlockMovementTraits.movementAllowed(world, pos)) - return false; - BlockState state = world.getBlockState(pos); - if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited)) - return false; + protected boolean addToInitialFrontier(World world, BlockPos pos, Direction forcedDirection, + List frontier) { + return true; + } - 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); - } + protected boolean moveBlock(World world, BlockPos pos, Direction forcedDirection, List frontier, + Set visited) { + visited.add(pos); + frontier.remove(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 (!world.isBlockPresent(pos)) + return false; + if (isAnchoringBlockAt(pos)) + return true; + if (!BlockMovementTraits.movementNecessary(world, pos)) + return true; + if (!BlockMovementTraits.movementAllowed(world, pos)) + return false; + BlockState state = world.getBlockState(pos); + if (isChassis(state) && !moveChassis(world, pos, forcedDirection, frontier, visited)) + return false; - // 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; - } + 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); + } - 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; - } + // Seats transfer their passenger to the contraption + if (state.getBlock() instanceof SeatBlock) { + BlockPos local = toLocalPos(pos); + seats.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 (limit <= -1) - return false; - } + // 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)); + } + } - // Doors try to stay whole - if (state.getBlock() instanceof DoorBlock) { - BlockPos otherPartPos = pos.up(state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? 1 : -1); - if (!visited.contains(otherPartPos)) - frontier.add(otherPartPos); - } + // 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; + } - Map superglue = SuperGlueHandler.gatherGlue(world, pos); + 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; + } - // Slime blocks drag adjacent blocks if possible - boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock; - for (Direction offset : Direction.values()) { - BlockPos offsetPos = pos.offset(offset); - BlockState blockState = world.getBlockState(offsetPos); - if (isAnchoringBlockAt(offsetPos)) - continue; - if (!BlockMovementTraits.movementAllowed(world, offsetPos)) { - if (offset == forcedDirection && isSlimeBlock) - return false; - continue; - } + if (limit <= -1) + return false; + } - boolean wasVisited = visited.contains(offsetPos); - boolean faceHasGlue = superglue.containsKey(offset); - boolean blockAttachedTowardsFace = - BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite()); - boolean brittle = BlockMovementTraits.isBrittle(blockState); + // Doors try to stay whole + if (state.getBlock() instanceof DoorBlock) { + BlockPos otherPartPos = pos.up(state.get(DoorBlock.HALF) == DoubleBlockHalf.LOWER ? 1 : -1); + if (!visited.contains(otherPartPos)) + frontier.add(otherPartPos); + } - if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue)) - frontier.add(offsetPos); + Map superglue = SuperGlueHandler.gatherGlue(world, pos); - if (faceHasGlue) - addGlue(superglue.get(offset)); - } + // Slime blocks drag adjacent blocks if possible + boolean isSlimeBlock = state.getBlock() instanceof SlimeBlock; + for (Direction offset : Direction.values()) { + BlockPos offsetPos = pos.offset(offset); + BlockState blockState = world.getBlockState(offsetPos); + if (isAnchoringBlockAt(offsetPos)) + continue; + if (!BlockMovementTraits.movementAllowed(world, offsetPos)) { + if (offset == forcedDirection && isSlimeBlock) + return false; + continue; + } - add(pos, capture(world, pos)); + boolean wasVisited = visited.contains(offsetPos); + boolean faceHasGlue = superglue.containsKey(offset); + boolean blockAttachedTowardsFace = + BlockMovementTraits.isBlockAttachedTowards(blockState, offset.getOpposite()); + boolean brittle = BlockMovementTraits.isBrittle(blockState); + + if (!wasVisited && ((isSlimeBlock && !brittle) || blockAttachedTowardsFace || faceHasGlue)) + frontier.add(offsetPos); + + if (faceHasGlue) + addGlue(superglue.get(offset)); + } + + add(pos, capture(world, pos)); return blocks.size() <= AllConfigs.SERVER.kinetics.maxBlocksMoved.get(); } - protected boolean isAnchoringBlockAt(BlockPos pos) { - return pos.equals(anchor); - } + protected boolean isAnchoringBlockAt(BlockPos pos) { + return pos.equals(anchor); + } - private boolean moveChassis(World world, BlockPos pos, Direction movementDirection, List frontier, - Set visited) { - TileEntity te = world.getTileEntity(pos); - if (!(te instanceof ChassisTileEntity)) - return false; - ChassisTileEntity chassis = (ChassisTileEntity) te; - chassis.addAttachedChasses(frontier, visited); - List includedBlockPositions = chassis.getIncludedBlockPositions(movementDirection, false); - if (includedBlockPositions == null) - return false; - for (BlockPos blockPos : includedBlockPositions) - if (!visited.contains(blockPos)) - frontier.add(blockPos); - return true; - } + private boolean moveChassis(World world, BlockPos pos, Direction movementDirection, List frontier, + Set visited) { + TileEntity te = world.getTileEntity(pos); + if (!(te instanceof ChassisTileEntity)) + return false; + ChassisTileEntity chassis = (ChassisTileEntity) te; + chassis.addAttachedChasses(frontier, visited); + List includedBlockPositions = chassis.getIncludedBlockPositions(movementDirection, false); + if (includedBlockPositions == null) + return false; + for (BlockPos blockPos : includedBlockPositions) + if (!visited.contains(blockPos)) + frontier.add(blockPos); + return true; + } - protected Pair capture(World world, BlockPos pos) { - BlockState blockstate = world.getBlockState(pos); - if (AllBlocks.MECHANICAL_SAW.has(blockstate)) - blockstate = blockstate.with(SawBlock.RUNNING, true); - if (blockstate.getBlock() instanceof ChestBlock) - blockstate = blockstate.with(ChestBlock.TYPE, ChestType.SINGLE); - if (AllBlocks.ADJUSTABLE_CRATE.has(blockstate)) - blockstate = blockstate.with(AdjustableCrateBlock.DOUBLE, false); - if (AllBlocks.REDSTONE_CONTACT.has(blockstate)) - blockstate = blockstate.with(RedstoneContactBlock.POWERED, true); - if (blockstate.getBlock() instanceof AbstractButtonBlock) { - blockstate = blockstate.with(AbstractButtonBlock.POWERED, false); - world.getPendingBlockTicks() - .scheduleTick(pos, blockstate.getBlock(), -1); - } - if (blockstate.getBlock() instanceof PressurePlateBlock) { - blockstate = blockstate.with(PressurePlateBlock.POWERED, false); - world.getPendingBlockTicks() - .scheduleTick(pos, blockstate.getBlock(), -1); - } - CompoundNBT compoundnbt = getTileEntityNBT(world, pos); - TileEntity tileentity = world.getTileEntity(pos); - return Pair.of(new BlockInfo(pos, blockstate, compoundnbt), tileentity); - } + protected Pair capture(World world, BlockPos pos) { + BlockState blockstate = world.getBlockState(pos); + if (AllBlocks.MECHANICAL_SAW.has(blockstate)) + blockstate = blockstate.with(SawBlock.RUNNING, true); + if (blockstate.getBlock() instanceof ChestBlock) + blockstate = blockstate.with(ChestBlock.TYPE, ChestType.SINGLE); + if (AllBlocks.ADJUSTABLE_CRATE.has(blockstate)) + blockstate = blockstate.with(AdjustableCrateBlock.DOUBLE, false); + if (AllBlocks.REDSTONE_CONTACT.has(blockstate)) + blockstate = blockstate.with(RedstoneContactBlock.POWERED, true); + if (blockstate.getBlock() instanceof AbstractButtonBlock) { + blockstate = blockstate.with(AbstractButtonBlock.POWERED, false); + world.getPendingBlockTicks() + .scheduleTick(pos, blockstate.getBlock(), -1); + } + if (blockstate.getBlock() instanceof PressurePlateBlock) { + blockstate = blockstate.with(PressurePlateBlock.POWERED, false); + world.getPendingBlockTicks() + .scheduleTick(pos, blockstate.getBlock(), -1); + } + CompoundNBT compoundnbt = getTileEntityNBT(world, pos); + TileEntity tileentity = world.getTileEntity(pos); + return Pair.of(new BlockInfo(pos, blockstate, compoundnbt), tileentity); + } - public void addGlue(SuperGlueEntity entity) { - BlockPos pos = entity.getHangingPosition(); - Direction direction = entity.getFacingDirection(); - BlockPos localPos = pos.subtract(anchor); - this.superglue.add(Pair.of(localPos, direction)); - glueToRemove.add(entity); - } + 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 void add(BlockPos pos, Pair pair) { - BlockInfo captured = pair.getKey(); - BlockPos localPos = pos.subtract(anchor); - BlockInfo blockInfo = new BlockInfo(localPos, captured.state, captured.nbt); + public BlockPos toLocalPos(BlockPos globalPos) { + return globalPos.subtract(anchor); + } - if (blocks.put(localPos, blockInfo) != null) - return; - bounds = bounds.union(new AxisAlignedBB(localPos)); + public void add(BlockPos pos, Pair pair) { + BlockInfo captured = pair.getKey(); + BlockPos localPos = pos.subtract(anchor); + BlockInfo blockInfo = new BlockInfo(localPos, captured.state, captured.nbt); - TileEntity te = pair.getValue(); - if (te != null && MountedStorage.canUseAsStorage(te)) - storage.put(localPos, new MountedStorage(te)); - if (captured.state.getBlock() instanceof IPortableBlock) - getActors().add(MutablePair.of(blockInfo, null)); - } + if (blocks.put(localPos, blockInfo) != null) + return; + bounds = bounds.union(new AxisAlignedBB(localPos)); - public void readNBT(World world, CompoundNBT nbt) { - blocks.clear(); - renderOrder.clear(); - customRenderTEs.clear(); + TileEntity te = pair.getValue(); + if (te != null && MountedStorage.canUseAsStorage(te)) + storage.put(localPos, new MountedStorage(te)); + if (captured.state.getBlock() instanceof IPortableBlock) + actors.add(MutablePair.of(blockInfo, null)); + } - nbt.getList("Blocks", 10) - .forEach(c -> { - CompoundNBT comp = (CompoundNBT) c; - BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")), - NBTUtil.readBlockState(comp.getCompound("Block")), - comp.contains("Data") ? comp.getCompound("Data") : null); - blocks.put(info.pos, info); + public void readNBT(World world, CompoundNBT nbt) { + blocks.clear(); + renderOrder.clear(); + customRenderTEs.clear(); - 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; - if (tag == null || block instanceof IPortableBlock) - return; + nbt.getList("Blocks", 10) + .forEach(c -> { + CompoundNBT comp = (CompoundNBT) c; + BlockInfo info = new BlockInfo(NBTUtil.readBlockPos(comp.getCompound("Pos")), + NBTUtil.readBlockState(comp.getCompound("Block")), + comp.contains("Data") ? comp.getCompound("Data") : null); + blocks.put(info.pos, info); - tag.putInt("x", info.pos.getX()); - tag.putInt("y", info.pos.getY()); - tag.putInt("z", info.pos.getZ()); + 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; + if (tag == null || block instanceof IPortableBlock) + return; - TileEntity te = TileEntity.create(tag); - te.setLocation(new WrappedWorld(world) { + tag.putInt("x", info.pos.getX()); + tag.putInt("y", info.pos.getY()); + tag.putInt("z", info.pos.getZ()); - @Override - public BlockState getBlockState(BlockPos pos) { - if (!pos.equals(te.getPos())) - return Blocks.AIR.getDefaultState(); - return info.state; - } + TileEntity te = TileEntity.create(tag); + te.setLocation(new WrappedWorld(world) { - }, te.getPos()); - if (te instanceof KineticTileEntity) - ((KineticTileEntity) te).setSpeed(0); - te.getBlockState(); - customRenderTEs.add(te); - } - }); + @Override + public BlockState getBlockState(BlockPos pos) { + if (!pos.equals(te.getPos())) + return Blocks.AIR.getDefaultState(); + return info.state; + } - actors.clear(); - nbt.getList("Actors", 10) - .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; - getActors().add(MutablePair.of(info, context)); - }); + }, te.getPos()); + if (te instanceof KineticTileEntity) + ((KineticTileEntity) te).setSpeed(0); + te.getBlockState(); + customRenderTEs.add(te); + } + }); - superglue.clear(); - nbt.getList("Superglue", 10) - .forEach(c -> { - CompoundNBT comp = (CompoundNBT) c; - superglue.add(Pair.of(NBTUtil.readBlockPos(comp.getCompound("Pos")), - Direction.byIndex(comp.getByte("Direction")))); - }); + actors.clear(); + nbt.getList("Actors", 10) + .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; + getActors().add(MutablePair.of(info, context)); + }); - storage.clear(); - nbt.getList("Storage", 10) - .forEach(c -> { - CompoundNBT comp = (CompoundNBT) c; - storage.put(NBTUtil.readBlockPos(comp.getCompound("Pos")), - new MountedStorage(comp.getCompound("Data"))); - }); - List list = storage.values() - .stream() - .map(MountedStorage::getItemHandler) - .collect(Collectors.toList()); - inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); + superglue.clear(); + nbt.getList("Superglue", 10) + .forEach(c -> { + CompoundNBT comp = (CompoundNBT) c; + superglue.add(Pair.of(NBTUtil.readBlockPos(comp.getCompound("Pos")), + Direction.byIndex(comp.getByte("Direction")))); + }); - if (nbt.contains("BoundsFront")) - bounds = NBTHelper.readAABB(nbt.getList("BoundsFront", 5)); + storage.clear(); + nbt.getList("Storage", 10) + .forEach(c -> { + CompoundNBT comp = (CompoundNBT) c; + storage.put(NBTUtil.readBlockPos(comp.getCompound("Pos")), + new MountedStorage(comp.getCompound("Data"))); + }); + List list = storage.values() + .stream() + .map(MountedStorage::getItemHandler) + .collect(Collectors.toList()); + inventory = new CombinedInvWrapper(Arrays.copyOf(list.toArray(), list.size(), IItemHandlerModifiable[].class)); - stalled = nbt.getBoolean("Stalled"); - anchor = NBTUtil.readBlockPos(nbt.getCompound("Anchor")); - } + if (nbt.contains("BoundsFront")) + bounds = NBTHelper.readAABB(nbt.getList("BoundsFront", 5)); - public CompoundNBT writeNBT() { - CompoundNBT nbt = new CompoundNBT(); - nbt.putString("Type", getType().id); - ListNBT blocksNBT = new ListNBT(); - for (BlockInfo block : this.blocks.values()) { - CompoundNBT c = new CompoundNBT(); - c.put("Block", NBTUtil.writeBlockState(block.state)); - c.put("Pos", NBTUtil.writeBlockPos(block.pos)); - if (block.nbt != null) - c.put("Data", block.nbt); - blocksNBT.add(c); - } + seats.clear(); + NBTHelper.iterateCompoundList(nbt.getList("Seats", NBT.TAG_COMPOUND), c -> seats.add(NBTUtil.readBlockPos(c))); + seatMapping.clear(); + NBTHelper.iterateCompoundList(nbt.getList("Passengers", NBT.TAG_COMPOUND), + c -> seatMapping.put(NBTUtil.readUniqueId(c.getCompound("Id")), c.getInt("Seat"))); - ListNBT actorsNBT = new ListNBT(); - for (MutablePair actor : getActors()) { - CompoundNBT compound = new CompoundNBT(); - compound.put("Pos", NBTUtil.writeBlockPos(actor.left.pos)); - getMovement(actor.left.state).writeExtraData(actor.right); - actor.right.writeToNBT(compound); - actorsNBT.add(compound); - } + stalled = nbt.getBoolean("Stalled"); + anchor = NBTUtil.readBlockPos(nbt.getCompound("Anchor")); + } - ListNBT superglueNBT = new ListNBT(); - for (Pair glueEntry : superglue) { - CompoundNBT c = new CompoundNBT(); - c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); - c.putByte("Direction", (byte) glueEntry.getValue() - .getIndex()); - superglueNBT.add(c); - } + public CompoundNBT writeNBT() { + CompoundNBT nbt = new CompoundNBT(); + nbt.putString("Type", getType().id); + ListNBT blocksNBT = new ListNBT(); + for (BlockInfo block : this.blocks.values()) { + CompoundNBT c = new CompoundNBT(); + c.put("Block", NBTUtil.writeBlockState(block.state)); + c.put("Pos", NBTUtil.writeBlockPos(block.pos)); + if (block.nbt != null) + c.put("Data", block.nbt); + blocksNBT.add(c); + } - ListNBT storageNBT = new ListNBT(); - for (BlockPos pos : storage.keySet()) { - CompoundNBT c = new CompoundNBT(); - MountedStorage mountedStorage = storage.get(pos); - if (!mountedStorage.isWorking()) - continue; - c.put("Pos", NBTUtil.writeBlockPos(pos)); - c.put("Data", mountedStorage.serialize()); - storageNBT.add(c); - } + ListNBT actorsNBT = new ListNBT(); + for (MutablePair actor : getActors()) { + CompoundNBT compound = new CompoundNBT(); + compound.put("Pos", NBTUtil.writeBlockPos(actor.left.pos)); + getMovement(actor.left.state).writeExtraData(actor.right); + actor.right.writeToNBT(compound); + actorsNBT.add(compound); + } - nbt.put("Blocks", blocksNBT); - nbt.put("Actors", actorsNBT); - nbt.put("Superglue", superglueNBT); - nbt.put("Storage", storageNBT); - nbt.put("Anchor", NBTUtil.writeBlockPos(anchor)); - nbt.putBoolean("Stalled", stalled); + ListNBT superglueNBT = new ListNBT(); + for (Pair glueEntry : superglue) { + CompoundNBT c = new CompoundNBT(); + c.put("Pos", NBTUtil.writeBlockPos(glueEntry.getKey())); + c.putByte("Direction", (byte) glueEntry.getValue() + .getIndex()); + superglueNBT.add(c); + } - if (bounds != null) { - ListNBT bb = NBTHelper.writeAABB(bounds); - nbt.put("BoundsFront", bb); - } + ListNBT storageNBT = new ListNBT(); + for (BlockPos pos : storage.keySet()) { + CompoundNBT c = new CompoundNBT(); + MountedStorage mountedStorage = storage.get(pos); + if (!mountedStorage.isWorking()) + continue; + c.put("Pos", NBTUtil.writeBlockPos(pos)); + c.put("Data", mountedStorage.serialize()); + storageNBT.add(c); + } - return nbt; - } + nbt.put("Seats", NBTHelper.writeCompoundList(seats, NBTUtil::writeBlockPos)); + nbt.put("Passengers", NBTHelper.writeCompoundList(seatMapping.entrySet(), e -> { + CompoundNBT tag = new CompoundNBT(); + tag.put("Id", NBTUtil.writeUniqueId(e.getKey())); + tag.putInt("Seat", e.getValue()); + return tag; + })); - public void removeBlocksFromWorld(IWorld world, BlockPos offset) { - removeBlocksFromWorld(world, offset, (pos, state) -> false); - } + nbt.put("Blocks", blocksNBT); + nbt.put("Actors", actorsNBT); + nbt.put("Superglue", superglueNBT); + nbt.put("Storage", storageNBT); + nbt.put("Anchor", NBTUtil.writeBlockPos(anchor)); + nbt.putBoolean("Stalled", stalled); - public void removeBlocksFromWorld(IWorld world, BlockPos offset, BiPredicate customRemoval) { - storage.values() - .forEach(MountedStorage::empty); - glueToRemove.forEach(SuperGlueEntity::remove); + if (bounds != null) { + ListNBT bb = NBTHelper.writeAABB(bounds); + nbt.put("BoundsFront", bb); + } - for (boolean brittles : Iterate.trueAndFalse) { - for (Iterator iterator = blocks.values() - .iterator(); iterator.hasNext(); ) { - BlockInfo block = iterator.next(); - if (brittles != BlockMovementTraits.isBrittle(block.state)) - continue; + return nbt; + } - BlockPos add = block.pos.add(anchor) - .add(offset); - if (customRemoval.test(add, block.state)) - continue; - BlockState oldState = world.getBlockState(add); - Block blockIn = oldState.getBlock(); - if (block.state.getBlock() != blockIn) - iterator.remove(); - world.getWorld() - .removeTileEntity(add); - int flags = 67; - if (blockIn instanceof DoorBlock) - flags = flags | 32 | 16; - if (blockIn instanceof IWaterLoggable && oldState.has(BlockStateProperties.WATERLOGGED) && oldState.get(BlockStateProperties.WATERLOGGED).booleanValue()) { - world.setBlockState(add, Blocks.WATER.getDefaultState(), flags); - continue; - } - world.setBlockState(add, Blocks.AIR.getDefaultState(), flags); - } - } - } + protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) { + return false; + } - public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { - addBlocksToWorld(world, offset, rotation, (pos, state) -> false); - } + protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { + return false; + } - public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation, - BiPredicate customPlacement) { - stop(world); - StructureTransform transform = new StructureTransform(offset, rotation); + public void removeBlocksFromWorld(IWorld world, BlockPos offset) { + storage.values() + .forEach(MountedStorage::empty); + glueToRemove.forEach(SuperGlueEntity::remove); - for (boolean nonBrittles : Iterate.trueAndFalse) { - for (BlockInfo block : blocks.values()) { - if (nonBrittles == BlockMovementTraits.isBrittle(block.state)) - continue; + for (boolean brittles : Iterate.trueAndFalse) { + for (Iterator iterator = blocks.values() + .iterator(); iterator.hasNext();) { + BlockInfo block = iterator.next(); + if (brittles != BlockMovementTraits.isBrittle(block.state)) + continue; - BlockPos targetPos = transform.apply(block.pos); + BlockPos add = block.pos.add(anchor) + .add(offset); + if (customBlockRemoval(world, add, block.state)) + continue; + BlockState oldState = world.getBlockState(add); + Block blockIn = oldState.getBlock(); + if (block.state.getBlock() != blockIn) + iterator.remove(); + world.getWorld() + .removeTileEntity(add); + int flags = 67; + if (blockIn instanceof DoorBlock) + flags = flags | 32 | 16; + if (blockIn instanceof IWaterLoggable && oldState.has(BlockStateProperties.WATERLOGGED) + && oldState.get(BlockStateProperties.WATERLOGGED) + .booleanValue()) { + world.setBlockState(add, Blocks.WATER.getDefaultState(), flags); + continue; + } + world.setBlockState(add, Blocks.AIR.getDefaultState(), flags); + } + } + } - BlockState state = transform.apply(block.state); + public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation, List seatedEntities) { + stop(world); + StructureTransform transform = new StructureTransform(offset, rotation); - if (customPlacement.test(targetPos, state)) - continue; + for (boolean nonBrittles : Iterate.trueAndFalse) { + for (BlockInfo block : blocks.values()) { + if (nonBrittles == BlockMovementTraits.isBrittle(block.state)) + continue; - if (nonBrittles) - for (Direction face : Direction.values()) - state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, - targetPos, targetPos.offset(face)); + BlockPos targetPos = transform.apply(block.pos); + BlockState state = transform.apply(block.state); - if (AllBlocks.MECHANICAL_SAW.has(state)) - state = state.with(SawBlock.RUNNING, false); + if (customBlockPlacement(world, targetPos, state)) + continue; - BlockState blockState = world.getBlockState(targetPos); - if (blockState.getBlockHardness(world, targetPos) == -1 || (state.getCollisionShape(world, targetPos) - .isEmpty() - && !blockState.getCollisionShape(world, targetPos) - .isEmpty())) { - if (targetPos.getY() == 0) - targetPos = targetPos.up(); - world.playEvent(2001, targetPos, Block.getStateId(state)); - Block.spawnDrops(state, world, targetPos, null); - continue; - } - if (state.getBlock() instanceof IWaterLoggable && state.has(BlockStateProperties.WATERLOGGED)) { - IFluidState ifluidstate = world.getFluidState(targetPos); - state = state.with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); - } + if (nonBrittles) + for (Direction face : Direction.values()) + state = state.updatePostPlacement(face, world.getBlockState(targetPos.offset(face)), world, + targetPos, targetPos.offset(face)); - world.destroyBlock(targetPos, true); - world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING); + if (AllBlocks.MECHANICAL_SAW.has(state)) + state = state.with(SawBlock.RUNNING, false); - boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal(); - verticalRotation = verticalRotation && transform.rotation != Rotation.NONE; - if (verticalRotation) { - if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock) - world.destroyBlock(targetPos, true); - } + BlockState blockState = world.getBlockState(targetPos); + if (blockState.getBlockHardness(world, targetPos) == -1 || (state.getCollisionShape(world, targetPos) + .isEmpty() + && !blockState.getCollisionShape(world, targetPos) + .isEmpty())) { + if (targetPos.getY() == 0) + targetPos = targetPos.up(); + world.playEvent(2001, targetPos, Block.getStateId(state)); + Block.spawnDrops(state, world, targetPos, null); + continue; + } + if (state.getBlock() instanceof IWaterLoggable && state.has(BlockStateProperties.WATERLOGGED)) { + IFluidState ifluidstate = world.getFluidState(targetPos); + state = state.with(BlockStateProperties.WATERLOGGED, + Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER)); + } - TileEntity tileEntity = world.getTileEntity(targetPos); - CompoundNBT tag = block.nbt; - if (tileEntity != null && tag != null) { - tag.putInt("x", targetPos.getX()); - tag.putInt("y", targetPos.getY()); - tag.putInt("z", targetPos.getZ()); + world.destroyBlock(targetPos, true); + world.setBlockState(targetPos, state, 3 | BlockFlags.IS_MOVING); - if (verticalRotation && tileEntity instanceof PulleyTileEntity) { - tag.remove("Offset"); - tag.remove("InitialOffset"); - } + boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal(); + verticalRotation = verticalRotation && transform.rotation != Rotation.NONE; + if (verticalRotation) { + if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock) + world.destroyBlock(targetPos, true); + } - tileEntity.read(tag); + TileEntity tileEntity = world.getTileEntity(targetPos); + CompoundNBT tag = block.nbt; + if (tileEntity != null && tag != null) { + tag.putInt("x", targetPos.getX()); + tag.putInt("y", targetPos.getY()); + tag.putInt("z", targetPos.getZ()); - if (storage.containsKey(block.pos)) { - MountedStorage mountedStorage = storage.get(block.pos); - if (mountedStorage.isWorking()) - mountedStorage.fill(tileEntity); - } - } - } - } + if (verticalRotation && tileEntity instanceof PulleyTileEntity) { + tag.remove("Offset"); + tag.remove("InitialOffset"); + } - for (Pair pair : superglue) { - BlockPos targetPos = transform.apply(pair.getKey()); - Direction targetFacing = transform.transformFacing(pair.getValue()); + tileEntity.read(tag); - SuperGlueEntity entity = new SuperGlueEntity(world, targetPos, targetFacing); - if (entity.onValidSurface()) { - if (!world.isRemote) - world.addEntity(entity); - } + if (storage.containsKey(block.pos)) { + MountedStorage mountedStorage = storage.get(block.pos); + if (mountedStorage.isWorking()) + mountedStorage.fill(tileEntity); + } + } + } + } - } + for (Pair pair : superglue) { + BlockPos targetPos = transform.apply(pair.getKey()); + Direction targetFacing = transform.transformFacing(pair.getValue()); - } + SuperGlueEntity entity = new SuperGlueEntity(world, targetPos, targetFacing); + if (entity.onValidSurface()) { + if (!world.isRemote) + world.addEntity(entity); + } + } - public void initActors(World world) { - for (MutablePair pair : actors) { - MovementContext context = new MovementContext(world, pair.left); - context.contraption = this; - getMovement(pair.left.state).startMoving(context); - pair.setRight(context); - } - } + for (Entity seatedEntity : seatedEntities) { + if (seatMapping.isEmpty()) + continue; + Integer seatIndex = seatMapping.get(seatedEntity.getUniqueID()); + BlockPos seatPos = seats.get(seatIndex); + seatPos = transform.apply(seatPos); + if (!(world.getBlockState(seatPos) + .getBlock() instanceof SeatBlock)) + continue; + if (SeatBlock.isSeatOccupied(world, seatPos)) + continue; + SeatBlock.sitDown(world, seatPos, seatedEntity); + } - public AxisAlignedBB getBoundingBox() { - return bounds; - } + } - public List> getActors() { - return actors; - } + public void initActors(World world) { + for (MutablePair pair : actors) { + MovementContext context = new MovementContext(world, pair.left); + context.contraption = this; + getMovement(pair.left.state).startMoving(context); + pair.setRight(context); + } + } - public BlockPos getAnchor() { - return anchor; - } + public AxisAlignedBB getBoundingBox() { + return bounds; + } - public void stop(World world) { - foreachActor(world, (behaviour, ctx) -> { - behaviour.stopMoving(ctx); - ctx.position = null; - ctx.motion = Vec3d.ZERO; - ctx.relativeMotion = Vec3d.ZERO; - ctx.rotation = Vec3d.ZERO; - }); - } + public List> getActors() { + return actors; + } - public void foreachActor(World world, BiConsumer callBack) { - for (MutablePair pair : actors) - callBack.accept(getMovement(pair.getLeft().state), pair.getRight()); - } + public BlockPos getAnchor() { + return anchor; + } - public void expandBoundsAroundAxis(Axis axis) { - AxisAlignedBB bb = bounds; - double maxXDiff = Math.max(bb.maxX - 1, -bb.minX); - double maxYDiff = Math.max(bb.maxY - 1, -bb.minY); - double maxZDiff = Math.max(bb.maxZ - 1, -bb.minZ); - double maxDiff = 0; + public void stop(World world) { + foreachActor(world, (behaviour, ctx) -> { + behaviour.stopMoving(ctx); + ctx.position = null; + ctx.motion = Vec3d.ZERO; + ctx.relativeMotion = Vec3d.ZERO; + ctx.rotation = Vec3d.ZERO; + }); + } - if (axis == Axis.X) - maxDiff = Math.max(maxZDiff, maxYDiff); - if (axis == Axis.Y) - maxDiff = Math.max(maxZDiff, maxXDiff); - if (axis == Axis.Z) - maxDiff = Math.max(maxXDiff, maxYDiff); + public void foreachActor(World world, BiConsumer callBack) { + for (MutablePair pair : actors) + callBack.accept(getMovement(pair.getLeft().state), pair.getRight()); + } - Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis) - .getDirectionVec()); - Vec3d planeByNormal = VecHelper.planeByNormal(vec); - Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ) - .add(planeByNormal.scale(-maxDiff)); - Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ) - .add(planeByNormal.scale(maxDiff + 1)); - bounds = new AxisAlignedBB(min, max); - } + public void expandBoundsAroundAxis(Axis axis) { + AxisAlignedBB bb = bounds; + double maxXDiff = Math.max(bb.maxX - 1, -bb.minX); + double maxYDiff = Math.max(bb.maxY - 1, -bb.minY); + double maxZDiff = Math.max(bb.maxZ - 1, -bb.minZ); + double maxDiff = 0; - protected abstract AllContraptionTypes getType(); + if (axis == Axis.X) + maxDiff = Math.max(maxZDiff, maxYDiff); + if (axis == Axis.Y) + maxDiff = Math.max(maxZDiff, maxXDiff); + if (axis == Axis.Z) + maxDiff = Math.max(maxXDiff, maxYDiff); + + Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis) + .getDirectionVec()); + Vec3d planeByNormal = VecHelper.planeByNormal(vec); + Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ) + .add(planeByNormal.scale(-maxDiff)); + Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ) + .add(planeByNormal.scale(maxDiff + 1)); + bounds = new AxisAlignedBB(min, max); + } + + public BlockPos getSeat(UUID entityId) { + if (!seatMapping.containsKey(entityId)) + return null; + int seatIndex = seatMapping.get(entityId); + if (seatIndex >= seats.size()) + return null; + return seats.get(seatIndex); + } + + protected abstract AllContraptionTypes getType(); } \ 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 6de3581fa..4c3770901 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 @@ -24,6 +24,7 @@ import com.simibubi.create.foundation.collision.ContinuousOBBCollider.Continuous import com.simibubi.create.foundation.collision.Matrix3d; import com.simibubi.create.foundation.collision.OrientedBB; import com.simibubi.create.foundation.utility.AngleHelper; +import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.block.BlockState; @@ -32,9 +33,11 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.world.ClientWorld; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; import net.minecraft.entity.MoverType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; import net.minecraft.util.Direction.Axis; @@ -51,10 +54,12 @@ 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.Constants.NBT; import net.minecraftforge.event.TickEvent.ClientTickEvent; import net.minecraftforge.event.TickEvent.Phase; import net.minecraftforge.event.TickEvent.WorldTickEvent; import net.minecraftforge.event.entity.EntityJoinWorldEvent; +import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod.EventBusSubscriber; @@ -66,7 +71,7 @@ public class ContraptionCollider { new DamageSource("create.contraption_suffocate").setDamageBypassesArmor(); public static boolean wasClientPlayerGrounded; public static Cache>> activeContraptions = CacheBuilder.newBuilder() - .expireAfterAccess(40, SECONDS) + .expireAfterAccess(400, SECONDS) .build(); @SubscribeEvent @@ -102,6 +107,22 @@ public class ContraptionCollider { runCollisions(world); } + @SubscribeEvent + public static void entitiesWhoJustDismountedGetSentToTheRightLocation(LivingUpdateEvent event) { + LivingEntity entityLiving = event.getEntityLiving(); + if (entityLiving == null) + return; + if (entityLiving.world.isRemote) + return; + CompoundNBT data = entityLiving.getPersistentData(); + if (!data.contains("ContraptionDismountLocation")) + return; + Vec3d position = VecHelper.readNBT(data.getList("ContraptionDismountLocation", NBT.TAG_DOUBLE)); + if (entityLiving.getRidingEntity() == null) + entityLiving.setPositionAndUpdate(position.x, position.y, position.z); + data.remove("ContraptionDismountLocation"); + } + private static void runCollisions(World world) { List> list = activeContraptions.getIfPresent(world); if (list == null) @@ -131,9 +152,9 @@ public class ContraptionCollider { return; Vec3d centerOfBlock = VecHelper.getCenterOf(BlockPos.ZERO); - double conRotX = contraptionRotation.z; + double conRotX = contraptionRotation.x; double conRotY = contraptionRotation.y; - double conRotZ = contraptionRotation.x; + double conRotZ = contraptionRotation.z; Vec3d conMotion = contraptionPosition.subtract(contraptionEntity.getPrevPositionVec()); Vec3d conAngularMotion = contraptionRotation.subtract(contraptionEntity.getPrevRotationVec()); Vec3d contraptionCentreOffset = contraptionEntity.stationary ? centerOfBlock : Vec3d.ZERO.add(0, 0.5, 0); @@ -180,6 +201,7 @@ public class ContraptionCollider { // Prepare entity bounds OrientedBB obb = new OrientedBB(localBB); obb.setRotation(rotation); + motion = motion.subtract(conMotion); motion = rotation.transform(motion); // Vec3d visualizerOrigin = new Vec3d(10, 64, 0); @@ -198,41 +220,48 @@ public class ContraptionCollider { .forEach(shape -> shape.toBoundingBoxList() .forEach(bbs::add)); - for (AxisAlignedBB bb : bbs) { - Vec3d currentResponse = collisionResponse.getValue(); - obb.setCenter(obbCenter.add(currentResponse)); - ContinuousSeparationManifold intersect = obb.intersect(bb, allowedMotion.getValue()); -// OutlineParams params = CreateClient.outliner.showAABB(bb, bb.offset(visualizerOrigin)) -// .withFaceTexture(AllSpecialTextures.HIGHLIGHT_CHECKERED); -// params.colored(0xffffff); + boolean doHorizontalPass = conRotX == 0 && conRotZ == 0; + for (boolean horizontalPass : Iterate.trueAndFalse) { - if (intersect == null) - continue; - if (surfaceCollision.isFalse()) - surfaceCollision.setValue(intersect.isSurfaceCollision()); + for (AxisAlignedBB bb : bbs) { + Vec3d currentResponse = collisionResponse.getValue(); + obb.setCenter(obbCenter.add(currentResponse)); + ContinuousSeparationManifold intersect = obb.intersect(bb, allowedMotion.getValue()); - double timeOfImpact = intersect.getTimeOfImpact(); - if (timeOfImpact > 0 && timeOfImpact < 1) { - futureCollision.setTrue(); -// Vec3d prev = allowedMotion.getValue(); - allowedMotion.setValue(intersect.getAllowedMotion(allowedMotion.getValue())); -// Debug.debugChat("Allowed Motion FROM " + prev.toString()); -// Debug.debugChat("Allowed Motion TO " + allowedMotion.getValue() -// .toString()); -// params.colored(0x4499ff); - continue; - } - Vec3d separation = intersect.asSeparationVec(entity.stepHeight); - if (separation != null && !separation.equals(Vec3d.ZERO)) { - collisionResponse.setValue(currentResponse.add(separation)); -// Debug.debugChat("Collision " + currentResponse.add(separation) -// .toString()); -// params.colored(0xff9944); + if (intersect == null) + continue; + if ((!horizontalPass || !doHorizontalPass) && surfaceCollision.isFalse()) + surfaceCollision.setValue(intersect.isSurfaceCollision()); + + double timeOfImpact = intersect.getTimeOfImpact(); + if (timeOfImpact > 0 && timeOfImpact < 1) { + futureCollision.setTrue(); + allowedMotion.setValue(intersect.getAllowedMotion(allowedMotion.getValue())); + continue; + } + + Vec3d separation = intersect.asSeparationVec(entity.stepHeight); + if (separation != null && !separation.equals(Vec3d.ZERO)) + collisionResponse.setValue(currentResponse.add(separation)); } + + if (!horizontalPass || !doHorizontalPass) + break; + + boolean noVerticalMotionResponse = allowedMotion.getValue().y == motion.y; + boolean noVerticalCollision = collisionResponse.getValue().y == 0; + if (noVerticalCollision && noVerticalMotionResponse) + break; + + // Re-run collisions with horizontal offset + collisionResponse.setValue(collisionResponse.getValue() + .mul(1, 0, 1)); + allowedMotion.setValue(allowedMotion.getValue() + .mul(1, 0, 1) + .add(0, motion.y, 0)); + continue; } -// Debug.debugChat("----"); - // Resolve collision Vec3d entityMotion = entity.getMotion(); Vec3d totalResponse = collisionResponse.getValue(); @@ -240,7 +269,8 @@ public class ContraptionCollider { boolean hardCollision = !totalResponse.equals(Vec3d.ZERO); rotation.transpose(); - motionResponse = rotation.transform(motionResponse); + motionResponse = rotation.transform(motionResponse) + .add(conMotion); totalResponse = rotation.transform(totalResponse); rotation.transpose(); @@ -262,7 +292,7 @@ public class ContraptionCollider { Vec3d contactPoint = entityPosition.subtract(contraptionCentreOffset) .subtract(contraptionPosition); contactPoint = - VecHelper.rotate(contactPoint, conAngularMotion.z, conAngularMotion.y, conAngularMotion.x); + VecHelper.rotate(contactPoint, conAngularMotion.x, conAngularMotion.y, conAngularMotion.z); contactPoint = contactPoint.add(contraptionPosition) .add(contraptionCentreOffset) .add(conMotion); 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 index 3a1a815d7..2dedebad0 100644 --- 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 @@ -5,12 +5,15 @@ import static com.simibubi.create.foundation.utility.AngleHelper.getShortestAngl import java.util.ArrayList; import java.util.List; +import java.util.Map.Entry; +import java.util.UUID; import java.util.stream.Stream; import org.apache.commons.lang3.tuple.MutablePair; import com.google.common.collect.ImmutableSet; 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; @@ -45,6 +48,7 @@ import net.minecraft.tags.BlockTags; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.DamageSource; import net.minecraft.util.Direction; +import net.minecraft.util.Hand; import net.minecraft.util.ReuseableStream; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; @@ -70,7 +74,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD protected BlockPos controllerPos; protected Vec3d motionBeforeStall; protected boolean stationary; - + protected boolean initialized; final List collidingEntities = new ArrayList<>(); private static final Ingredient FUEL_ITEMS = Ingredient.fromItems(Items.COAL, Items.CHARCOAL); @@ -98,11 +102,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD public static ContraptionEntity createMounted(World world, Contraption contraption, float initialAngle) { ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.CONTRAPTION.get(), world); - entity.contraption = contraption; + entity.contraptionCreated(contraption); entity.initialAngle = initialAngle; entity.forceYaw(initialAngle); - if (contraption != null) - contraption.gatherStoredItems(); return entity; } @@ -116,12 +118,25 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD public static ContraptionEntity createStationary(World world, Contraption contraption) { ContraptionEntity entity = new ContraptionEntity(AllEntityTypes.STATIONARY_CONTRAPTION.get(), world); - entity.contraption = contraption; - if (contraption != null) - contraption.gatherStoredItems(); + entity.contraptionCreated(contraption); return entity; } + 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; @@ -142,6 +157,110 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD 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.seatMapping.put(passenger.getUniqueID(), seatIndex); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionSeatMappingPacket(getEntityId(), contraption.seatMapping)); + } + + @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.seatMapping.remove(passenger.getUniqueID()); + AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> this), + new ContraptionSeatMappingPacket(getEntityId(), contraption.seatMapping)); + } + + @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)) + .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.seats.size(); + } + + public boolean handlePlayerInteraction(PlayerEntity player, BlockPos localPos, Direction side, + Hand interactionHand) { + int indexOfSeat = contraption.seats.indexOf(localPos); + if (indexOfSeat == -1) + return false; + + // Eject potential existing passenger + for (Entry entry : contraption.seatMapping.entrySet()) { + if (entry.getValue() != indexOfSeat) + continue; + for (Entity entity : getPassengers()) { + if (!entry.getKey().equals(entity.getUniqueID())) + continue; + if (entity instanceof PlayerEntity) + return false; + if (!world.isRemote) { + Vec3d transformedVector = getPassengerPosition(entity); + entity.stopRiding(); + if (transformedVector != null) + entity.setPositionAndUpdate(transformedVector.x, transformedVector.y, transformedVector.z); + } + + } + } + + if (world.isRemote) + return true; + addSittingPassenger(player, indexOfSeat); + return true; + } + + public Vec3d toGlobalVector(Vec3d localVec) { + Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); + localVec = localVec.subtract(rotationOffset); + localVec = VecHelper.rotate(localVec, getRotationVec()); + localVec = localVec.add(rotationOffset) + .add(getAnchorVec()); + return localVec; + } + + public Vec3d toLocalVector(Vec3d globalVec) { + Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); + globalVec = globalVec.subtract(getAnchorVec()) + .subtract(rotationOffset); + globalVec = VecHelper.rotate(globalVec, getRotationVec().scale(-1)); + globalVec = globalVec.add(rotationOffset); + return globalVec; + } + @Override public void tick() { if (contraption == null) { @@ -149,6 +268,9 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD return; } + if (!initialized) + contraptionInitialize(); + checkController(); Entity mountedEntity = getRidingEntity(); @@ -173,10 +295,6 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD super.tick(); } - public void collisionTick() { -// ContraptionCollider.collideEntities(this); - } - public void tickAsPassenger(Entity e) { boolean rotationLock = false; boolean pauseWhileRotating = false; @@ -266,10 +384,8 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } public void tickActors(Vec3d movementVector) { - float anglePitch = getPitch(1); - float angleYaw = getYaw(1); - float angleRoll = getRoll(1); - Vec3d rotationVec = new Vec3d(angleRoll, angleYaw, anglePitch); + Vec3d rotationVec = getRotationVec(); + Vec3d reversedRotationVec = rotationVec.scale(-1); Vec3d rotationOffset = VecHelper.getCenterOf(BlockPos.ZERO); boolean stalledPreviously = contraption.stalled; @@ -283,7 +399,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD Vec3d actorPosition = new Vec3d(blockInfo.pos); actorPosition = actorPosition.add(actor.getActiveAreaOffset(context)); - actorPosition = VecHelper.rotate(actorPosition, angleRoll, angleYaw, anglePitch); + actorPosition = VecHelper.rotate(actorPosition, rotationVec); actorPosition = actorPosition.add(rotationOffset) .add(getAnchorVec()); @@ -295,7 +411,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD if (previousPosition != null) { context.motion = actorPosition.subtract(previousPosition); Vec3d relativeMotion = context.motion; - relativeMotion = VecHelper.rotate(relativeMotion, -angleRoll, -angleYaw, -anglePitch); + relativeMotion = VecHelper.rotate(relativeMotion, reversedRotationVec); context.relativeMotion = relativeMotion; newPosVisited = !new BlockPos(previousPosition).equals(gridPosition) || context.relativeMotion.length() > 0 && context.firstMovement; @@ -429,6 +545,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD @Override protected void readAdditional(CompoundNBT compound) { + initialized = compound.getBoolean("Initialized"); contraption = Contraption.fromNBT(world, compound.getCompound("Contraption")); initialAngle = compound.getFloat("InitialAngle"); forceYaw(compound.contains("ForcedYaw") ? compound.getFloat("ForcedYaw") : initialAngle); @@ -479,6 +596,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD compound.putFloat("InitialAngle", initialAngle); compound.putBoolean("Stalled", isStalled()); + compound.putBoolean("Initialized", initialized); } @Override @@ -499,15 +617,15 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } public void disassemble() { - if (!isAlive()) { + if (!isAlive()) return; - } if (getContraption() != null) { remove(); BlockPos offset = new BlockPos(getAnchorVec().add(.5, .5, .5)); - Vec3d rotation = new Vec3d(getRoll(1), getYaw(1), getPitch(1)); - getContraption().addBlocksToWorld(world, offset, rotation); - preventMovedEntitiesFromGettingStuck(); + Vec3d rotation = getRotationVec(); + setBoundingBox(new AxisAlignedBB(0, 300, 0, 0, 300, 0)); + contraption.addBlocksToWorld(world, offset, rotation, getPassengers()); +// preventMovedEntitiesFromGettingStuck(); } } @@ -633,11 +751,11 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD } public Vec3d getRotationVec() { - return new Vec3d(getPitch(1), getYaw(1), getRoll(1)); + return new Vec3d(getRoll(1), getYaw(1), getPitch(1)); } public Vec3d getPrevRotationVec() { - return new Vec3d(getPitch(0), getYaw(0), getRoll(0)); + return new Vec3d(getRoll(0), getYaw(0), getPitch(0)); } public Vec3d getPrevPositionVec() { @@ -653,8 +771,12 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD 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) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionPacket.java new file mode 100644 index 000000000..0b2d2c56a --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionInteractionPacket.java @@ -0,0 +1,65 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.Direction; +import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class ContraptionInteractionPacket extends SimplePacketBase { + + private Hand interactionHand; + private int target; + private BlockPos localPos; + private Direction face; + + public ContraptionInteractionPacket(ContraptionEntity target, Hand hand, BlockPos localPos, Direction side) { + this.interactionHand = hand; + this.localPos = localPos; + this.target = target.getEntityId(); + this.face = side; + } + + public ContraptionInteractionPacket(PacketBuffer buffer) { + target = buffer.readInt(); + int handId = buffer.readInt(); + interactionHand = handId == -1 ? null : Hand.values()[handId]; + localPos = buffer.readBlockPos(); + face = Direction.byIndex(buffer.readShort()); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeInt(target); + buffer.writeInt(interactionHand == null ? -1 : interactionHand.ordinal()); + buffer.writeBlockPos(localPos); + buffer.writeShort(face.getIndex()); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + ServerPlayerEntity sender = context.get() + .getSender(); + if (sender == null) + return; + Entity entityByID = sender.getServerWorld() + .getEntityByID(target); + if (!(entityByID instanceof ContraptionEntity)) + return; + ContraptionEntity contraptionEntity = (ContraptionEntity) entityByID; + if (contraptionEntity.handlePlayerInteraction(sender, localPos, face, interactionHand)) + sender.swingHand(interactionHand, true); + }); + context.get() + .setPacketHandled(true); + } + +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionSeatMappingPacket.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionSeatMappingPacket.java new file mode 100644 index 000000000..d67e51504 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/ContraptionSeatMappingPacket.java @@ -0,0 +1,58 @@ +package com.simibubi.create.content.contraptions.components.structureMovement; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.function.Supplier; + +import com.simibubi.create.foundation.networking.SimplePacketBase; + +import net.minecraft.client.Minecraft; +import net.minecraft.entity.Entity; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent.Context; + +public class ContraptionSeatMappingPacket extends SimplePacketBase { + + private Map mapping; + private int entityID; + + public ContraptionSeatMappingPacket(int entityID, Map mapping) { + this.entityID = entityID; + this.mapping = mapping; + } + + public ContraptionSeatMappingPacket(PacketBuffer buffer) { + entityID = buffer.readInt(); + mapping = new HashMap<>(); + short size = buffer.readShort(); + for (int i = 0; i < size; i++) + mapping.put(buffer.readUniqueId(), (int) buffer.readShort()); + } + + @Override + public void write(PacketBuffer buffer) { + buffer.writeInt(entityID); + buffer.writeShort(mapping.size()); + mapping.forEach((k, v) -> { + buffer.writeUniqueId(k); + buffer.writeShort(v); + }); + } + + @Override + public void handle(Supplier context) { + context.get() + .enqueueWork(() -> { + Entity entityByID = Minecraft.getInstance().world + .getEntityByID(entityID); + if (!(entityByID instanceof ContraptionEntity)) + return; + ContraptionEntity contraptionEntity = (ContraptionEntity) entityByID; + contraptionEntity.contraption.seatMapping = mapping; + }); + context.get() + .setPacketHandled(true); + } + +} 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 ed6aac7ba..d137d9c31 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 @@ -47,10 +47,6 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe if (running && Contraption.isFrozen()) disassemble(); - if (hourHand != null) - hourHand.collisionTick(); - if (minuteHand != null) - minuteHand.collisionTick(); if (!world.isRemote && assembleNextTick) { assembleNextTick = false; 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 f5463d1ad..9a013ba7d 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 @@ -208,8 +208,6 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp if (world.isRemote) clientAngleDiff /= 2; - if (movedContraption != null) - movedContraption.collisionTick(); if (running && Contraption.isFrozen()) disassemble(); 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 4f7b006c8..928eff3c8 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 @@ -20,7 +20,6 @@ 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.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; @@ -91,13 +90,13 @@ public class MountedContraption extends Contraption { } @Override - public void removeBlocksFromWorld(IWorld world, BlockPos offset) { - super.removeBlocksFromWorld(world, offset, (pos, state) -> pos.equals(anchor)); + protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) { + return AllBlocks.MINECART_ANCHOR.has(state); } - + @Override - public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { - super.addBlocksToWorld(world, offset, rotation, (pos, state) -> AllBlocks.MINECART_ANCHOR.has(state)); + protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { + return pos.equals(anchor); } } 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 53211b904..43140fb09 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 @@ -53,7 +53,6 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme super.tick(); if (movedContraption != null) { - movedContraption.collisionTick(); if (!movedContraption.isAlive()) movedContraption = null; } 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 cff0e3afc..7af815d55 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 @@ -16,7 +16,6 @@ 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.glue.SuperGlueEntity; 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; @@ -32,7 +31,6 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.Direction; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.Vec3d; import net.minecraft.world.IWorld; import net.minecraft.world.World; import net.minecraft.world.gen.feature.template.Template.BlockInfo; @@ -174,44 +172,36 @@ public class PistonContraption extends Contraption { } @Override - public void addGlue(SuperGlueEntity entity) { - BlockPos pos = entity.getHangingPosition(); - Direction direction = entity.getFacingDirection(); - BlockPos localPos = pos.subtract(anchor) + public BlockPos toLocalPos(BlockPos globalPos) { + return globalPos.subtract(anchor) .offset(orientation, -initialExtensionProgress); - this.superglue.add(Pair.of(localPos, direction)); - glueToRemove.add(entity); } @Override - public void addBlocksToWorld(World world, BlockPos offset, Vec3d rotation) { - super.addBlocksToWorld(world, offset, rotation, (pos, state) -> { - BlockPos pistonPos = anchor.offset(orientation, -1); - BlockState pistonState = world.getBlockState(pistonPos); - TileEntity te = world.getTileEntity(pistonPos); - if (pos.equals(pistonPos)) { - if (te == null || te.isRemoved()) - return true; - if (!isExtensionPole(state) && isPiston(pistonState)) - world.setBlockState(pistonPos, pistonState.with(MechanicalPistonBlock.STATE, PistonState.RETRACTED), - 3 | 16); + protected boolean customBlockPlacement(IWorld world, BlockPos pos, BlockState state) { + BlockPos pistonPos = anchor.offset(orientation, -1); + BlockState pistonState = world.getBlockState(pistonPos); + TileEntity te = world.getTileEntity(pistonPos); + if (pos.equals(pistonPos)) { + if (te == null || te.isRemoved()) return true; - } - return false; - }); + if (!isExtensionPole(state) && isPiston(pistonState)) + world.setBlockState(pistonPos, pistonState.with(MechanicalPistonBlock.STATE, PistonState.RETRACTED), + 3 | 16); + return true; + } + return false; } @Override - public void removeBlocksFromWorld(IWorld world, BlockPos offset) { - super.removeBlocksFromWorld(world, offset, (pos, state) -> { - BlockPos pistonPos = anchor.offset(orientation, -1); - BlockState blockState = world.getBlockState(pos); - if (pos.equals(pistonPos) && isPiston(blockState)) { - world.setBlockState(pos, blockState.with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66 | 16); - return true; - } - return false; - }); + protected boolean customBlockRemoval(IWorld world, BlockPos pos, BlockState state) { + BlockPos pistonPos = anchor.offset(orientation, -1); + BlockState blockState = world.getBlockState(pos); + if (pos.equals(pistonPos) && isPiston(blockState)) { + world.setBlockState(pos, blockState.with(MechanicalPistonBlock.STATE, PistonState.MOVING), 66 | 16); + return true; + } + return false; } @Override diff --git a/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java b/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java index d7423304c..0f697c166 100644 --- a/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java +++ b/src/main/java/com/simibubi/create/foundation/collision/CollisionDebugger.java @@ -6,7 +6,6 @@ import com.simibubi.create.CreateClient; import com.simibubi.create.foundation.collision.ContinuousOBBCollider.ContinuousSeparationManifold; import com.simibubi.create.foundation.renderState.SuperRenderTypeBuffer; import com.simibubi.create.foundation.utility.AngleHelper; -import com.simibubi.create.foundation.utility.Debug; import com.simibubi.create.foundation.utility.MatrixStacker; import com.simibubi.create.foundation.utility.outliner.AABBOutline; @@ -31,7 +30,6 @@ public class CollisionDebugger { angle += delta; angle = (int) angle; OBB.setRotation(new Matrix3d().asZRotation(AngleHelper.rad(angle))); - Debug.debugMessage("Angle: " + angle); } public static void render(MatrixStack ms, SuperRenderTypeBuffer buffer) { 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 141a0499c..a8b304c24 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -6,6 +6,8 @@ import java.util.function.Supplier; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.structureMovement.CancelPlayerFallPacket; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionInteractionPacket; +import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionSeatMappingPacket; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket; import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueEffectPacket; import com.simibubi.create.content.contraptions.relays.advanced.sequencer.ConfigureSequencedGearshiftPacket; @@ -45,6 +47,7 @@ public enum AllPackets { CONFIGURE_SCROLLABLE(ScrollValueUpdatePacket.class, ScrollValueUpdatePacket::new), CANCEL_FALL(CancelPlayerFallPacket.class, CancelPlayerFallPacket::new), EXTENDO_INTERACT(ExtendoGripInteractionPacket.class, ExtendoGripInteractionPacket::new), + CONTRAPTION_INTERACT(ContraptionInteractionPacket.class, ContraptionInteractionPacket::new), PLACE_ARM(ArmPlacementPacket.class, ArmPlacementPacket::new), // Server to Client @@ -54,6 +57,7 @@ public enum AllPackets { CONFIGURE_CONFIG(ConfigureConfigPacket.class, ConfigureConfigPacket::new), CONTRAPTION_STALL(ContraptionStallPacket.class, ContraptionStallPacket::new), GLUE_EFFECT(GlueEffectPacket.class, GlueEffectPacket::new), + CONTRAPTION_SEAT_MAPPING(ContraptionSeatMappingPacket.class, ContraptionSeatMappingPacket::new), ; diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index 3852632ff..17123dd50 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -13,6 +13,10 @@ import net.minecraft.util.math.Vec3i; public class VecHelper { + public static Vec3d rotate(Vec3d vec, Vec3d rotationVec) { + return rotate(vec, rotationVec.x, rotationVec.y, rotationVec.z); + } + public static Vec3d rotate(Vec3d vec, double xRot, double yRot, double zRot) { return rotate(rotate(rotate(vec, xRot, Axis.X), yRot, Axis.Y), zRot, Axis.Z); } diff --git a/src/main/resources/assets/create/textures/block/seat/bottom.png b/src/main/resources/assets/create/textures/block/seat/bottom.png index 744293ab69cc2cf06fb87c802110e6ff03df3be2..97a2c28d03e98b2e6c3d55185c50728ae7f32810 100644 GIT binary patch delta 241 zcmdnMw25hgXMJjFYC%CkWo2b`b#;4=O-H`-tU8YcJz=Y+#;>1|xpjUH0}|MCZtia& zm$SelvY3H^?;r>>?wFYU7AV;5>Eak7ahbPwBj;fQ5tsFWf)Ho(HURow7 z|CmvyG>>VLsl$(=$;Xa-ir150XR#yeyTz9CF`IYrnSUw25#C(aWB1{BgO`?#`l0A2 zS9pF1S$dZooaAb@l7DW*YM&d|581T{TCbk>sKGT+Y1gCeb6xqa#(wlNe978wdd|(C h*Rq*y?b*;tum7d+JFNKra7_Wo?VhfFF6*2UngHc;Vm<%> delta 239 zcmdnQw1H`YXMIjVX<1!UdydVlI*$cCVXLObub+{*b$(7uXCDIwNZVv^7bwVC;1OBO zz`%DHgc*>%L6-m)O~pTg2u1tm@9?H+ITu5K-OUh8mU zvxrZLx8b{3T_&&fKKGXYuE2A9ph?olwEiGX2E5tc?OQ+g`L7 zcAeRD*EDJCrz2LX+s>6nM7}<_T|!iCkx$x4(CZEQhHRdW` ZrrZCL*W<`K)$;@7eot3Fmvv4FO#o2!Vi^Dc diff --git a/src/main/resources/assets/create/textures/block/seat/side_black.png b/src/main/resources/assets/create/textures/block/seat/side_black.png index 3dec26d414a346ea1d16bb910c49791214c0d97d..4f952499d686d6ea9992e5dfc442e9e25bd69a8b 100644 GIT binary patch delta 302 zcmV+}0nz@01N#DyR(}vlL_t(IPh6Q+>C&bDA3l7@FmKKru;A}MKxeW5T?IA-p%{i?;(tjgDGc)R@(e5*8X90l zu110k!hGCdHVnM|^cBitfXl(eK$<~%;Vv)}x&xLF;Nt?*$l$}LZ(tf(Zr1}Tup!JQ zCMFH9UcF+F<#@sHPx# delta 310 zcmV-60m=UR0)qpPR(}{tL_t(IPwi4oO9L?weTkdHZa)xFA@YWFCj}41 zi-`Y5@Z<-DcEK-}ZFg75O3chQHHas@c<{k6GjHCTgb-n^#cv>&`N#NQ@D~<{-Oh=`(A|)9!Tf0Sn`^6Zz4b2LJ#707*qo IM6N<$g2xte00VD7L2O}QXMoGS{d5mZ%gYxrfb_y$U?y}2EFr*$>U0qJ@CgzI z$a1?LNP%6zY+_>4@aoko23d|53{RfEWMKIBi{Z=X&kT3&Jz;q9@->+M=hqJ~28o04 z-~TKO=O6xI_%!q94+CRCK>;`re?B=3Hd&Yt)f?yl<}G#^TOi56001i}mW5k@3!DG| N002ovPDHLkV1hfBj4%KI delta 312 zcmV-80muG`1BC;SR(~2vL_t(IPwkRHO2a@Hg@x3WA=)y*F_q zg05V+^9UY8s2hda6t!(8O=1~+f15ChE8V#8gJIsh|GgOq@vOD@4gPZfG5;6*g$ul$ zqZ7LlY6O8sSsJ_*22m>(U3u>8Yu0y-itoxUmCvrXy?-pfVt=4oi(#IM=Fo+&RWm|O zywkG_nZdSg#cYbO*_PSi?iS)WhIf8>W%D9O^Z5qd&ZZPxihPbx zHI}CZ!_gCF8+%Zpg3mGqNzDWg{W}RzvrM@2?0W35>u1J@D8^$14UP3)4{Pm?gkGnk zdYLQ}ubdmnvN6N1A88GKgS2~q;bXrJ5e9i#waCk0AX#=It?>?eAGG2mPx#9K0000< KMNUMnLSTX^IFxb# diff --git a/src/main/resources/assets/create/textures/block/seat/side_brown.png b/src/main/resources/assets/create/textures/block/seat/side_brown.png index 87110fe8246c6eff7064972775d1211a3ebc388b..b4a7eea166e9c9c459032eae21778b809a90baaa 100644 GIT binary patch delta 312 zcmV-80muG<1BC;SR(~2vL_t(IPhuHiX&4#H8WXt5*!N94{E2JblT)@b4GHm(QOW?%aFA@Z#lbF#pf5A7Bg;2jRc} zSs2bg{KN3)&oLhc#)5(Za3KDCau{r~Fq${e0n7{RGPXdHfdK%CRFyy+qwg*N0000< KMNUMnLSTYBJdjWT delta 308 zcmV-40n7e{1AzmOR(}>rL_t(IPwi66O2a@DJu}g!8H*2++Ak2ga_3*TaIb5jU!)rm z6c_IO7#BiU3biR}Z6-}Ljy=~-4dO~SE<7;YGv{#!LX>k3zk#05ALD<)Us#|Hce>7m z3Q?$$7jLkIL%bRY_gdZin$>l|M#&^Le6`f#V;7PX6_wGHPEeoX-euKv6`eXbX z`~?HC(?3T?ptj=VX#PChsm>c`+vC4U$MEg%w+jC<(SAi z=rqF-C?<#?2vit`IKRDv$|fjtUDVbF_R3r_aZ;}qnQQK3Zx@c^z;a!ei;k`@(CbzL zAmurEtxh2rE=iw&0$O|s(tdTY-yLwlT4%m>!b@7cL7lsN*x(MDp68v#ag43@5YgiZ zcrP#+k1@E9Fg+YS^IjG?56aUhm4%y7LP`nY`#wM7EV^RnUdLQxF_N^pR%`P>&%g(K WxtJ{hM8wDd00007p4bPlwQ=aIgi-SLS-1F`|=ROEg)>`}qZ&`oL|AN1;KXPiO|Sp%^}a@v3Qw@w8lF+iL}5T{0G+n0000< KMNUMnLSTaaahQt$ diff --git a/src/main/resources/assets/create/textures/block/seat/side_gray.png b/src/main/resources/assets/create/textures/block/seat/side_gray.png index d9249a4fecc7978f926cc14096513228dc7446ed..39732edad2786b28d378015810ddbcfe8b8c6cad 100644 GIT binary patch delta 298 zcmV+_0oDG21NQ=uR(}jhL_t(IPhl z`ST|b|6<_d;{~%}V#spnYMGD)U;vwDWB?Nf>1DJwHwPz0kN~>mbUK0YuT z2Ht-93S}|C*g-@r7o+^z>wU_+QqOiUVHy?VtU z%khHY$?`T@ouaS;CdpM~N4!#@mv{`_HJEGQ@d w2jb5shruQb^CNMCXrL_t(IPwi4YOT$nUJujkZ(i;n~q2(LpHU<|au0nUjNq zxQXEA>W>hd{6MGyzX)lQG>SZPZu;t@IO*cxfy=%3+;dJsh%(0DH}IzY$M_HU3ju1o z-#5O$1mE{jmSt6Mh@wzt%el9Ct>+RJ-&dT3Vt@YVf={!zdapy({=t!n zABMO%Kf|OV?Q1q9Hyxhc6OoHyHJP6rzX!cv>s2ep;yJ=A}>A=G#92@jqCUc z+1da>(1J%Z2jV3i;qvNM1e|Fm*txqLJ@k6xQ7S``jL}>Spt~LDoH1NZ_(3`A%ng0%iglZ|U;bjun%>BWOT*v#bnW+s^sp|!?uXnn>X^FQD( z3=sQ=d)o0_xZVoNyg-$g@OmB2jb?kz+LkRCzH7EII`xX(;eQVQiqey8s$6kSrVTyK zcm(Byh~ro%NrLl>GpN@R)k48(OUPCCOEG(ObZU*flj9M5--ir>fQybc`WSROoEsiy z&mYM;mY&h5nR=IRaL^yK(d({pw0WGpaJ0S4+f5$ggkgA^Wf``;3DUbM@K)eyKF9bb z#bkQV_o~SGkTOoE(h}E6y_QlCQ55k4HL1_#=;MVd*w`S$Ae z$#nLFe0Kof^Pw1~AdB=35950=P%}(ec{h8^FsrgO6;aOTaP0`4ejhvAT`|4B&(%3NM19xGKx~`$Pu1o)U8Qsw2_A}ZLPw4F)HY@M}x)!$< T9CoWm00000NkvXXu0mjf)`gV= delta 314 zcmV-A0mc4~1BU~UR(~8xL_t(IPwkLBPQySDg`YQy?W_|>WQQDxhJu1KaRFKygcK@z zT5f_AQ4lGKlYrxY6fOG}J6a(sXefBnXl7^LHiQC{ z-$Pv%crSAV!_d@i&z^nt3cJzjJJ?p+Co9s;5}Wz6*~X~y)PLj_YO_6KkRj__-%M2; z$9UXksI#3m?cm7)++d({-@pVpE3*WCaAanuqX1D9!MVM=S5;lX-#%a*o*2MZUG3p| zo#yqa)q06?bPmt;APBRdGX3?J*^@D_CQLE&ZTHBK6-BQ9O&4{NpxcocP9`|+hsN}l zt`CtH%`Nu&J~P@&hOFpG3Em(ZUtl$#9ZVFBT-FBlx>y)5nVyvR01L6tVe8>f{{R30 M07*qoM6N<$f)>-40ssI2 diff --git a/src/main/resources/assets/create/textures/block/seat/side_light_gray.png b/src/main/resources/assets/create/textures/block/seat/side_light_gray.png index cddf833d3d0e89e63b33e942ebf7f91dea198be4..376d9763c56ef29b66054ebc0dd1201e5c248e58 100644 GIT binary patch delta 335 zcmV-V0kHm;1DpepR(~-`L_t(IPwi7NPQx%1eQuE;NmU`TAy9@2DNDDA2@b&-I~u5|x~@UfbQA>#=LJmDq*!rHt)1Ix5(?j$n^3&;c7G2BgYk2kf>mR+Dv@(e zF=KUdS*~c6rzuV5Jthfp%=0`Eh9QE<1X-Se=T)1AhMv)bq3dLpMycgFhhgZX*~1|$ z%L4O#Uj#vb>x*-keS-`NNt&-Cd}@k2Iyr-F+g}|V?o3J8?$@U_@s!qY(9|yPcBzA| z<2d6uj-g1N3s|MP2fMU~sv hXhU6LbMLtN0w0!LsnM_*r1k&+002ovPDHLkV1i;on*#s< delta 330 zcmV-Q0k!^|1D6AkR(~u>L_t(IPwkMuPQx$|#y=;b!A>MVN$CSrFthL$47@`p-h#(q zsgPh|=Pg*65mG0RN)tg#Y?D8g$z7W&LQJqQ@LATK@4nx~v2f1eH}cl;$NC@e7Y2y4 z(a0$!A*F(~2F6&#am;yJ>-N5Sy>6k^cW_s2oml^1I6R*(7Jm@Us;U~=7|w-Qnd`dZ zNMCDv&fOn=?!%M6tm~a#zZ0`4Qn^)Z8~Ky cF;Xdf0_W+%9NemBo&W#<07*qoM6N<$f)78V0{{R3 diff --git a/src/main/resources/assets/create/textures/block/seat/side_lime.png b/src/main/resources/assets/create/textures/block/seat/side_lime.png index a0c7347203dd92b794172a2a8a8b7696546849ea..ae9c2575f6d8e24d0702c5d560fdea26136e8f0e 100644 GIT binary patch delta 326 zcmV-M0lEH$1Cs-gR(~i-L_t(IPwi7nPQx%1oP5+YDX9?MA!xQaK*S2JfW%4Y5jX+2 z$Qp?yTMoblDnv?<+N70G(xyr3)WokCSqL_;VZlh_vERITvKQ7k=lBiucl|N`2mFNr z+U4~rw;T-}TSvX#qAEDtfkAs&Q@zi}I zJ<67IV3DopsI}aAHWsO`~W1NkiL=&W6V YH*M3k3f`W{b^rhX07*qoM6N<$f>pGjssI20 delta 313 zcmV-90mlB51BL^TR(~5wL_t(IPwkK~PQySDMZed73KdhYIPR=9@Mcd#q#6Dx{rf&8K2Yh2ZmyMKjjcXw385bIrBUYR`4 z@u+X1$`pl}%qT?;j%!LI{FsAXTcw)A*hPG!smsPH)#EhFDQ6#e*&i?D!JuiKN5_V7$+<<@{H400000 LNkvXXu0mjfxs8>L diff --git a/src/main/resources/assets/create/textures/block/seat/side_magenta.png b/src/main/resources/assets/create/textures/block/seat/side_magenta.png index d355e56d412b9aaff32f928d219d7ffaea2702f2..01703d91d36158f8c325822da1eec2b913bf0841 100644 GIT binary patch delta 321 zcmV-H0lxl%1C9fbR(~T&L_t(IPwi7dPJ>Vs9B3^Cm6)O%Q^S@65I5@5^g1M7pf~Uo zEIoj3b?*flBMF*HkMY0YFD%eb zk57cPX26uJo@o@Ksnv*QczWE;B?~!hhR{i>6}jLY=A}kusFk z!Y~w36k&B9qi9OWCu|Oek`^`wCWk3VUS3zQ4U@gzWDM7J(f2%$hpu+c;MnVMxB}?A z_xbXzkRWec>Z9xxQV-n&Q1;^l`=c2TZrK*AiYzZ#Rqx_JwL@kL##K+qTexAmIPGjxTvL9rZiV6$r-oNIrpAMFO(d Th5aiL00000NkvXXu0mjfJA|A+ delta 309 zcmV-50m}Z41A+sPR(}^sL_t(IPwkMwO2bePMQ>7?G>=-9r1l5=6*uC-fAK@yx)GtS z+>2jRC@vJzrWn)ay(XnRbH~0C#FcJbc;PbhX6_kCJZmj}BY#(atp5Xl;edC2c4bvJ zMAX=9D(J?s8c6SE?cLX`-yS%92e;+sWc^v0<2g^|8ojEGRDTD#+TPJ*$a*)oW1D3e z?9&9xS~p(fAm}w#=m(L&1i33JgFzU{&O1Lvk|gl%?jLMbSLnSxVi=zY&{kb-5rm!H z>r?Z^4C~_yghBHOgxOG~UgBjskpO$b6f58D85y#^(OR0iDA4UF9F0ae?8g#%UoH05 z#>i~5)siJc)-I2f0{=ldyu|!SJgL`vZU4d>5oE%P#h00000NkvXX Hu0mjfau}9F diff --git a/src/main/resources/assets/create/textures/block/seat/side_orange.png b/src/main/resources/assets/create/textures/block/seat/side_orange.png index 267ab3c3e252d57af90a76a8c77dbe8b01b4f625..9ada1ff3bff553cf7100d1932403b4ddbaadd879 100644 GIT binary patch delta 327 zcmV-N0l5By1C#@hR(~l;L_t(IPwkLFO2bePhX0pVt&NS6E-a#Co2?KOM9<*L6L^6f z!DG0W9KfwxUE2$kVjw~rshFfGHNNJV8H_wdTNgFs<~(fEPyvY4|`o@}9-=!X(gN(kTg`4OL^Yo6S-s#U*XLcdV4vVByY Zz$+jPo5^SMpZNd)002ovPDHLkV1gEHqKp6l delta 310 zcmV-60m=T91A_yQR(}{tL_t(IPwkLFO2a@Hh2KnR(oWh`ZE7we2%f=(8}R^Msv8mP zs(X*&5rnQ3YE!gHGig%d$Qw-=#g%Sc_`xtQ|9kHrh%m zpwkoBtPON-a1cwYo0;o<%}RIB@Lk!ZnX@a#=f~C!!j?7jw12jmrVC$dJVH&x`0Bm^4Qh@uGMdNMU-Rig8Ji_!4V7F?>bhUdR8 zYFI3vu-QL_@A;4{Q;=L|c$nSW05!{mH^1E(JM79rYb&ZWMZ2Z27snX%hBmZXFLy^5 zg`I6{ZL{pKD=)iBf&U;Moni4f+l2^&T-F@&GN0QlJ6)yl1}ty2S}J$%ivR!s07*qo IM6N<$g8RdkMF0Q* diff --git a/src/main/resources/assets/create/textures/block/seat/side_pink.png b/src/main/resources/assets/create/textures/block/seat/side_pink.png index cc1a19c0ea72e0a13bb0fe8f59922ce0fadc4803..b8ac240990d2eefe99c281a97db3c442d601aa2a 100644 GIT binary patch delta 331 zcmV-R0kr;<1DFGlR(~x?L_t(IPwi8?PQx%1J#H(JM~MpE5GWgpm?NgbKkyOkQNN&H zz{JL!nVl8Zhz(_^5Rrn^hIihSfT=GvL=h7#3>?e$^*Q%kKO{5GIevrIV*WAy3;cxw z>}daxYl;e0QBag6^0Gj`w?eVx>RL0mRVO6AGuI(`;cf434u3{ZX#&O=UaAUNky9+1 zKsDzC#BNd(dAASu#4*=(c@PB9E;@*d6iJ?8S<_*tUFfPtW?>XsoTV`IE@}Bz1=BRa zJkR64@8j(F0DVIzgT!5&Eh2nsk{j#|VOiGK3AR_qB=n4rUF&#^bDHbg$<-R2pl#ds zD2gI%C=-O&Q$*lxhBQeqz6>#$-q5<5mDB|<`YZ3?JgDe>nBzF~pP$21s@%Lr6Y>g6 d>pSxicn5s6s(cCXi);V@002ovPDHLkV1fkDoBsd+ delta 327 zcmV-N0l5B{1C#@hR(~l;L_t(IPwkLRPQx%1gvSXqi4#hzr1S>txB=n>EVu;s;1Dd3 z5JG|#dv3xOsVk65Q%dt=CvB?0n5K#lE7-7LEX&XH=6jYb>bk~nWUbF1>wmys7$7cB z&ui&=@LU(VD4+_Bu-7+r z@wKMMTs(U_#eo}udprk5RTA&Mf1>)X4! zT$FHU_ZWnG254(huF!Gp_3cxW=?jYfF`SMAi!ci+S1F!Gk0!vHFvXMiwnv7nrIj+p zB1y1qOZ0|A>_7&g3C*+VW-G0Yw_GWcB}3Noqy+yUADm$FJlcdP205(R)Z2J$vSd6d Z@eck#!pEOb2^#T!-X^w|{+pG8`>dG2aC!w3`0HCz{-A iJfjKuEcNt?pTGxR@uQJ4vDR(?0000L_t(IPwkLFPK7WKhJPRrq>!iqxO}vW>P2NhAC%pJXTBH>#Q(g@*u5{zVKPfYv`M+tYqqW9ww5_N04~9lkhplk{q)WlC?}Xik@n*nF~qu! z5GIjTg^9djoZvX%Q diff --git a/src/main/resources/assets/create/textures/block/seat/side_red.png b/src/main/resources/assets/create/textures/block/seat/side_red.png index f275d37ea82d2c6defeae5fa54969ba2c4f3e1ee..c21eb5131dc84170beeae01654981cb1d89d0141 100644 GIT binary patch delta 322 zcmV-I0lof%1CIlcR(~W(L_t(IPwi7NPQySDob%ZPLJ}d;A&?6iKfq9dM8yyIho8U; z_=PKekQRC#K!mVlq{Ijb#U_E{&WCq{(Fq|6XebzIJ$ExZtG&X)T8rPnd*>hHf52ZD zAkOxVY}d0`lQkB`!@L$428PeA=6audJy&S)RoF$VQ`Re#K!3K7JdLW-U~WS#yB-x~ zC@a!5wON)ypN~))gX-0w7fAG_M9=3e2gxgyMt{X;&p$av7>4kpDB`Be-4esWIyzXU z6lz@0p7=~ydI269t!nNEO_;JD8|-h6xp8CAWp?p6n=`xK=yr=YkZ~NJ7Da)b)d}*u zDNrj^Wr^`kjyuWpp6^;cbCFJEtdFZqLu(C@Bnkh|FZl&erd7WKJ%P~KK5V|g8!9ZN Ufv8mIBWOT3^V)B|IJ~AwHCjT-1Hyo|G-~3AkGhuY$7dU z)uA>Lx)aC(!?W}J-Pf%24X5v5U(P31PFjJdTJbfiY6b2Na(~_5Q4vF|xVXHwMNy!; zy+>&bs-;01DD;&=+GCbM+Li4J{jkS7d3J(4&mpdE?rhUG*m-@xAUjwSp4!GBjMV0} z)^s+($Nn**FoGnQ2GT;8cpg1+fM$Y8)amVe#1JcMt$AqYa|9~E-f)QBG~>{FHQSc1 zYxb5#bCwulWiOm0pg&j)PBDEMZ9^mq(lJ-0xAB;>#KcL0Pv(@s`hc6F4FCWD07*qo IM6N<$fk=)#GI!DP!rMO|jen-D>q661lx2x5%fJ|` zqbaVclCn6h)kK}}_`VP3I1cwb4`C2MQ52+UN?A0NWtq&v7{>|XB!Q-?RC8h&FijH! z%d)7*f4BuJWT;|O0Le2jk2BH)bWO%Vomb0-Gsj~H@5cleM>7%*HHmT;FL84RUF~ju zN)z;L+nz>IgiN#j1%js#c-tVYN1eF=7U7ci)ux~jyofCy;L)q<`>DVtlL@`&*WjKy li&4MBYWG`v#%28l-T}U3s3Mal{W<^u002ovPDHLkV1gb4qI3WN delta 323 zcmV-J0lfa81CRrdR(~Z)L_t(IPwkLRPQx$|g`X3pANuJj?SOLI`NBQGeGp_x)n6R+=k)ZJ1Fm z%To5l)%C5(vJ8%{Q4}SrszMM1h@ud_?=wsw&5E)_6ox$0j*lcsAa3sNP208Dd40e% zK44(1u3cl|+MCm-(&Y=@_fOzXTv!BCL#kDYr}-lXs3(|2mCj?27-Fra{|{=qqJU#d z?9FD_4Pp-E)jV>$RnxGi*NU^m5Nmn;OVS(E(^I6+^KFPkLAq?%q_@R_v&48(;sYu% V!qm3=xkvy2002ovPDHLkV1gPqo$LSr diff --git a/src/main/resources/assets/create/textures/block/seat/side_yellow.png b/src/main/resources/assets/create/textures/block/seat/side_yellow.png index d25d7af9e163cd23ca2145fbf7c2ca770bbd1cfa..6e992a4bf3d02073c534947f4425d3e45addfb9b 100644 GIT binary patch delta 327 zcmV-N0l5By1C#@hR(~l;L_t(IPwh}aO2a@DeMzgf4T&*=h$z|S06{_Q8N5mk;KI8| z4&c_UuJr<;7>t^xRGOqIHJx^x`4|~QThheoSEQ8W3CN(U3oxGRbQ@E~+w&!`&baTtFZ5e>w zMK1376c|5M%biyGBK`nh2JCaQWzt@EC3v{{-4HM)pUYF?hUA>D=FA)R*oZHD%6=i|e%RPpJkp^s)MGe>c zIAj#Ap0PbXhv#|_gxOGOmS8cT=>U7e6f58Mj0{V*mgE