Bulk Wrenching
- Tracks can now be removed in bulk using the wrench - Track placement now automatically picks larger radii when connecting at non-equal y levels
This commit is contained in:
parent
9e0f35e4d7
commit
7ba4af1bea
7 changed files with 231 additions and 8 deletions
|
@ -60,6 +60,10 @@ public class TrainRelocator {
|
|||
static Boolean lastHoveredResult;
|
||||
static List<Vec3> toVisualise;
|
||||
|
||||
public static boolean isRelocating() {
|
||||
return relocatingTrain != null;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onClicked(ClickInputEvent event) {
|
||||
if (relocatingTrain == null)
|
||||
|
|
|
@ -292,6 +292,15 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
|||
|
||||
@Override
|
||||
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
|
||||
if (context.getLevel().isClientSide)
|
||||
TrackRemoval.wrenched(context.getClickedPos());
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
|
||||
if (context.getLevel().isClientSide)
|
||||
TrackRemoval.sneakWrenched(context.getClickedPos());
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -286,20 +286,21 @@ public class TrackPlacement {
|
|||
return info.withMessage("too_sharp")
|
||||
.tooJumbly();
|
||||
|
||||
int minTurnSize = ninety ? 7 : 3;
|
||||
int maxAscend = ninety ? 3 : 2;
|
||||
double minTurnSize = ninety ? 7 : 3.25;
|
||||
double turnSizeToFitAscend =
|
||||
minTurnSize + (ninety ? Math.max(0, absAscend - 3) * 2f : Math.max(0, absAscend - 1.5f) * 1.5f);
|
||||
|
||||
if (turnSize < minTurnSize)
|
||||
return info.withMessage("too_sharp");
|
||||
if (absAscend > maxAscend)
|
||||
if (turnSize < turnSizeToFitAscend)
|
||||
return info.withMessage("too_steep");
|
||||
|
||||
// This is for standardising curve sizes
|
||||
ex1 += (turnSize - minTurnSize) / axis1.length();
|
||||
ex2 += (turnSize - minTurnSize) / axis2.length();
|
||||
info.end1Extent = Math.round(ex1);
|
||||
info.end2Extent = Math.round(ex2);
|
||||
turnSize = minTurnSize;
|
||||
ex1 += (turnSize - turnSizeToFitAscend) / axis1.length();
|
||||
ex2 += (turnSize - turnSizeToFitAscend) / axis2.length();
|
||||
info.end1Extent = Mth.floor(ex1);
|
||||
info.end2Extent = Mth.floor(ex2);
|
||||
turnSize = turnSizeToFitAscend;
|
||||
}
|
||||
|
||||
Vec3 offset1 = axis1.scale(info.end1Extent);
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.HitResult.Type;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class TrackRemoval {
|
||||
|
||||
static BlockPos startPos;
|
||||
static BlockPos hoveringPos;
|
||||
static Set<BlockPos> toRemove;
|
||||
|
||||
// TODO localisation
|
||||
|
||||
public static void sneakWrenched(BlockPos pos) {
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
if (startPos != null) {
|
||||
startPos = null;
|
||||
player.displayClientMessage(new TextComponent("Track removal aborted").withStyle(ChatFormatting.RED), true);
|
||||
return;
|
||||
}
|
||||
startPos = pos;
|
||||
}
|
||||
|
||||
public static void wrenched(BlockPos pos) {
|
||||
if (startPos == null || hoveringPos == null || toRemove == null)
|
||||
return;
|
||||
if (TrainRelocator.isRelocating())
|
||||
return;
|
||||
AllPackets.channel.sendToServer(new TrackRemovalPacket(toRemove));
|
||||
startPos = null;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void clientTick() {
|
||||
if (startPos == null)
|
||||
return;
|
||||
|
||||
LocalPlayer player = Minecraft.getInstance().player;
|
||||
ItemStack stack = player.getMainHandItem();
|
||||
HitResult hitResult = Minecraft.getInstance().hitResult;
|
||||
|
||||
if (hitResult == null)
|
||||
return;
|
||||
if (hitResult.getType() != Type.BLOCK)
|
||||
return;
|
||||
|
||||
if (!AllItems.WRENCH.isIn(stack)) {
|
||||
hoveringPos = null;
|
||||
startPos = null;
|
||||
player.displayClientMessage(new TextComponent("Track removal aborted").withStyle(ChatFormatting.RED), true);
|
||||
return;
|
||||
}
|
||||
|
||||
BlockHitResult result = (BlockHitResult) hitResult;
|
||||
BlockPos blockPos = result.getBlockPos();
|
||||
Level level = player.level;
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (!(blockState.getBlock()instanceof ITrackBlock track)) {
|
||||
player.displayClientMessage(new TextComponent("Select a second track piece, Unequip Wrench to abort"),
|
||||
true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (blockPos.equals(hoveringPos)) {
|
||||
if (hoveringPos.equals(startPos)) {
|
||||
player.displayClientMessage(
|
||||
new TextComponent("Starting point selected. Right-Click a second Track piece"), true);
|
||||
} else if (toRemove == null) {
|
||||
player.displayClientMessage(new TextComponent("Starting point not reachable, Sneak-Click to abort")
|
||||
.withStyle(ChatFormatting.RED), true);
|
||||
} else
|
||||
player.displayClientMessage(new TextComponent("Right-Click to confirm").withStyle(ChatFormatting.GREEN),
|
||||
true);
|
||||
|
||||
//
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
hoveringPos = blockPos;
|
||||
toRemove = new HashSet<>();
|
||||
|
||||
List<BlockPos> frontier = new ArrayList<>();
|
||||
Set<BlockPos> visited = new HashSet<>();
|
||||
|
||||
if (search(level, hoveringPos, frontier, visited, 0)) {
|
||||
toRemove.add(hoveringPos);
|
||||
toRemove.add(startPos);
|
||||
return;
|
||||
}
|
||||
|
||||
toRemove = null;
|
||||
}
|
||||
|
||||
private static boolean search(Level level, BlockPos pos, List<BlockPos> frontier, Set<BlockPos> visited,
|
||||
int depth) {
|
||||
if (pos.equals(startPos))
|
||||
return true;
|
||||
if (depth > 32)
|
||||
return false;
|
||||
if (!visited.add(pos))
|
||||
return false;
|
||||
BlockState blockState = level.getBlockState(pos);
|
||||
if (!(blockState.getBlock()instanceof ITrackBlock track))
|
||||
return false;
|
||||
for (DiscoveredLocation discoveredLocation : track.getConnected(level, pos, blockState, false, null)) {
|
||||
for (BlockPos blockPos : discoveredLocation.allAdjacent()) {
|
||||
if (!search(level, blockPos, frontier, visited, depth + 1))
|
||||
continue;
|
||||
toRemove.add(pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
package com.simibubi.create.content.logistics.trains.track;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.content.logistics.trains.ITrackBlock;
|
||||
import com.simibubi.create.foundation.networking.SimplePacketBase;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
|
||||
public class TrackRemovalPacket extends SimplePacketBase {
|
||||
|
||||
private Set<BlockPos> tracks;
|
||||
|
||||
public TrackRemovalPacket(Set<BlockPos> tracks) {
|
||||
this.tracks = tracks;
|
||||
}
|
||||
|
||||
public TrackRemovalPacket(FriendlyByteBuf buffer) {
|
||||
tracks = new HashSet<>();
|
||||
int size = buffer.readVarInt();
|
||||
for (int i = 0; i < size; i++)
|
||||
tracks.add(buffer.readBlockPos());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeVarInt(tracks.size());
|
||||
tracks.forEach(buffer::writeBlockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(Supplier<Context> context) {
|
||||
Context ctx = context.get();
|
||||
ctx.enqueueWork(() -> {
|
||||
ServerPlayer sender = ctx.getSender();
|
||||
Level level = sender.level;
|
||||
if (!AllItems.WRENCH.isIn(sender.getMainHandItem()))
|
||||
return;
|
||||
|
||||
for (BlockPos blockPos : tracks) {
|
||||
BlockState blockState = level.getBlockState(blockPos);
|
||||
if (!blockPos.closerThan(sender.blockPosition(), 48))
|
||||
continue;
|
||||
if (!(blockState.getBlock()instanceof ITrackBlock track))
|
||||
continue;
|
||||
if (!sender.mayInteract(level, blockPos))
|
||||
continue;
|
||||
|
||||
level.destroyBlock(blockPos, !sender.isCreative());
|
||||
}
|
||||
|
||||
sender.displayClientMessage(new TextComponent("Tracks removed successfully"), true);
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
|
||||
}
|
|
@ -37,6 +37,7 @@ import com.simibubi.create.content.logistics.trains.entity.CarriageCouplingRende
|
|||
import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackPlacement;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRemoval;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
|
||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||
|
@ -153,6 +154,7 @@ public class ClientEvents {
|
|||
ToolboxHandlerClient.clientTick();
|
||||
TrackTargetingBlockItem.clientTick();
|
||||
TrackPlacement.clientTick();
|
||||
TrackRemoval.clientTick();
|
||||
TrainRelocator.clientTick();
|
||||
}
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.station
|
|||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket.TrainEditReturnPacket;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleEditPacket;
|
||||
import com.simibubi.create.content.logistics.trains.track.TrackRemovalPacket;
|
||||
import com.simibubi.create.content.schematics.packet.ConfigureSchematicannonPacket;
|
||||
import com.simibubi.create.content.schematics.packet.InstantSchematicPacket;
|
||||
import com.simibubi.create.content.schematics.packet.SchematicPlacePacket;
|
||||
|
@ -118,6 +119,7 @@ public enum AllPackets {
|
|||
C_CONFIGURE_TRAIN(TrainEditPacket.class, TrainEditPacket::new, PLAY_TO_SERVER),
|
||||
RELOCATE_TRAIN(TrainRelocationPacket.class, TrainRelocationPacket::new, PLAY_TO_SERVER),
|
||||
CONTROLS_INPUT(ControlsInputPacket.class, ControlsInputPacket::new, PLAY_TO_SERVER),
|
||||
REMOVE_TRACKS(TrackRemovalPacket.class, TrackRemovalPacket::new, PLAY_TO_SERVER),
|
||||
|
||||
// Server to Client
|
||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
||||
|
|
Loading…
Reference in a new issue