diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index 85a41614a..fc1657113 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -114,8 +114,9 @@ public class AllBlockPartials { TRACK_SEGMENT_LEFT = block("track/segment_left"), TRACK_SEGMENT_RIGHT = block("track/segment_right"), TRACK_TIE = block("track/tie"), - GIRDER_SEGMENT = block("metal_girder/segment"), - GIRDER_SEGMENT_2 = block("metal_girder/segment2"), + GIRDER_SEGMENT_TOP = block("metal_girder/segment_top"), + GIRDER_SEGMENT_MIDDLE = block("metal_girder/segment_middle"), + GIRDER_SEGMENT_BOTTOM = block("metal_girder/segment_bottom"), TRACK_STATION_OVERLAY = block("track/station_overlay"), TRACK_STATION_OVERLAY_DIAGONAL = block("track/station_overlay_diagonal"), diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java index 0dfb6df4c..1fd7d9b89 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/StructureTransform.java @@ -40,11 +40,11 @@ import net.minecraft.world.phys.Vec3; public class StructureTransform { // Assuming structures cannot be rotated around multiple axes at once - Rotation rotation; - int angle; - Axis rotationAxis; - BlockPos offset; - Mirror mirror; + public Axis rotationAxis; + public BlockPos offset; + public int angle; + public Rotation rotation; + public Mirror mirror; private StructureTransform(BlockPos offset, int angle, Axis axis, Rotation rotation, Mirror mirror) { this.offset = offset; @@ -88,6 +88,15 @@ public class StructureTransform { mirror = Mirror.NONE; } + public Vec3 applyWithoutOffsetUncentered(Vec3 localVec) { + Vec3 vec = localVec; + if (mirror != null) + vec = VecHelper.mirror(vec, mirror); + if (rotationAxis != null) + vec = VecHelper.rotate(vec, angle, rotationAxis); + return vec; + } + public Vec3 applyWithoutOffset(Vec3 localVec) { Vec3 vec = localVec; if (mirror != null) diff --git a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java index aeda1b98d..b03889b02 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/relays/elementary/BracketedTileEntityBehaviour.java @@ -55,6 +55,11 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour { this.bracket = Optional.of(state); reRender = true; tileEntity.notifyUpdate(); + Level world = getWorld(); + if (world.isClientSide) + return; + tileEntity.getBlockState() + .updateNeighbourShapes(world, getPos(), 3); } public void transformBracket(StructureTransform transform) { @@ -71,10 +76,15 @@ public class BracketedTileEntityBehaviour extends TileEntityBehaviour { world.levelEvent(2001, getPos(), Block.getId(getBracket())); this.bracket = Optional.empty(); reRender = true; - if (inOnReplacedContext) + if (inOnReplacedContext) { tileEntity.sendData(); - else - tileEntity.notifyUpdate(); + return; + } + tileEntity.notifyUpdate(); + if (world.isClientSide) + return; + tileEntity.getBlockState() + .updateNeighbourShapes(world, getPos(), 3); } public boolean isBracketPresent() { diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java index 4b6c6d86e..a2f23ca39 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java +++ b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderBlock.java @@ -2,6 +2,8 @@ package com.simibubi.create.content.curiosities.girder; import static net.minecraft.world.level.block.state.properties.BlockStateProperties.WATERLOGGED; +import java.util.Random; + import com.simibubi.create.AllBlocks; import com.simibubi.create.AllShapes; import com.simibubi.create.content.contraptions.base.KineticTileEntity; @@ -10,7 +12,7 @@ import com.simibubi.create.content.contraptions.relays.elementary.BracketedTileE import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.content.logistics.block.chute.AbstractChuteBlock; import com.simibubi.create.content.logistics.trains.track.TrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape; +import com.simibubi.create.content.logistics.trains.track.TrackShape; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.placement.IPlacementHelper; @@ -19,6 +21,7 @@ import com.simibubi.create.foundation.utility.placement.PlacementHelpers; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Direction.Axis; +import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; @@ -107,6 +110,12 @@ public class GirderBlock extends Block implements SimpleWaterloggedBlock, IWrenc return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : Fluids.EMPTY.defaultFluidState(); } + @Override + public void tick(BlockState p_60462_, ServerLevel p_60463_, BlockPos p_60464_, Random p_60465_) { + Block.updateOrDestroy(p_60462_, Block.updateFromNeighbourShapes(p_60462_, p_60463_, p_60464_), p_60463_, + p_60464_, 3); + } + @Override public BlockState updateShape(BlockState state, Direction direction, BlockState neighbourState, LevelAccessor world, BlockPos pos, BlockPos neighbourPos) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java index f3e5b1694..f0d0c9b51 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java +++ b/src/main/java/com/simibubi/create/content/curiosities/girder/GirderPlacementHelper.java @@ -17,6 +17,7 @@ import net.minecraft.world.entity.ai.attributes.AttributeInstance; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraftforge.common.ForgeMod; @@ -94,7 +95,8 @@ public class GirderPlacementHelper implements IPlacementHelper { .isReplaceable()) continue; - return PlacementOffset.success(newPos, bState -> withAxis(bState, dir.getAxis())); + return PlacementOffset.success(newPos, + bState -> Block.updateFromNeighbourShapes(withAxis(bState, dir.getAxis()), world, newPos)); } return PlacementOffset.fail(); 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 621c7dd43..75f7b73f5 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 @@ -4,7 +4,7 @@ import java.util.Iterator; import com.jozufozu.flywheel.repack.joml.Math; import com.jozufozu.flywheel.util.transform.MatrixTransformStack; -import com.mojang.math.Matrix4f; +import com.mojang.blaze3d.vertex.PoseStack.Pose; import com.simibubi.create.content.logistics.trains.track.TrackRenderer; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; @@ -24,7 +24,6 @@ import net.minecraftforge.api.distmarker.OnlyIn; public class BezierConnection implements Iterable { public Couple tePositions; - public Couple trackEnds; public Couple starts; public Couple axes; public Couple normals; @@ -44,37 +43,37 @@ public class BezierConnection implements Iterable { private double handleLength; public BezierConnection(Couple positions, Couple starts, Couple axes, Couple normals, - Couple targets, boolean primary, boolean girder) { + boolean primary, boolean girder) { tePositions = positions; this.starts = starts; this.axes = axes; this.normals = normals; - this.trackEnds = targets; this.primary = primary; this.hasGirder = girder; resolved = false; } public BezierConnection secondary() { - return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), trackEnds.swap(), - false, hasGirder); + return new BezierConnection(tePositions.swap(), starts.swap(), axes.swap(), normals.swap(), false, hasGirder); } - public BezierConnection(CompoundTag compound) { - this(Couple.deserializeEach(compound.getList("Positions", Tag.TAG_COMPOUND), NbtUtils::readBlockPos), - Couple.deserializeEach(compound.getList("Starts", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), + public BezierConnection(CompoundTag compound, BlockPos localTo) { + this(Couple.deserializeEach(compound.getList("Positions", Tag.TAG_COMPOUND), NbtUtils::readBlockPos) + .map(b -> b.offset(localTo)), + Couple.deserializeEach(compound.getList("Starts", Tag.TAG_COMPOUND), VecHelper::readNBTCompound) + .map(v -> v.add(Vec3.atLowerCornerOf(localTo))), Couple.deserializeEach(compound.getList("Axes", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), Couple.deserializeEach(compound.getList("Normals", Tag.TAG_COMPOUND), VecHelper::readNBTCompound), - Couple.create(compound.getBoolean("TrackEnd1"), compound.getBoolean("TrackEnd2")), compound.getBoolean("Primary"), compound.getBoolean("Girder")); } - public CompoundTag write() { + public CompoundTag write(BlockPos localTo) { + Couple tePositions = this.tePositions.map(b -> b.subtract(localTo)); + Couple starts = this.starts.map(v -> v.subtract(Vec3.atLowerCornerOf(localTo))); + CompoundTag compound = new CompoundTag(); compound.putBoolean("Girder", hasGirder); compound.putBoolean("Primary", primary); - compound.putBoolean("TrackEnd1", trackEnds.getFirst()); - compound.putBoolean("TrackEnd2", trackEnds.getSecond()); compound.put("Positions", tePositions.serializeEach(NbtUtils::writeBlockPos)); compound.put("Starts", starts.serializeEach(VecHelper::writeNBTCompound)); compound.put("Axes", axes.serializeEach(VecHelper::writeNBTCompound)); @@ -85,7 +84,7 @@ public class BezierConnection implements Iterable { public BezierConnection(FriendlyByteBuf buffer) { this(Couple.create(buffer::readBlockPos), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), Couple.create(() -> VecHelper.read(buffer)), - Couple.create(buffer::readBoolean), buffer.readBoolean(), buffer.readBoolean()); + buffer.readBoolean(), buffer.readBoolean()); } public void write(FriendlyByteBuf buffer) { @@ -93,7 +92,6 @@ public class BezierConnection implements Iterable { starts.forEach(v -> VecHelper.write(v, buffer)); axes.forEach(v -> VecHelper.write(v, buffer)); normals.forEach(v -> VecHelper.write(v, buffer)); - trackEnds.forEach(buffer::writeBoolean); buffer.writeBoolean(primary); buffer.writeBoolean(hasGirder); } @@ -344,8 +342,8 @@ public class BezierConnection implements Iterable { @OnlyIn(Dist.CLIENT) public static class SegmentAngles { - public Matrix4f tieTransform; - public Couple railTransforms; + public Pose tieTransform; + public Couple railTransforms; public BlockPos lightPosition; } @@ -353,8 +351,8 @@ public class BezierConnection implements Iterable { @OnlyIn(Dist.CLIENT) public static class GirderAngles { - public Couple beams; - public Couple> beamCaps; + public Couple beams; + public Couple> beamCaps; public BlockPos lightPosition; } @@ -398,8 +396,7 @@ public class BezierConnection implements Iterable { .rotateZRadians(tieAngles.z) .translate(-1 / 2f, -2 / 16f - 1 / 256f, 0); angles.tieTransform = mts.unwrap() - .last() - .pose(); + .last(); angles.railTransforms = Couple.create(null, null); // Rails @@ -418,8 +415,7 @@ public class BezierConnection implements Iterable { .translate(0, -2 / 16f + (i % 2 == 0 ? 1 : -1) / 2048f - 1 / 256f, -1 / 32f) .scale(1, 1, (float) diff.length() * scale); angles.railTransforms.set(first, mts.unwrap() - .last() - .pose()); + .last()); } previousOffsets = railOffsets; @@ -494,8 +490,7 @@ public class BezierConnection implements Iterable { .translate(0, 2 / 16f + (segment.index % 2 == 0 ? 1 : -1) / 2048f - 1 / 1024f, -1 / 32f) .scale(1, 1, (float) beamDiff.length() * scale); angles.beams.set(first, mts.unwrap() - .last() - .pose()); + .last()); // Caps for (boolean top : Iterate.trueAndFalse) { @@ -516,8 +511,7 @@ public class BezierConnection implements Iterable { .scale(1, 1, (float) diff.length() * scale); angles.beamCaps.get(top) .set(first, mts.unwrap() - .last() - .pose()); + .last()); } } 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 b1044d578..b35900cb1 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 @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains; import com.simibubi.create.foundation.utility.VecHelper; +import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.util.Mth; @@ -60,11 +61,11 @@ public class TrackEdge { } public CompoundTag write() { - return isTurn() ? turn.write() : new CompoundTag(); + return isTurn() ? turn.write(BlockPos.ZERO) : new CompoundTag(); } public static TrackEdge read(CompoundTag tag) { - return new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag) : null); + return new TrackEdge(tag.contains("Positions") ? new BezierConnection(tag, BlockPos.ZERO) : null); } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java index d6a7e9d96..c17283c52 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraphHelper.java @@ -26,7 +26,7 @@ public class TrackGraphHelper { double length = axis.length(); List> ends = - TrackPropagator.getEnds(level, pos, trackBlockState, null, true); + TrackPropagator.getEnds(level, pos, trackBlockState, true, null, null); TrackGraph graph = null; TrackNode frontNode = null; @@ -46,7 +46,7 @@ public class TrackGraphHelper { for (int i = 0; i < 32; i++) { DiscoveredLocation loc = current; List> list = - TrackPropagator.getEnds(level, currentPos, level.getBlockState(currentPos), current, true); + TrackPropagator.getEnds(level, currentPos, level.getBlockState(currentPos), true, current, null); if (!list.isEmpty()) { currentPos = list.get(0) .getFirst(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index f7865ca83..95804463c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -13,7 +13,7 @@ import javax.annotation.Nullable; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation; import com.simibubi.create.content.logistics.trains.track.TrackBlock; -import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape; +import com.simibubi.create.content.logistics.trains.track.TrackShape; import com.simibubi.create.content.logistics.trains.track.TrackTileEntity; import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.VecHelper; @@ -47,11 +47,10 @@ public class TrackPropagator { currentPos = pos; currentNode = location; } - } public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) { - List> ends = getEnds(reader, pos, state, null, false); + List> ends = getEnds(reader, pos, state, false, null, null); TrackGraph foundGraph = null; GlobalRailwayManager manager = Create.RAILWAYS; TrackGraphSync sync = manager.sync; @@ -78,9 +77,16 @@ public class TrackPropagator { for (Pair removedEnd : ends) { BlockPos adjPos = removedEnd.getFirst(); BlockState adjState = reader.getBlockState(adjPos); - - if (!getEnds(reader, adjPos, adjState, removedEnd.getSecond(), true).isEmpty()) - toUpdate.add(onRailAdded(reader, adjPos, adjState)); + List> adjEnds = + getEnds(reader, adjPos, adjState, true, removedEnd.getSecond(), null); + if (adjEnds.isEmpty()) + continue; + Vec3 filter = adjEnds.get(0) + .getSecond() + .getLocation() + .subtract(removedEnd.getSecond() + .getLocation()); + toUpdate.add(onRailAdded(reader, adjPos, adjState, filter.normalize())); } for (TrackGraph railGraph : toUpdate) @@ -89,7 +95,7 @@ public class TrackPropagator { manager.markTracksDirty(); } - public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) { + public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state, Vec3 axisFilter) { // 1. Remove all immediately reachable node locations GlobalRailwayManager manager = Create.RAILWAYS; @@ -97,7 +103,7 @@ public class TrackPropagator { List frontier = new ArrayList<>(); Set visited = new HashSet<>(); Set connectedGraphs = new HashSet<>(); - addInitialEndsOf(reader, pos, state, frontier, false); + addInitialEndsOf(reader, pos, state, frontier, false, axisFilter); int emergencyExit = 1000; while (!frontier.isEmpty()) { @@ -155,7 +161,7 @@ public class TrackPropagator { // 2. Find the first graph node candidate nearby - addInitialEndsOf(reader, pos, state, frontier, true); + addInitialEndsOf(reader, pos, state, frontier, true, axisFilter); emergencyExit = 1000; while (!frontier.isEmpty()) { @@ -229,8 +235,8 @@ public class TrackPropagator { } private static void addInitialEndsOf(LevelAccessor reader, BlockPos pos, BlockState state, - List frontier, boolean ignoreTurns) { - for (Pair initial : getEnds(reader, pos, state, null, ignoreTurns)) + List frontier, boolean ignoreTurns, Vec3 axisFilter) { + for (Pair initial : getEnds(reader, pos, state, ignoreTurns, null, axisFilter)) frontier.add(new FrontierEntry(initial.getFirst(), pos, initial.getSecond())); } @@ -255,13 +261,13 @@ public class TrackPropagator { } for (Pair pair : getEnds(reader, prevPos, reader.getBlockState(prevPos), - entry.currentNode, false)) + false, entry.currentNode, null)) if (!pair.getSecond() .equals(entry.prevNode)) ends.add(pair); } - ends.addAll(getEnds(reader, entry.currentPos, currentState, entry.currentNode, false)); + ends.addAll(getEnds(reader, entry.currentPos, currentState, false, entry.currentNode, null)); return ends; } @@ -304,7 +310,7 @@ public class TrackPropagator { // TODO ITrackBlock public static List> getEnds(LevelReader reader, BlockPos pos, BlockState state, - @Nullable DiscoveredLocation fromEnd, boolean ignoreTurns) { + boolean ignoreTurns, @Nullable DiscoveredLocation fromEnd, @Nullable Vec3 axisFilter) { Vec3 center = VecHelper.getCenterOf(pos); List> list = new ArrayList<>(); @@ -315,21 +321,36 @@ public class TrackPropagator { if (state.getValue(TrackBlock.HAS_TURN) && blockEntity instanceof TrackTileEntity && !ignoreTurns) { TrackTileEntity trackTileEntity = (TrackTileEntity) blockEntity; trackTileEntity.getConnections() - .forEach(map -> map.forEach((connectedPos, bc) -> addToSet(fromEnd, list, - (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, - bc))); + .forEach((connectedPos, bc) -> { + Vec3 curveHandle = bc.axes.getFirst(); + if (axisFilter != null && !testAxisFilter(curveHandle.normalize(), axisFilter)) + return; + addToSet(fromEnd, list, + (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), + bc.normals::get, bc); + }); } TrackShape shape = state.getValue(TrackBlock.SHAPE); - if (shape != TrackShape.NONE) - shape.getAxes() - .forEach(axis -> addToSet(fromEnd, list, (d, b) -> axis.scale(b ? d : -d) + if (shape == TrackShape.NONE) + return list; + + shape.getAxes() + .forEach(axis -> { + if (axisFilter != null && !testAxisFilter(axis.normalize(), axisFilter)) + return; + addToSet(fromEnd, list, (d, b) -> axis.scale(b ? d : -d) .add(center) - .add(0, axis.y == 0 ? -.5 : 0, 0), b -> shape.getNormal(), null)); + .add(0, axis.y == 0 ? -.5 : 0, 0), b -> shape.getNormal(), null); + }); return list; } + private static boolean testAxisFilter(Vec3 axis, Vec3 filter) { + return Mth.equal(axis.distanceToSqr(filter), 0) || Mth.equal(axis.distanceToSqr(filter.scale(-1)), 0); + } + private static void addToSet(DiscoveredLocation fromEnd, List> list, BiFunction offsetFactory, Function normalFactory, BezierConnection viaTurn) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java index 3c760fcee..23001e88c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationTileEntity.java @@ -326,7 +326,7 @@ public class StationTileEntity extends SmartTileEntity { DiscoveredLocation location = null; List> ends = - TrackPropagator.getEnds(level, trackPosition, trackState, null, true); + TrackPropagator.getEnds(level, trackPosition, trackState, true, null, null); for (Pair pair : ends) if (trackPosition.relative(assemblyDirection) .equals(pair.getFirst())) 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 e090dac84..fa3981ce5 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 @@ -4,7 +4,6 @@ import java.util.List; import java.util.Map.Entry; import java.util.Random; -import com.google.common.collect.ImmutableList; import com.jozufozu.flywheel.core.PartialModel; import com.jozufozu.flywheel.util.transform.MatrixTransformStack; import com.mojang.blaze3d.vertex.PoseStack; @@ -15,12 +14,12 @@ import com.simibubi.create.AllTileEntities; import com.simibubi.create.Create; import com.simibubi.create.CreateClient; import com.simibubi.create.content.contraptions.wrench.IWrenchable; +import com.simibubi.create.content.curiosities.girder.GirderBlock; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.TrackPropagator; import com.simibubi.create.content.logistics.trains.management.StationTileEntity; import com.simibubi.create.foundation.utility.AngleHelper; import com.simibubi.create.foundation.utility.Iterate; -import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VecHelper; import net.minecraft.core.BlockPos; @@ -29,18 +28,20 @@ import net.minecraft.core.Direction.Axis; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.Mth; -import net.minecraft.util.StringRepresentable; 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; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelReader; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition.Builder; @@ -62,74 +63,6 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac public static final EnumProperty SHAPE = EnumProperty.create("shape", TrackShape.class); public static final BooleanProperty HAS_TURN = BooleanProperty.create("turn"); - public enum TrackShape implements StringRepresentable { - NONE("", Vec3.ZERO), - ZO("z_ortho", new Vec3(0, 0, 1)), - XO("x_ortho", new Vec3(1, 0, 0)), - PD("diag", new Vec3(1, 0, 1)), - ND("diag_2", new Vec3(-1, 0, 1)), - AN("ascending", 180, new Vec3(0, 1, -1), new Vec3(0, 1, 1)), - AS("ascending", 0, new Vec3(0, 1, 1), new Vec3(0, 1, -1)), - AE("ascending", 270, new Vec3(1, 1, 0), new Vec3(-1, 1, 0)), - AW("ascending", 90, new Vec3(-1, 1, 0), new Vec3(1, 1, 0)), - - CR_O("cross_ortho", new Vec3(0, 0, 1), new Vec3(1, 0, 0)), - CR_D("cross_diag", new Vec3(1, 0, 1), new Vec3(-1, 0, 1)), - CR_PDX("cross_d1_xo", new Vec3(1, 0, 0), new Vec3(1, 0, 1)), - CR_PDZ("cross_d1_zo", new Vec3(0, 0, 1), new Vec3(1, 0, 1)), - CR_NDX("cross_d2_xo", new Vec3(1, 0, 0), new Vec3(-1, 0, 1)), - CR_NDZ("cross_d2_zo", new Vec3(0, 0, 1), new Vec3(-1, 0, 1)); - - private String model; - private List axes; - private int modelRotation; - private Vec3 normal; - - private TrackShape(String model, Vec3 axis) { - this(model, 0, axis, new Vec3(0, 1, 0)); - } - - private TrackShape(String model, Vec3 axis, Vec3 secondAxis) { - this.model = model; - this.modelRotation = 0; - this.normal = new Vec3(0, 1, 0); - this.axes = ImmutableList.of(axis, secondAxis); - } - - private TrackShape(String model, int modelRotation, Vec3 axis, Vec3 normal) { - this.model = model; - this.modelRotation = modelRotation; - this.normal = normal.normalize(); - this.axes = ImmutableList.of(axis); - } - - @Override - public String getSerializedName() { - return Lang.asId(name()); - } - - public String getModel() { - return model; - } - - public List getAxes() { - return axes; - } - - public boolean isJunction() { - return axes.size() > 1; - } - - public Vec3 getNormal() { - return normal; - } - - public int getModelRotation() { - return modelRotation; - } - - } - public TrackBlock(Properties p_49795_) { super(p_49795_); registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO) @@ -201,14 +134,18 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) { if (pOldState.getBlock() == this && pState.setValue(HAS_TURN, true) == pOldState.setValue(HAS_TURN, true)) return; + if (pLevel.isClientSide) + return; LevelTickAccess blockTicks = pLevel.getBlockTicks(); if (!blockTicks.hasScheduledTick(pPos, this)) pLevel.scheduleTick(pPos, this, 1); + updateGirders(pState, pLevel, pPos, blockTicks); } @Override public void tick(BlockState p_60462_, ServerLevel p_60463_, BlockPos p_60464_, Random p_60465_) { - TrackPropagator.onRailAdded(p_60463_, p_60464_, p_60462_); + for (Vec3 axis : getTrackAxes(p_60463_, p_60464_, p_60462_)) + TrackPropagator.onRailAdded(p_60463_, p_60464_, p_60462_, axis.normalize()); } @Override @@ -216,7 +153,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac boolean removeTE = false; if (pState.getValue(HAS_TURN) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TURN))) { BlockEntity blockEntity = pLevel.getBlockEntity(pPos); - if (blockEntity instanceof TrackTileEntity) + if (blockEntity instanceof TrackTileEntity && !pLevel.isClientSide) ((TrackTileEntity) blockEntity).removeInboundConnections(); removeTE = true; } @@ -225,6 +162,8 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac TrackPropagator.onRailRemoved(pLevel, pPos, pState); if (removeTE) pLevel.removeBlockEntity(pPos); + if (!pLevel.isClientSide) + updateGirders(pState, pLevel, pPos, pLevel.getBlockTicks()); } @Override @@ -253,14 +192,24 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac return InteractionResult.SUCCESS; } -// if (asItem() == itemInHand.getItem()) { -// TrackConnectionPlacementHandler.select(world, pos, player.getLookAngle(), itemInHand); -// return InteractionResult.SUCCESS; -// } - return InteractionResult.PASS; } + private void updateGirders(BlockState pState, Level pLevel, BlockPos pPos, LevelTickAccess blockTicks) { + for (Vec3 vec3 : getTrackAxes(pLevel, pPos, pState)) { + if (vec3.length() > 1 || vec3.y != 0) + continue; + for (int side : Iterate.positiveAndNegative) { + BlockPos girderPos = pPos.below() + .offset(vec3.z * side, 0, vec3.x * side); + BlockState girderState = pLevel.getBlockState(girderPos); + if (girderState.getBlock()instanceof GirderBlock girderBlock + && !blockTicks.hasScheduledTick(girderPos, girderBlock)) + pLevel.scheduleTick(girderPos, girderBlock, 1); + } + } + } + @Override public boolean canSurvive(BlockState state, LevelReader reader, BlockPos pos) { return reader.getBlockState(pos.below()) @@ -298,16 +247,21 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac .add(0, (vertical ? 0 : -.5f), 0) .add(axis.scale(.5)); } - + + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + return InteractionResult.SUCCESS; + } + @Override public BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) { if (placed.getBlock() != this) return existing; - + TrackShape existingShape = existing.getValue(SHAPE); TrackShape placedShape = placed.getValue(SHAPE); TrackShape combinedShape = null; - + for (boolean flip : Iterate.trueAndFalse) { TrackShape s1 = flip ? existingShape : placedShape; TrackShape s2 = flip ? placedShape : existingShape; @@ -324,26 +278,22 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac if (s1 == TrackShape.ZO && s2 == TrackShape.ND) combinedShape = TrackShape.CR_NDZ; } - + if (combinedShape != null) existing = existing.setValue(SHAPE, combinedShape); return existing; } @Override - public BlockState getRotatedBlockState(BlockState state, Direction targetedFace) { - switch (state.getValue(SHAPE)) { - case ND: - return state.setValue(SHAPE, TrackShape.XO); - case PD: - return state.setValue(SHAPE, TrackShape.ZO); - case XO: - return state.setValue(SHAPE, TrackShape.PD); - case ZO: - return state.setValue(SHAPE, TrackShape.ND); - default: - return state; - } + public BlockState rotate(BlockState state, Rotation pRotation) { + return state.setValue(SHAPE, state.getValue(SHAPE) + .rotate(pRotation)); + } + + @Override + public BlockState mirror(BlockState state, Mirror pMirror) { + return state.setValue(SHAPE, state.getValue(SHAPE) + .mirror(pMirror)); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java index 1007f12ad..a3541e6ce 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java @@ -113,20 +113,17 @@ public class TrackBlockItem extends BlockItem { ITrackBlock track = (ITrackBlock) block; Pair nearestTrackAxis = track.getNearestTrackAxis(world, pos, blockState, lookVec); - Vec3 axis = nearestTrackAxis.getFirst(); - boolean front = nearestTrackAxis.getSecond() == AxisDirection.POSITIVE; + Vec3 axis = nearestTrackAxis.getFirst() + .scale(nearestTrackAxis.getSecond() == AxisDirection.POSITIVE ? -1 : 1); + Vec3 end = track.getCurveStart(world, pos, blockState, axis); Vec3 normal = track.getUpNormal(world, pos, blockState) .normalize(); - axis = axis.scale(front ? -1 : 1); - Vec3 end = track.getCurveStart(world, pos, blockState, axis); - CompoundTag compoundTag = heldItem.getOrCreateTagElement("ConnectingFrom"); compoundTag.put("Pos", NbtUtils.writeBlockPos(pos)); compoundTag.put("Axis", VecHelper.writeNBT(axis)); compoundTag.put("Normal", VecHelper.writeNBT(normal)); compoundTag.put("End", VecHelper.writeNBT(end)); - compoundTag.putBoolean("Front", front); return true; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java index 15b1f0dfb..a14da5a73 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockStateGenerator.java @@ -1,7 +1,6 @@ package com.simibubi.create.content.logistics.trains.track; import com.simibubi.create.Create; -import com.simibubi.create.content.logistics.trains.track.TrackBlock.TrackShape; import com.simibubi.create.foundation.data.SpecialBlockStateGen; import com.tterrag.registrate.providers.DataGenContext; import com.tterrag.registrate.providers.RegistrateBlockstateProvider; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java index b07c9bbec..7bb371ede 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackInstance.java @@ -2,7 +2,6 @@ package com.simibubi.create.content.logistics.trains.track; import java.util.ArrayList; import java.util.List; -import java.util.Map; import java.util.Objects; import javax.annotation.Nullable; @@ -12,11 +11,11 @@ import com.jozufozu.flywheel.backend.instancing.blockentity.BlockEntityInstance; import com.jozufozu.flywheel.core.Materials; import com.jozufozu.flywheel.core.materials.model.ModelData; import com.jozufozu.flywheel.light.LightUpdater; -import com.jozufozu.flywheel.util.FlwUtil; import com.jozufozu.flywheel.util.box.GridAlignedBB; import com.jozufozu.flywheel.util.box.ImmutableBox; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.PoseStack.Pose; import com.simibubi.create.AllBlockPartials; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; @@ -39,13 +38,12 @@ public class TrackInstance extends BlockEntityInstance { @Override public void update() { - if (blockEntity.connections.stream() - .allMatch(Map::isEmpty)) { + if (blockEntity.connections.isEmpty()) return; - } - instances = blockEntity.connections.stream() - .flatMap(FlwUtil::mapValues) + remove(); + instances = blockEntity.connections.values() + .stream() .map(this::createInstance) .filter(Objects::nonNull) .toList(); @@ -56,10 +54,8 @@ public class TrackInstance extends BlockEntityInstance { @Override public ImmutableBox getVolume() { List out = new ArrayList<>(); - out.addAll(blockEntity.connections.getFirst() - .keySet()); - out.addAll(blockEntity.connections.getSecond() - .keySet()); + out.addAll(blockEntity.connections.keySet()); + out.addAll(blockEntity.connections.keySet()); return GridAlignedBB.containingAll(out); } @@ -129,12 +125,15 @@ public class TrackInstance extends BlockEntityInstance { var modelIndex = i - 1; ties[modelIndex].setTransform(pose) - .mulPose(segment.tieTransform); + .mulPose(segment.tieTransform.pose()) + .mulNormal(segment.tieTransform.normal()); tiesLightPos[modelIndex] = segment.lightPosition.offset(tePosition); for (boolean first : Iterate.trueAndFalse) { + Pose transform = segment.railTransforms.get(first); (first ? this.left : this.right)[modelIndex].setTransform(pose) - .mulPose(segment.railTransforms.get(first)); + .mulPose(transform.pose()) + .mulNormal(transform.normal()); (first ? leftLightPos : rightLightPos)[modelIndex] = segment.lightPosition.offset(tePosition); } } @@ -185,8 +184,9 @@ public class TrackInstance extends BlockEntityInstance { beams = Couple.create(() -> new ModelData[segCount]); beamCaps = Couple.create(() -> Couple.create(() -> new ModelData[segCount])); lightPos = new BlockPos[segCount]; - beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_2)::createInstances); - beamCaps.forEach(c -> c.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT)::createInstances)); + beams.forEach(mat.getModel(AllBlockPartials.GIRDER_SEGMENT_MIDDLE)::createInstances); + beamCaps.forEachWithContext((c, top) -> c.forEach(mat.getModel(top ? AllBlockPartials.GIRDER_SEGMENT_TOP + : AllBlockPartials.GIRDER_SEGMENT_BOTTOM)::createInstances)); GirderAngles[] bakedGirders = bc.getBakedGirders(); for (int i = 1; i < bakedGirders.length; i++) { @@ -195,13 +195,18 @@ public class TrackInstance extends BlockEntityInstance { lightPos[modelIndex] = segment.lightPosition.offset(tePosition); for (boolean first : Iterate.trueAndFalse) { + Pose beamTransform = segment.beams.get(first); beams.get(first)[modelIndex].setTransform(pose) - .mulPose(segment.beams.get(first)); - for (boolean top : Iterate.trueAndFalse) + .mulPose(beamTransform.pose()) + .mulNormal(beamTransform.normal()); + for (boolean top : Iterate.trueAndFalse) { + Pose beamCapTransform = segment.beamCaps.get(top) + .get(first); beamCaps.get(top) .get(first)[modelIndex].setTransform(pose) - .mulPose(segment.beamCaps.get(top) - .get(first)); + .mulPose(beamCapTransform.pose()) + .mulNormal(beamCapTransform.normal()); + } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index df84605af..a0ec882aa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -84,11 +84,10 @@ public class TrackPlacement { ITrackBlock track = (ITrackBlock) state2.getBlock(); Pair nearestTrackAxis = track.getNearestTrackAxis(level, pos2, state2, lookVec); - Vec3 axis2 = nearestTrackAxis.getFirst(); - boolean front2 = nearestTrackAxis.getSecond() == AxisDirection.POSITIVE; + Vec3 axis2 = nearestTrackAxis.getFirst() + .scale(nearestTrackAxis.getSecond() == AxisDirection.POSITIVE ? -1 : 1); Vec3 normal2 = track.getUpNormal(level, pos2, state2) .normalize(); - axis2 = axis2.scale(front2 ? -1 : 1); Vec3 normedAxis2 = axis2.normalize(); Vec3 end2 = track.getCurveStart(level, pos2, state2, axis2); @@ -137,7 +136,6 @@ public class TrackPlacement { if ((parallel && normedAxis1.dot(normedAxis2) > 0) || (!parallel && (intersect[0] < 0 || intersect[1] < 0))) { axis2 = axis2.scale(-1); normedAxis2 = normedAxis2.scale(-1); - front2 = !front2; end2 = track.getCurveStart(level, pos2, state2, axis2); if (level.isClientSide) { info.end2 = end2; @@ -161,7 +159,7 @@ public class TrackPlacement { BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z); info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), Couple.create(front1, front2), true, girder); + Couple.create(normal1, normal2), true, girder); } // S curve or Straight @@ -281,7 +279,7 @@ public class TrackPlacement { if (dist2 > dist1) ex2 = (float) ((dist2 - dist1) / axis2.length()); - double turnSize = Math.min(dist1, dist2); + double turnSize = Math.min(dist1, dist2) - .1d; boolean ninety = (absAngle + .25f) % 90 < 1; if (intersect[0] < 0 || intersect[1] < 0) @@ -312,7 +310,7 @@ public class TrackPlacement { info.curve = skipCurve ? null : new BezierConnection(Couple.create(targetPos1, targetPos2), Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2), - Couple.create(normal1, normal2), Couple.create(front1, front2), true, girder); + Couple.create(normal1, normal2), true, girder); info.valid = true; @@ -324,13 +322,15 @@ public class TrackPlacement { Vec3 axis = first ? axis1 : axis2; BlockPos pos = first ? pos1 : pos2; BlockState state = first ? state1 : state2; + if (state.hasProperty(TrackBlock.HAS_TURN)) + state = state.setValue(TrackBlock.HAS_TURN, false); for (int i = 0; i < extent; i++) { Vec3 offset = axis.scale(i); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockState stateAtPos = level.getBlockState(offsetPos); BlockState toPlace = state; - + boolean canPlace = stateAtPos.getMaterial() .isReplaceable(); if (stateAtPos.getBlock()instanceof ITrackBlock trackAtPos) { @@ -361,8 +361,8 @@ public class TrackPlacement { TrackTileEntity tte1 = (TrackTileEntity) te1; TrackTileEntity tte2 = (TrackTileEntity) te2; - tte1.addConnection(front1, info.curve); - tte2.addConnection(front2, info.curve.secondary()); + tte1.addConnection(info.curve); + tte2.addConnection(info.curve.secondary()); return info; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java index ca418c002..27d3024ad 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackRenderer.java @@ -1,7 +1,8 @@ package com.simibubi.create.content.logistics.trains.track; -import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT; -import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_2; +import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_BOTTOM; +import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_MIDDLE; +import static com.simibubi.create.AllBlockPartials.GIRDER_SEGMENT_TOP; import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_LEFT; import static com.simibubi.create.AllBlockPartials.TRACK_SEGMENT_RIGHT; import static com.simibubi.create.AllBlockPartials.TRACK_TIE; @@ -10,6 +11,7 @@ import com.jozufozu.flywheel.backend.Backend; import com.jozufozu.flywheel.repack.joml.Math; import com.jozufozu.flywheel.util.transform.TransformStack; import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.blaze3d.vertex.PoseStack.Pose; import com.mojang.blaze3d.vertex.VertexConsumer; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.BezierConnection.GirderAngles; @@ -29,6 +31,7 @@ import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction.Axis; import net.minecraft.util.Mth; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -40,22 +43,21 @@ public class TrackRenderer extends SafeTileEntityRenderer { @Override protected void renderSafe(TrackTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer, int light, int overlay) { - if (Backend.isOn()) + Level level = te.getLevel(); + if (Backend.canUseInstancing(level)) return; - VertexConsumer vb = buffer.getBuffer(RenderType.cutoutMipped()); - te.connections.forEach(map -> map.values() - .forEach(bc -> renderBezierTurn(bc, ms, vb))); + te.connections.values() + .forEach(bc -> renderBezierTurn(level, bc, ms, vb)); } - public static void renderBezierTurn(BezierConnection bc, PoseStack ms, VertexConsumer vb) { + public static void renderBezierTurn(Level level, BezierConnection bc, PoseStack ms, VertexConsumer vb) { if (!bc.isPrimary()) return; ms.pushPose(); BlockPos tePosition = bc.tePositions.getFirst(); BlockState air = Blocks.AIR.defaultBlockState(); - ClientLevel level = Minecraft.getInstance().level; SegmentAngles[] segments = bc.getBakedSegments(); TransformStack.cast(ms) @@ -68,17 +70,19 @@ public class TrackRenderer extends SafeTileEntityRenderer { int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); CachedBufferer.partial(TRACK_TIE, air) - .mulPose(segment.tieTransform) - .disableDiffuseMult() + .mulPose(segment.tieTransform.pose()) + .mulNormal(segment.tieTransform.normal()) .light(light) .renderInto(ms, vb); - for (boolean first : Iterate.trueAndFalse) + for (boolean first : Iterate.trueAndFalse) { + Pose transform = segment.railTransforms.get(first); CachedBufferer.partial(first ? TRACK_SEGMENT_LEFT : TRACK_SEGMENT_RIGHT, air) - .mulPose(segment.railTransforms.get(first)) - .disableDiffuseMult() + .mulPose(transform.pose()) + .mulNormal(transform.normal()) .light(light) .renderInto(ms, vb); + } } ms.popPose(); @@ -97,19 +101,22 @@ public class TrackRenderer extends SafeTileEntityRenderer { int light = LevelRenderer.getLightColor(level, segment.lightPosition.offset(tePosition)); for (boolean first : Iterate.trueAndFalse) { - CachedBufferer.partial(GIRDER_SEGMENT_2, air) - .mulPose(segment.beams.get(first)) - .disableDiffuseMult() + Pose beamTransform = segment.beams.get(first); + CachedBufferer.partial(GIRDER_SEGMENT_MIDDLE, air) + .mulPose(beamTransform.pose()) + .mulNormal(beamTransform.normal()) .light(light) .renderInto(ms, vb); - for (boolean top : Iterate.trueAndFalse) - CachedBufferer.partial(GIRDER_SEGMENT, air) - .mulPose(segment.beamCaps.get(top) - .get(first)) - .disableDiffuseMult() + for (boolean top : Iterate.trueAndFalse) { + Pose beamCapTransform = segment.beamCaps.get(top) + .get(first); + CachedBufferer.partial(top ? GIRDER_SEGMENT_TOP : GIRDER_SEGMENT_BOTTOM, air) + .mulPose(beamCapTransform.pose()) + .mulNormal(beamCapTransform.normal()) .light(light) .renderInto(ms, vb); + } } } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java new file mode 100644 index 000000000..f9a22a148 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackShape.java @@ -0,0 +1,135 @@ +package com.simibubi.create.content.logistics.trains.track; + +import java.util.EnumMap; +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.simibubi.create.foundation.utility.Lang; + +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.phys.Vec3; + +public enum TrackShape implements StringRepresentable { + NONE("", Vec3.ZERO), + ZO("z_ortho", new Vec3(0, 0, 1)), + XO("x_ortho", new Vec3(1, 0, 0)), + PD("diag", new Vec3(1, 0, 1)), + ND("diag_2", new Vec3(-1, 0, 1)), + AN("ascending", 180, new Vec3(0, 1, -1), new Vec3(0, 1, 1)), + AS("ascending", 0, new Vec3(0, 1, 1), new Vec3(0, 1, -1)), + AE("ascending", 270, new Vec3(1, 1, 0), new Vec3(-1, 1, 0)), + AW("ascending", 90, new Vec3(-1, 1, 0), new Vec3(1, 1, 0)), + + CR_O("cross_ortho", new Vec3(0, 0, 1), new Vec3(1, 0, 0)), + CR_D("cross_diag", new Vec3(1, 0, 1), new Vec3(-1, 0, 1)), + CR_PDX("cross_d1_xo", new Vec3(1, 0, 0), new Vec3(1, 0, 1)), + CR_PDZ("cross_d1_zo", new Vec3(0, 0, 1), new Vec3(1, 0, 1)), + CR_NDX("cross_d2_xo", new Vec3(1, 0, 0), new Vec3(-1, 0, 1)), + CR_NDZ("cross_d2_zo", new Vec3(0, 0, 1), new Vec3(-1, 0, 1)); + + private String model; + private List axes; + private int modelRotation; + private Vec3 normal; + + static EnumMap zMirror = new EnumMap<>(TrackShape.class), + xMirror = new EnumMap<>(TrackShape.class), clockwise = new EnumMap<>(TrackShape.class); + + static { + zMirror.putAll(ImmutableMap.builder() + .put(PD, ND) + .put(ND, PD) + .put(AN, AS) + .put(AS, AN) + .put(CR_PDX, CR_NDX) + .put(CR_NDX, CR_PDX) + .put(CR_PDZ, CR_NDZ) + .put(CR_NDZ, CR_PDZ) + .build()); + + xMirror.putAll(ImmutableMap.builder() + .put(PD, ND) + .put(ND, PD) + .put(AE, AW) + .put(AW, AE) + .put(CR_PDX, CR_NDX) + .put(CR_NDX, CR_PDX) + .put(CR_PDZ, CR_NDZ) + .put(CR_NDZ, CR_PDZ) + .build()); + + clockwise.putAll(ImmutableMap.builder() + .put(PD, ND) + .put(ND, PD) + .put(XO, ZO) + .put(ZO, XO) + .put(AE, AS) + .put(AS, AW) + .put(AW, AN) + .put(AN, AE) + .put(CR_PDX, CR_NDZ) + .put(CR_NDX, CR_PDZ) + .put(CR_PDZ, CR_NDX) + .put(CR_NDZ, CR_PDX) + .build()); + } + + private TrackShape(String model, Vec3 axis) { + this(model, 0, axis, new Vec3(0, 1, 0)); + } + + private TrackShape(String model, Vec3 axis, Vec3 secondAxis) { + this.model = model; + this.modelRotation = 0; + this.normal = new Vec3(0, 1, 0); + this.axes = ImmutableList.of(axis, secondAxis); + } + + private TrackShape(String model, int modelRotation, Vec3 axis, Vec3 normal) { + this.model = model; + this.modelRotation = modelRotation; + this.normal = normal.normalize(); + this.axes = ImmutableList.of(axis); + } + + @Override + public String getSerializedName() { + return Lang.asId(name()); + } + + public String getModel() { + return model; + } + + public List getAxes() { + return axes; + } + + public boolean isJunction() { + return axes.size() > 1; + } + + public Vec3 getNormal() { + return normal; + } + + public int getModelRotation() { + return modelRotation; + } + + public TrackShape mirror(Mirror mirror) { + return mirror == Mirror.NONE ? this + : mirror == Mirror.FRONT_BACK ? xMirror.getOrDefault(this, this) : zMirror.getOrDefault(this, this); + } + + public TrackShape rotate(Rotation rotation) { + TrackShape shape = this; + for (int i = 0; i < rotation.ordinal(); i++) + shape = clockwise.getOrDefault(shape, shape); + return shape; + } + +} \ No newline at end of file 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 d83a73721..71fec22ef 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 @@ -1,102 +1,118 @@ package com.simibubi.create.content.logistics.trains.track; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; import com.jozufozu.flywheel.backend.instancing.InstancedRenderDispatcher; +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.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.Couple; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.DistExecutor; -public class TrackTileEntity extends SmartTileEntity { +public class TrackTileEntity extends SmartTileEntity implements ITransformableTE, IMergeableTE { - Couple> connections; + Map connections; + boolean connectionsValidated; public TrackTileEntity(BlockEntityType type, BlockPos pos, BlockState state) { super(type, pos, state); - connections = Couple.create(HashMap::new); + connections = new HashMap<>(); + connectionsValidated = false; } - public Couple> getConnections() { + public Map getConnections() { + if (!level.isClientSide && !connectionsValidated) + validateConnections(); return connections; } - public void addConnection(boolean front, BezierConnection connection) { - connections.get(front) - .put(connection.getKey(), connection); - notifyUpdate(); - level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); + 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; + } + invalid.add(key); + } + + connectionsValidated = true; + for (BlockPos blockPos : invalid) + removeConnection(blockPos); } - public void removeConnection(boolean front, BlockPos target) { - connections.get(front) - .remove(target); + public void addConnection(BezierConnection connection) { + connections.put(connection.getKey(), connection); + level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); notifyUpdate(); + } - // TODO remove TE when all connections removed. seems tricky without a packet - // because level.removeBlockEntity apparently no longer syncs + public void removeConnection(BlockPos target) { + connections.remove(target); + notifyUpdate(); + if (!connections.isEmpty()) + return; -// if (connections.getFirst() -// .isEmpty() -// && connections.getSecond() -// .isEmpty()) { -// BlockState blockState = getBlockState(); -// if (!blockState.hasProperty(TrackBlock.HAS_TURN)) -// return; -// } + BlockState blockState = getBlockState(); + if (blockState.hasProperty(TrackBlock.HAS_TURN)) + level.setBlockAndUpdate(worldPosition, blockState.setValue(TrackBlock.HAS_TURN, false)); + AllPackets.channel.send(packetTarget(), new RemoveTileEntityPacket(worldPosition)); } public void removeInboundConnections() { - connections.forEach(map -> map.values() - .forEach(bc -> { - BlockEntity blockEntity = level.getBlockEntity(bc.getKey()); - if (!(blockEntity instanceof TrackTileEntity)) - return; - TrackTileEntity other = (TrackTileEntity) blockEntity; - other.removeConnection(bc.trackEnds.getSecond(), bc.tePositions.getFirst()); - })); + for (BezierConnection bezierConnection : connections.values()) { + BlockEntity blockEntity = level.getBlockEntity(bezierConnection.getKey()); + if (!(blockEntity instanceof TrackTileEntity)) + return; + TrackTileEntity other = (TrackTileEntity) blockEntity; + other.removeConnection(bezierConnection.tePositions.getFirst()); + } } @Override protected void write(CompoundTag tag, boolean clientPacket) { super.write(tag, clientPacket); - - CompoundTag connectionsTag = new CompoundTag(); - connections.forEachWithContext((map, first) -> { - ListTag listTag = new ListTag(); - map.values() - .forEach(e -> listTag.add(e.write())); - connectionsTag.put(first ? "Front" : "Back", listTag); - }); - - tag.put("Connections", connectionsTag); + ListTag listTag = new ListTag(); + for (BezierConnection bezierConnection : connections.values()) + listTag.add(bezierConnection.write(worldPosition)); + tag.put("Connections", listTag); } @Override protected void read(CompoundTag tag, boolean clientPacket) { super.read(tag, clientPacket); - - CompoundTag connectionsTag = tag.getCompound("Connections"); - connections.forEach(Map::clear); - connections.forEachWithContext((map, first) -> connectionsTag.getList(first ? "Front" : "Back", 10) - .forEach(t -> { - if (!(t instanceof CompoundTag)) - return; - BezierConnection connection = new BezierConnection((CompoundTag) t); - map.put(connection.getKey(), connection); - })); + connections.clear(); + for (Tag t : tag.getList("Connections", Tag.TAG_COMPOUND)) { + if (!(t instanceof CompoundTag)) + return; + BezierConnection connection = new BezierConnection((CompoundTag) t, worldPosition); + connections.put(connection.getKey(), connection); + } DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> InstancedRenderDispatcher.enqueueUpdate(this)); } @@ -109,4 +125,49 @@ public class TrackTileEntity extends SmartTileEntity { @Override public void addBehaviours(List behaviours) {} + @Override + public void accept(BlockEntity other) { + if (other instanceof TrackTileEntity track) + connections.putAll(track.connections); + connectionsValidated = false; + level.scheduleTick(worldPosition, getBlockState().getBlock(), 1); + } + + @Override + public void transform(StructureTransform transform) { + if (transform.rotationAxis != Axis.Y) + return; + + Map transformedConnections = new HashMap<>(); + for (Entry entry : connections.entrySet()) { + BezierConnection newConnection = entry.getValue(); + newConnection.normals.replace(transform::applyWithoutOffsetUncentered); + newConnection.axes.replace(transform::applyWithoutOffsetUncentered); + + BlockPos diff = newConnection.tePositions.getSecond() + .subtract(newConnection.tePositions.getFirst()); + newConnection.tePositions.setSecond(new BlockPos(Vec3.atCenterOf(newConnection.tePositions.getFirst()) + .add(transform.applyWithoutOffsetUncentered(Vec3.atLowerCornerOf(diff))))); + + Vec3 teVec = Vec3.atLowerCornerOf(worldPosition); + Vec3 teCenterVec = teVec.add(0.5, 0.5, 0.5); + Vec3 start = newConnection.starts.getFirst(); + Vec3 startToTE = start.subtract(teCenterVec); + Vec3 endToStart = newConnection.starts.getSecond() + .subtract(start); + startToTE = transform.applyWithoutOffsetUncentered(startToTE) + .add(teCenterVec); + endToStart = transform.applyWithoutOffsetUncentered(endToStart) + .add(startToTE); + + newConnection.starts.setFirst(new TrackNodeLocation(startToTE).getLocation()); + newConnection.starts.setSecond(new TrackNodeLocation(endToStart).getLocation()); + + BlockPos newTarget = newConnection.getKey(); + transformedConnections.put(newTarget, newConnection); + } + + connections = transformedConnections; + } + } diff --git a/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java b/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java index fc56d4815..9df53cf9a 100644 --- a/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java +++ b/src/main/java/com/simibubi/create/content/schematics/SchematicPrinter.java @@ -8,6 +8,7 @@ import com.simibubi.create.AllBlocks; import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks; import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.schematics.item.SchematicItem; +import com.simibubi.create.foundation.tileEntity.IMergeableTE; import com.simibubi.create.foundation.utility.BlockHelper; import net.minecraft.core.BlockPos; @@ -190,7 +191,9 @@ public class SchematicPrinter { BlockEntity tileEntity = blockReader.getBlockEntity(pos); BlockState toReplace = world.getBlockState(pos); + BlockEntity toReplaceTE = world.getBlockEntity(pos); BlockState toReplaceOther = null; + if (state.hasProperty(BlockStateProperties.BED_PART) && state.hasProperty(BlockStateProperties.HORIZONTAL_FACING) && state.getValue(BlockStateProperties.BED_PART) == BedPart.FOOT) toReplaceOther = world.getBlockState(pos.relative(state.getValue(BlockStateProperties.HORIZONTAL_FACING))); @@ -198,11 +201,14 @@ public class SchematicPrinter { && state.getValue(BlockStateProperties.DOUBLE_BLOCK_HALF) == DoubleBlockHalf.LOWER) toReplaceOther = world.getBlockState(pos.above()); + boolean mergeTEs = tileEntity != null && toReplaceTE instanceof IMergeableTE mergeTE && toReplaceTE.getType() + .equals(tileEntity.getType()); + if (!world.isLoaded(pos)) return false; if (!world.getWorldBorder().isWithinBounds(pos)) return false; - if (toReplace == state) + if (toReplace == state && !mergeTEs) return false; if (toReplace.getDestroySpeed(world, pos) == -1 || (toReplaceOther != null && toReplaceOther.getDestroySpeed(world, pos) == -1)) diff --git a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java index fb4e2a8ab..e604afc2e 100644 --- a/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java +++ b/src/main/java/com/simibubi/create/content/schematics/client/SchematicHandler.java @@ -8,6 +8,7 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.AllKeys; +import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform; import com.simibubi.create.content.schematics.SchematicWorld; import com.simibubi.create.content.schematics.client.tools.Tools; import com.simibubi.create.content.schematics.filtering.SchematicInstances; @@ -23,6 +24,7 @@ import com.simibubi.create.foundation.utility.outliner.AABBOutline; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction.Axis; import net.minecraft.core.Vec3i; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; @@ -33,6 +35,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Mirror; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; @@ -137,16 +141,27 @@ public class SchematicHandler { SchematicWorld wMirroredFB = new SchematicWorld(clientWorld); SchematicWorld wMirroredLR = new SchematicWorld(clientWorld); StructurePlaceSettings placementSettings = new StructurePlaceSettings(); + StructureTransform transform; BlockPos pos; pos = BlockPos.ZERO; schematic.placeInWorld(w, pos, pos, placementSettings, w.getRandom(), Block.UPDATE_CLIENTS); + placementSettings.setMirror(Mirror.FRONT_BACK); pos = BlockPos.ZERO.east(size.getX() - 1); schematic.placeInWorld(wMirroredFB, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS); + transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE, + placementSettings.getMirror()); + for (BlockEntity te : wMirroredFB.getRenderedTileEntities()) + transform.apply(te); + placementSettings.setMirror(Mirror.LEFT_RIGHT); pos = BlockPos.ZERO.south(size.getZ() - 1); schematic.placeInWorld(wMirroredLR, pos, pos, placementSettings, wMirroredFB.getRandom(), Block.UPDATE_CLIENTS); + transform = new StructureTransform(placementSettings.getRotationPivot(), Axis.Y, Rotation.NONE, + placementSettings.getMirror()); + for (BlockEntity te : wMirroredLR.getRenderedTileEntities()) + transform.apply(te); renderers.get(0) .display(w); @@ -187,11 +202,11 @@ public class SchematicHandler { renderers.get(0) .render(ms, buffer); } - + if (active) currentTool.getTool() - .renderOnSchematic(ms, buffer); - + .renderOnSchematic(ms, buffer); + ms.popPose(); } @@ -227,7 +242,7 @@ public class SchematicHandler { return; } currentTool.getTool() - .handleRightClick(); + .handleRightClick(); } public void onKeyInput(int key, boolean pressed) { @@ -272,10 +287,12 @@ public class SchematicHandler { private boolean itemLost(Player player) { for (int i = 0; i < Inventory.getSelectionSize(); i++) { - if (!player.getInventory().getItem(i) + if (!player.getInventory() + .getItem(i) .sameItem(activeSchematicItem)) continue; - if (!ItemStack.tagMatches(player.getInventory().getItem(i), activeSchematicItem)) + if (!ItemStack.tagMatches(player.getInventory() + .getItem(i), activeSchematicItem)) continue; return false; } @@ -289,7 +306,8 @@ public class SchematicHandler { public void sync() { if (activeSchematicItem == null) return; - AllPackets.channel.sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(), transformation.getAnchor(), deployed)); + AllPackets.channel.sendToServer(new SchematicSyncPacket(activeHotbarSlot, transformation.toSettings(), + transformation.getAnchor(), deployed)); } public void equip(Tools tool) { 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 c8a4169d2..af1f83931 100644 --- a/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java +++ b/src/main/java/com/simibubi/create/foundation/networking/AllPackets.java @@ -57,6 +57,7 @@ import com.simibubi.create.foundation.command.SConfigureConfigPacket; import com.simibubi.create.foundation.config.ui.CConfigureConfigPacket; import com.simibubi.create.foundation.gui.container.ClearContainerPacket; import com.simibubi.create.foundation.gui.container.GhostItemSubmitPacket; +import com.simibubi.create.foundation.tileEntity.RemoveTileEntityPacket; import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringCountUpdatePacket; import com.simibubi.create.foundation.tileEntity.behaviour.scrollvalue.ScrollValueUpdatePacket; import com.simibubi.create.foundation.utility.ServerSpeedProvider; @@ -132,6 +133,7 @@ public enum AllPackets { PERSISTENT_DATA(ISyncPersistentData.PersistentDataPacket.class, ISyncPersistentData.PersistentDataPacket::new, PLAY_TO_CLIENT), SYNC_POTATO_PROJECTILE_TYPES(PotatoProjectileTypeManager.SyncPacket.class, PotatoProjectileTypeManager.SyncPacket::new, PLAY_TO_CLIENT), SYNC_RAIL_GRAPH(RailGraphSyncPacket.class, RailGraphSyncPacket::new, PLAY_TO_CLIENT), + REMOVE_TE(RemoveTileEntityPacket.class, RemoveTileEntityPacket::new, PLAY_TO_CLIENT), ; diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/IMergeableTE.java b/src/main/java/com/simibubi/create/foundation/tileEntity/IMergeableTE.java new file mode 100644 index 000000000..da3636adf --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/IMergeableTE.java @@ -0,0 +1,9 @@ +package com.simibubi.create.foundation.tileEntity; + +import net.minecraft.world.level.block.entity.BlockEntity; + +public interface IMergeableTE { + + public void accept(BlockEntity other); + +} diff --git a/src/main/java/com/simibubi/create/foundation/tileEntity/RemoveTileEntityPacket.java b/src/main/java/com/simibubi/create/foundation/tileEntity/RemoveTileEntityPacket.java new file mode 100644 index 000000000..a12f2958c --- /dev/null +++ b/src/main/java/com/simibubi/create/foundation/tileEntity/RemoveTileEntityPacket.java @@ -0,0 +1,26 @@ +package com.simibubi.create.foundation.tileEntity; + +import com.simibubi.create.foundation.networking.TileEntityDataPacket; + +import net.minecraft.core.BlockPos; +import net.minecraft.network.FriendlyByteBuf; + +public class RemoveTileEntityPacket extends TileEntityDataPacket { + + public RemoveTileEntityPacket(BlockPos pos) { + super(pos); + } + + public RemoveTileEntityPacket(FriendlyByteBuf buffer) { + super(buffer); + } + + @Override + protected void writeData(FriendlyByteBuf buffer) {} + + @Override + protected void handlePacket(SyncedTileEntity tile) { + tile.setRemoved(); + } + +} diff --git a/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java b/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java index 7037f24d7..f95a41faf 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/BlockHelper.java @@ -7,6 +7,7 @@ import javax.annotation.Nullable; 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.foundation.tileEntity.IMergeableTE; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -200,15 +201,12 @@ public class BlockHelper { int idx = chunk.getSectionIndex(target.getY()); LevelChunkSection chunksection = chunk.getSection(idx); if (chunksection == null) { - chunksection = new LevelChunkSection(chunk.getSectionYFromSectionIndex(idx), - world.registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)); + chunksection = new LevelChunkSection(chunk.getSectionYFromSectionIndex(idx), world.registryAccess() + .registryOrThrow(Registry.BIOME_REGISTRY)); chunk.getSections()[idx] = chunksection; } - BlockState old = chunksection.setBlockState( - SectionPos.sectionRelative(target.getX()), - SectionPos.sectionRelative(target.getY()), - SectionPos.sectionRelative(target.getZ()), - state); + BlockState old = chunksection.setBlockState(SectionPos.sectionRelative(target.getX()), + SectionPos.sectionRelative(target.getY()), SectionPos.sectionRelative(target.getZ()), state); chunk.setUnsaved(true); world.markAndNotifyBlock(target, chunk, old, state, 82, 512); @@ -219,6 +217,8 @@ public class BlockHelper { public static void placeSchematicBlock(Level world, BlockState state, BlockPos target, ItemStack stack, @Nullable CompoundTag data) { + BlockEntity existingTile = world.getBlockEntity(target); + // Piston if (state.hasProperty(BlockStateProperties.EXTENDED)) state = state.setValue(BlockStateProperties.EXTENDED, Boolean.FALSE); @@ -259,6 +259,14 @@ public class BlockHelper { } if (data != null) { + if (existingTile instanceof IMergeableTE mergeable) { + BlockEntity loaded = BlockEntity.loadStatic(target, state, data); + if (existingTile.getType() + .equals(loaded.getType())) { + mergeable.accept(loaded); + return; + } + } BlockEntity tile = world.getBlockEntity(target); if (tile != null) { data.putInt("x", target.getX()); diff --git a/src/main/resources/assets/create/models/block/metal_girder/segment_bottom.json b/src/main/resources/assets/create/models/block/metal_girder/segment_bottom.json new file mode 100644 index 000000000..dde8fe7bb --- /dev/null +++ b/src/main/resources/assets/create/models/block/metal_girder/segment_bottom.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/girder" + }, + "elements": [ + { + "from": [-4, -1, 0], + "to": [4, 1, 8], + "rotation": {"angle": 0, "axis": "y", "origin": [8, 13, 8]}, + "faces": { + "north": {"uv": [12, 2, 16, 3], "texture": "#0"}, + "east": {"uv": [1, 5, 5, 4], "texture": "#0"}, + "south": {"uv": [12, 2, 16, 3], "texture": "#0"}, + "west": {"uv": [3, 5, 7, 4], "texture": "#0"}, + "up": {"uv": [12, 0, 16, 4], "rotation": 270, "texture": "#0"}, + "down": {"uv": [2, 0, 6, 4], "rotation": 270, "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/metal_girder/segment2.json b/src/main/resources/assets/create/models/block/metal_girder/segment_middle.json similarity index 100% rename from src/main/resources/assets/create/models/block/metal_girder/segment2.json rename to src/main/resources/assets/create/models/block/metal_girder/segment_middle.json diff --git a/src/main/resources/assets/create/models/block/metal_girder/segment.json b/src/main/resources/assets/create/models/block/metal_girder/segment_top.json similarity index 100% rename from src/main/resources/assets/create/models/block/metal_girder/segment.json rename to src/main/resources/assets/create/models/block/metal_girder/segment_top.json