diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java index ad5dcdacb..1ed3751e3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/BezierConnection.java @@ -298,18 +298,26 @@ public class BezierConnection implements Iterable { public void addItemsToPlayer(Player player) { Inventory inv = player.getInventory(); - int tracks = (getSegmentCount() + 1) / 2; + int tracks = getTrackItemCost(); while (tracks > 0) { inv.placeItemBackInInventory(AllBlocks.TRACK.asStack(Math.min(64, tracks))); tracks -= 64; } - int girders = hasGirder ? ((getSegmentCount() + 1) / 2) * 2 : 0; + int girders = getGirderItemCost(); while (girders > 0) { inv.placeItemBackInInventory(AllBlocks.METAL_GIRDER.asStack(Math.min(64, girders))); girders -= 64; } } + public int getGirderItemCost() { + return hasGirder ? getTrackItemCost() * 2 : 0; + } + + public int getTrackItemCost() { + return (getSegmentCount() + 1) / 2; + } + public void spawnItems(Level level) { if (!level.getGameRules() .getBoolean(GameRules.RULE_DOBLOCKDROPS)) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java index 35a630b47..d5e3affe0 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackEdge.java @@ -52,6 +52,16 @@ public class TrackEdge { .normalize(); } + public Vec3 getDirectionAt(double t) { + double length = getLength(); + double step = .5f / length; + t /= length; + Vec3 ahead = getPosition(Math.min(1, t + step)); + Vec3 behind = getPosition(Math.max(0, t - step)); + return ahead.subtract(behind) + .normalize(); + } + public boolean canTravelTo(TrackEdge other) { if (isInterDimensional() || other.isInterDimensional()) return true; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java index 82c5ec27d..fe237c7ca 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java @@ -8,6 +8,7 @@ import javax.annotation.Nullable; import com.jozufozu.flywheel.core.PartialModel; import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.Create; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.trains.DimensionPalette; import com.simibubi.create.content.logistics.trains.GraphLocation; import com.simibubi.create.content.logistics.trains.ITrackBlock; @@ -18,11 +19,13 @@ import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SingleTileEdgePoint; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; +import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.foundation.render.CachedBufferer; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType; import com.simibubi.create.foundation.utility.Iterate; +import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; @@ -32,6 +35,7 @@ import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; +import net.minecraft.nbt.Tag; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; @@ -49,6 +53,9 @@ public class TrackTargetingBehaviour extends TileEntit private AxisDirection targetDirection; private UUID id; + private Vec3 prevDirection; + private Vec3 rotatedDirection; + private CompoundTag migrationData; private EdgePointType edgePointType; private T edgePoint; @@ -64,12 +71,21 @@ public class TrackTargetingBehaviour extends TileEntit orthogonal = false; } + @Override + public boolean isSafeNBT() { + return true; + } + @Override public void write(CompoundTag nbt, boolean clientPacket) { nbt.putUUID("Id", id); nbt.put("TargetTrack", NbtUtils.writeBlockPos(targetTrack)); nbt.putBoolean("Ortho", orthogonal); nbt.putBoolean("TargetDirection", targetDirection == AxisDirection.POSITIVE); + if (rotatedDirection != null) + nbt.put("RotatedAxis", VecHelper.writeNBT(rotatedDirection)); + if (prevDirection != null) + nbt.put("PrevAxis", VecHelper.writeNBT(prevDirection)); if (migrationData != null && !clientPacket) nbt.put("Migrate", migrationData); if (targetBezier != null) { @@ -84,10 +100,14 @@ public class TrackTargetingBehaviour extends TileEntit @Override public void read(CompoundTag nbt, boolean clientPacket) { - id = nbt.getUUID("Id"); + id = nbt.contains("Id") ? nbt.getUUID("Id") : UUID.randomUUID(); targetTrack = NbtUtils.readBlockPos(nbt.getCompound("TargetTrack")); targetDirection = nbt.getBoolean("TargetDirection") ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE; orthogonal = nbt.getBoolean("Ortho"); + if (nbt.contains("PrevAxis")) + prevDirection = VecHelper.readNBT(nbt.getList("PrevAxis", Tag.TAG_DOUBLE)); + if (nbt.contains("RotatedAxis")) + rotatedDirection = VecHelper.readNBT(nbt.getList("RotatedAxis", Tag.TAG_DOUBLE)); if (nbt.contains("Migrate")) migrationData = nbt.getCompound("Migrate"); if (clientPacket) @@ -144,12 +164,26 @@ public class TrackTargetingBehaviour extends TileEntit TrackNode node2 = graph.locateNode(loc.edge.getSecond()); TrackEdge edge = graph.getConnectionsFrom(node1) .get(node2); - - boolean front = getTargetDirection() == AxisDirection.POSITIVE; - if (edge == null) return null; + T point = edgePointType.create(); + boolean front = getTargetDirection() == AxisDirection.POSITIVE; + + prevDirection = edge.getDirectionAt(loc.position) + .scale(front ? -1 : 1); + + if (rotatedDirection != null) { + double dot = prevDirection.dot(rotatedDirection); + if (dot < -.85f) { + rotatedDirection = null; + targetDirection = targetDirection.opposite(); + return null; + } + + rotatedDirection = null; + } + double length = edge.getLength(); CompoundTag data = migrationData; migrationData = null; @@ -183,13 +217,11 @@ public class TrackTargetingBehaviour extends TileEntit } } - T point = edgePointType.create(); - boolean reverseEdge = front || point instanceof SingleTileEdgePoint; - if (data != null) point.read(data, true, DimensionPalette.read(data)); point.setId(id); + boolean reverseEdge = front || point instanceof SingleTileEdgePoint; point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position); point.tileAdded(tileEntity, front); loc.graph.addPoint(edgePointType, point); @@ -262,6 +294,8 @@ public class TrackTargetingBehaviour extends TileEntit public static void render(LevelAccessor level, BlockPos pos, AxisDirection direction, BezierTrackPointLocation bezier, PoseStack ms, MultiBufferSource buffer, int light, int overlay, RenderedTrackOverlayType type, float scale) { + if (level instanceof SchematicWorld) + return; BlockState trackState = level.getBlockState(pos); Block block = trackState.getBlock(); @@ -284,4 +318,16 @@ public class TrackTargetingBehaviour extends TileEntit ms.popPose(); } + public void transform(StructureTransform transform) { + id = UUID.randomUUID(); + targetTrack = transform.applyWithoutOffset(targetTrack); + if (prevDirection != null) + rotatedDirection = transform.applyWithoutOffsetUncentered(prevDirection); + if (targetBezier != null) + targetBezier = new BezierTrackPointLocation(transform.applyWithoutOffset(targetBezier.curveTarget() + .subtract(getPos())) + .offset(getPos()), targetBezier.segment()); + tileEntity.notifyUpdate(); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java index b50772f23..f73576cc7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java @@ -4,6 +4,8 @@ import java.util.List; import javax.annotation.Nullable; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; @@ -19,7 +21,7 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; import net.minecraft.world.ticks.TickPriority; -public class SignalTileEntity extends SmartTileEntity { +public class SignalTileEntity extends SmartTileEntity implements ITransformableTE { public static enum OverlayState { RENDER, SKIP, DUAL @@ -153,4 +155,9 @@ public class SignalTileEntity extends SmartTileEntity { return new AABB(worldPosition, edgePoint.getGlobalPosition()).inflate(2); } + @Override + public void transform(StructureTransform transform) { + edgePoint.transform(transform); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java index 09c4bb339..32ea101f7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java @@ -17,6 +17,8 @@ import com.simibubi.create.AllItems; import com.simibubi.create.AllSoundEvents; import com.simibubi.create.Create; import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException; +import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.block.depot.DepotBehaviour; import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock; @@ -71,7 +73,7 @@ import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.network.PacketDistributor; -public class StationTileEntity extends SmartTileEntity { +public class StationTileEntity extends SmartTileEntity implements ITransformableTE { public TrackTargetingBehaviour edgePoint; public LerpedFloat flag; @@ -700,4 +702,9 @@ public class StationTileEntity extends SmartTileEntity { return true; } + @Override + public void transform(StructureTransform transform) { + edgePoint.transform(transform); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java index e12eec574..085a2dfaa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java @@ -36,6 +36,9 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation.Discovered import com.simibubi.create.content.logistics.trains.TrackPropagator; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity; +import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement; +import com.simibubi.create.content.schematics.ItemRequirement; +import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType; import com.simibubi.create.foundation.block.render.DestroyProgressRenderingHandler; import com.simibubi.create.foundation.block.render.ReducedDestroyEffects; import com.simibubi.create.foundation.utility.AngleHelper; @@ -61,6 +64,7 @@ import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockGetter; @@ -94,7 +98,7 @@ import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.client.IBlockRenderProperties; -public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrackBlock { +public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement { public static final EnumProperty SHAPE = EnumProperty.create("shape", TrackShape.class); public static final BooleanProperty HAS_TE = BooleanProperty.create("turn"); @@ -688,6 +692,33 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac && state1.setValue(HAS_TE, false) == state2.setValue(HAS_TE, false); } + @Override + public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) { + int trackAmount = 1; + int girderAmount = 0; + + if (te instanceof TrackTileEntity track) { + for (BezierConnection bezierConnection : track.getConnections().values()) { + if (!bezierConnection.isPrimary()) + continue; + trackAmount += bezierConnection.getTrackItemCost(); + girderAmount += bezierConnection.getGirderItemCost(); + } + } + + List stacks = new ArrayList<>(); + while (trackAmount > 0) { + stacks.add(AllBlocks.TRACK.asStack(Math.min(trackAmount, 64))); + trackAmount -= 64; + } + while (girderAmount > 0) { + stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64))); + girderAmount -= 64; + } + + return new ItemRequirement(ItemUseType.CONSUME, stacks); + } + public static class RenderProperties extends ReducedDestroyEffects implements DestroyProgressRenderingHandler { @Override public boolean renderDestroyProgress(ClientLevel level, LevelRenderer renderer, int breakerId, BlockPos pos, diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java index dad78d407..9226bd6a5 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackTileEntity.java @@ -12,12 +12,14 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.logistics.trains.BezierConnection; +import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.TrackNodeLocation; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.tileEntity.IMergeableTE; import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; +import com.simibubi.create.foundation.utility.Debug; import com.simibubi.create.foundation.utility.Pair; import net.minecraft.core.BlockPos; @@ -69,15 +71,34 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE private void validateConnections() { Set invalid = new HashSet<>(); + for (Entry entry : connections.entrySet()) { BlockPos key = entry.getKey(); BezierConnection bc = entry.getValue(); - if (key.equals(bc.getKey()) && worldPosition.equals(bc.tePositions.getFirst())) { - BlockEntity blockEntity = level.getBlockEntity(key); - if (blockEntity instanceof TrackTileEntity trackTE && trackTE.connections.containsKey(worldPosition)) - continue; + + if (!key.equals(bc.getKey()) || !worldPosition.equals(bc.tePositions.getFirst())) { + invalid.add(key); + continue; } - invalid.add(key); + + BlockState blockState = level.getBlockState(key); + if (blockState.getBlock()instanceof ITrackBlock trackBlock && !blockState.getValue(TrackBlock.HAS_TE)) + for (Vec3 v : trackBlock.getTrackAxes(level, key, blockState)) { + Vec3 bcEndAxis = bc.axes.getSecond(); + if (v.distanceTo(bcEndAxis) < 1 / 1024f || v.distanceTo(bcEndAxis.scale(-1)) < 1 / 1024f) + level.setBlock(key, blockState.setValue(TrackBlock.HAS_TE, true), 3); + else + Debug.debugChat(v + " != " + bcEndAxis); + } + + BlockEntity blockEntity = level.getBlockEntity(key); + if (!(blockEntity instanceof TrackTileEntity trackTE) || blockEntity.isRemoved()) { + invalid.add(key); + continue; + } + + if (!trackTE.connections.containsKey(worldPosition)) + trackTE.addConnection(bc.secondary()); } connectionsValidated = true; @@ -125,20 +146,29 @@ public class TrackTileEntity extends SmartTileEntity implements ITransformableTE setChanged(); } + @Override + public void writeSafe(CompoundTag tag, boolean clientPacket) { + super.writeSafe(tag, clientPacket); + writeTurns(tag); + } + @Override protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); + writeTurns(tag); + if (boundLocation == null) + return; + tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond())); + tag.putString("BoundDimension", boundLocation.getFirst() + .location() + .toString()); + } + + private void writeTurns(CompoundTag tag) { ListTag listTag = new ListTag(); for (BezierConnection bezierConnection : connections.values()) listTag.add(bezierConnection.write(worldPosition)); tag.put("Connections", listTag); - - if (boundLocation != null) { - tag.put("BoundLocation", NbtUtils.writeBlockPos(boundLocation.getSecond())); - tag.putString("BoundDimension", boundLocation.getFirst() - .location() - .toString()); - } } @Override