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 Boolean lastHoveredResult;
|
||||||
static List<Vec3> toVisualise;
|
static List<Vec3> toVisualise;
|
||||||
|
|
||||||
|
public static boolean isRelocating() {
|
||||||
|
return relocatingTrain != null;
|
||||||
|
}
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static void onClicked(ClickInputEvent event) {
|
public static void onClicked(ClickInputEvent event) {
|
||||||
if (relocatingTrain == null)
|
if (relocatingTrain == null)
|
||||||
|
|
|
@ -292,6 +292,15 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
|
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;
|
return InteractionResult.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -286,20 +286,21 @@ public class TrackPlacement {
|
||||||
return info.withMessage("too_sharp")
|
return info.withMessage("too_sharp")
|
||||||
.tooJumbly();
|
.tooJumbly();
|
||||||
|
|
||||||
int minTurnSize = ninety ? 7 : 3;
|
double minTurnSize = ninety ? 7 : 3.25;
|
||||||
int maxAscend = ninety ? 3 : 2;
|
double turnSizeToFitAscend =
|
||||||
|
minTurnSize + (ninety ? Math.max(0, absAscend - 3) * 2f : Math.max(0, absAscend - 1.5f) * 1.5f);
|
||||||
|
|
||||||
if (turnSize < minTurnSize)
|
if (turnSize < minTurnSize)
|
||||||
return info.withMessage("too_sharp");
|
return info.withMessage("too_sharp");
|
||||||
if (absAscend > maxAscend)
|
if (turnSize < turnSizeToFitAscend)
|
||||||
return info.withMessage("too_steep");
|
return info.withMessage("too_steep");
|
||||||
|
|
||||||
// This is for standardising curve sizes
|
// This is for standardising curve sizes
|
||||||
ex1 += (turnSize - minTurnSize) / axis1.length();
|
ex1 += (turnSize - turnSizeToFitAscend) / axis1.length();
|
||||||
ex2 += (turnSize - minTurnSize) / axis2.length();
|
ex2 += (turnSize - turnSizeToFitAscend) / axis2.length();
|
||||||
info.end1Extent = Math.round(ex1);
|
info.end1Extent = Mth.floor(ex1);
|
||||||
info.end2Extent = Math.round(ex2);
|
info.end2Extent = Mth.floor(ex2);
|
||||||
turnSize = minTurnSize;
|
turnSize = turnSizeToFitAscend;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec3 offset1 = axis1.scale(info.end1Extent);
|
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.entity.TrainRelocator;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBlockItem;
|
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.TrackPlacement;
|
||||||
|
import com.simibubi.create.content.logistics.trains.track.TrackRemoval;
|
||||||
import com.simibubi.create.foundation.config.AllConfigs;
|
import com.simibubi.create.foundation.config.AllConfigs;
|
||||||
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
|
import com.simibubi.create.foundation.config.ui.BaseConfigScreen;
|
||||||
import com.simibubi.create.foundation.fluid.FluidHelper;
|
import com.simibubi.create.foundation.fluid.FluidHelper;
|
||||||
|
@ -153,6 +154,7 @@ public class ClientEvents {
|
||||||
ToolboxHandlerClient.clientTick();
|
ToolboxHandlerClient.clientTick();
|
||||||
TrackTargetingBlockItem.clientTick();
|
TrackTargetingBlockItem.clientTick();
|
||||||
TrackPlacement.clientTick();
|
TrackPlacement.clientTick();
|
||||||
|
TrackRemoval.clientTick();
|
||||||
TrainRelocator.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;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.TrainEditPacket.TrainEditReturnPacket;
|
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.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.ConfigureSchematicannonPacket;
|
||||||
import com.simibubi.create.content.schematics.packet.InstantSchematicPacket;
|
import com.simibubi.create.content.schematics.packet.InstantSchematicPacket;
|
||||||
import com.simibubi.create.content.schematics.packet.SchematicPlacePacket;
|
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),
|
C_CONFIGURE_TRAIN(TrainEditPacket.class, TrainEditPacket::new, PLAY_TO_SERVER),
|
||||||
RELOCATE_TRAIN(TrainRelocationPacket.class, TrainRelocationPacket::new, PLAY_TO_SERVER),
|
RELOCATE_TRAIN(TrainRelocationPacket.class, TrainRelocationPacket::new, PLAY_TO_SERVER),
|
||||||
CONTROLS_INPUT(ControlsInputPacket.class, ControlsInputPacket::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
|
// Server to Client
|
||||||
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
|
||||||
|
|
Loading…
Reference in a new issue