Politeness Intensifies
- Train navigation now tries to pick destinations and directions avoiding other trains and stations on the way - Trains now slow to a secondary top speed when approaching a turn - Attempts to fix trains not always showing up when entering a clients tracking distance - Substantial increase to carriage contraption's client tracking range - Fixed Carriage Contraptions starting to render before fully aligned to their position/angle - Fixed trains remaining stuck to far away signals after being controlled manually for a bit - Fixed crash when placing tracks into a replaceable block - Fixed a handful of dist issues for dedicated servers - Fixed controls allowing control even when a train is not fully assembled yet - Controls now disengage on relog/esc
This commit is contained in:
parent
7ba4af1bea
commit
71e18eb505
25 changed files with 380 additions and 150 deletions
|
@ -2143,7 +2143,7 @@ d080b1b25e5bc8baf5aee68691b08c7f12ece3b0 assets/create/models/item/windmill_bear
|
|||
a80fb25a0b655e76be986b5b49fcb0f03461a1ab assets/create/models/item/zinc_nugget.json
|
||||
b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json
|
||||
5049f72c327a88f175f6f9425909e098fc711100 assets/create/sounds.json
|
||||
0f1b4b980afba9bf2caf583b88e261bba8b10313 data/create/advancements/aesthetics.json
|
||||
5d0cc4c0255dc241e61c173b31ddca70c88d08e4 data/create/advancements/aesthetics.json
|
||||
613e64b44bed959da899fdd54c1cacb227fb33f2 data/create/advancements/andesite_alloy.json
|
||||
81885c6bfb85792c88aaa7c9b70f58832945d31f data/create/advancements/andesite_casing.json
|
||||
83c046bd200623933545c9e4326f782fb02c87fa data/create/advancements/arm_blaze_burner.json
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
"trigger": "create:bracket_apply",
|
||||
"conditions": {
|
||||
"accepted_entries": [
|
||||
"create:cogwheel",
|
||||
"create:large_cogwheel"
|
||||
"create:large_cogwheel",
|
||||
"create:cogwheel"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
|
@ -41,7 +41,7 @@ public class AllEntityTypes {
|
|||
GantryContraptionEntity::new, () -> ContraptionEntityRenderer::new, 10, 40, false);
|
||||
public static final EntityEntry<CarriageContraptionEntity> CARRIAGE_CONTRAPTION =
|
||||
contraption("carriage_contraption", CarriageContraptionEntity::new,
|
||||
() -> CarriageContraptionEntityRenderer::new, 5, 3, true);
|
||||
() -> CarriageContraptionEntityRenderer::new, 15, 3, true);
|
||||
|
||||
public static final EntityEntry<SuperGlueEntity> SUPER_GLUE =
|
||||
register("super_glue", SuperGlueEntity::new, () -> SuperGlueRenderer::new, MobCategory.MISC, 10,
|
||||
|
|
|
@ -5,6 +5,9 @@ import java.util.Collection;
|
|||
import java.util.HashSet;
|
||||
import java.util.Vector;
|
||||
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.ControlsUtil;
|
||||
|
@ -13,6 +16,7 @@ import com.simibubi.create.foundation.utility.Lang;
|
|||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class ControlsHandler {
|
||||
|
||||
|
@ -24,6 +28,13 @@ public class ControlsHandler {
|
|||
static WeakReference<AbstractContraptionEntity> entityRef = new WeakReference<>(null);
|
||||
static BlockPos controlsPos;
|
||||
|
||||
public static void levelUnloaded(LevelAccessor level) {
|
||||
packetCooldown = 0;
|
||||
entityRef = new WeakReference<>(null);
|
||||
controlsPos = null;
|
||||
currentlyPressed.clear();
|
||||
}
|
||||
|
||||
public static void startControlling(AbstractContraptionEntity entity, BlockPos controllerLocalPos) {
|
||||
entityRef = new WeakReference<AbstractContraptionEntity>(entity);
|
||||
controlsPos = controllerLocalPos;
|
||||
|
@ -36,10 +47,10 @@ public class ControlsHandler {
|
|||
ControlsUtil.getControls()
|
||||
.forEach(kb -> kb.setDown(ControlsUtil.isActuallyPressed(kb)));
|
||||
AbstractContraptionEntity abstractContraptionEntity = entityRef.get();
|
||||
|
||||
|
||||
if (!currentlyPressed.isEmpty() && abstractContraptionEntity != null)
|
||||
AllPackets.channel.sendToServer(
|
||||
new ControlsInputPacket(currentlyPressed, false, abstractContraptionEntity.getId(), controlsPos));
|
||||
AllPackets.channel.sendToServer(new ControlsInputPacket(currentlyPressed, false,
|
||||
abstractContraptionEntity.getId(), controlsPos, false));
|
||||
|
||||
packetCooldown = 0;
|
||||
entityRef = new WeakReference<>(null);
|
||||
|
@ -57,6 +68,16 @@ public class ControlsHandler {
|
|||
if (packetCooldown > 0)
|
||||
packetCooldown--;
|
||||
|
||||
if (InputConstants.isKeyDown(Minecraft.getInstance()
|
||||
.getWindow()
|
||||
.getWindow(), GLFW.GLFW_KEY_ESCAPE)) {
|
||||
BlockPos pos = controlsPos;
|
||||
stopControlling();
|
||||
AllPackets.channel
|
||||
.sendToServer(new ControlsInputPacket(currentlyPressed, false, entity.getId(), pos, true));
|
||||
return;
|
||||
}
|
||||
|
||||
Vector<KeyMapping> controls = ControlsUtil.getControls();
|
||||
Collection<Integer> pressedKeys = new HashSet<>();
|
||||
for (int i = 0; i < controls.size(); i++) {
|
||||
|
@ -71,13 +92,14 @@ public class ControlsHandler {
|
|||
|
||||
// Released Keys
|
||||
if (!releasedKeys.isEmpty()) {
|
||||
AllPackets.channel.sendToServer(new ControlsInputPacket(releasedKeys, false, entity.getId(), controlsPos));
|
||||
AllPackets.channel
|
||||
.sendToServer(new ControlsInputPacket(releasedKeys, false, entity.getId(), controlsPos, false));
|
||||
// AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .5f, true);
|
||||
}
|
||||
|
||||
// Newly Pressed Keys
|
||||
if (!newKeys.isEmpty()) {
|
||||
AllPackets.channel.sendToServer(new ControlsInputPacket(newKeys, true, entity.getId(), controlsPos));
|
||||
AllPackets.channel.sendToServer(new ControlsInputPacket(newKeys, true, entity.getId(), controlsPos, false));
|
||||
packetCooldown = PACKET_RATE;
|
||||
// AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .75f, true);
|
||||
}
|
||||
|
@ -86,7 +108,7 @@ public class ControlsHandler {
|
|||
if (packetCooldown == 0) {
|
||||
if (!pressedKeys.isEmpty()) {
|
||||
AllPackets.channel
|
||||
.sendToServer(new ControlsInputPacket(pressedKeys, true, entity.getId(), controlsPos));
|
||||
.sendToServer(new ControlsInputPacket(pressedKeys, true, entity.getId(), controlsPos, false));
|
||||
packetCooldown = PACKET_RATE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,15 @@ public class ControlsInputPacket extends SimplePacketBase {
|
|||
private boolean press;
|
||||
private int contraptionEntityId;
|
||||
private BlockPos controlsPos;
|
||||
private boolean stopControlling;
|
||||
|
||||
public ControlsInputPacket(Collection<Integer> activatedButtons, boolean press, int contraptionEntityId,
|
||||
BlockPos controlsPos) {
|
||||
BlockPos controlsPos, boolean stopControlling) {
|
||||
this.contraptionEntityId = contraptionEntityId;
|
||||
this.activatedButtons = activatedButtons;
|
||||
this.press = press;
|
||||
this.controlsPos = controlsPos;
|
||||
this.stopControlling = stopControlling;
|
||||
}
|
||||
|
||||
public ControlsInputPacket(FriendlyByteBuf buffer) {
|
||||
|
@ -39,6 +41,7 @@ public class ControlsInputPacket extends SimplePacketBase {
|
|||
for (int i = 0; i < size; i++)
|
||||
activatedButtons.add(buffer.readVarInt());
|
||||
controlsPos = buffer.readBlockPos();
|
||||
stopControlling = buffer.readBoolean();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +51,7 @@ public class ControlsInputPacket extends SimplePacketBase {
|
|||
buffer.writeVarInt(activatedButtons.size());
|
||||
activatedButtons.forEach(buffer::writeVarInt);
|
||||
buffer.writeBlockPos(controlsPos);
|
||||
buffer.writeBoolean(stopControlling);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,11 +68,14 @@ public class ControlsInputPacket extends SimplePacketBase {
|
|||
Entity entity = world.getEntity(contraptionEntityId);
|
||||
if (!(entity instanceof AbstractContraptionEntity ace))
|
||||
return;
|
||||
if (!ace.toGlobalVector(Vec3.atCenterOf(controlsPos), 0)
|
||||
.closerThan(player.position(), 16))
|
||||
if (stopControlling) {
|
||||
ace.stopControlling(controlsPos);
|
||||
return;
|
||||
}
|
||||
|
||||
ControlsServerHandler.receivePressed(world, ace, controlsPos, uniqueID, activatedButtons, press);
|
||||
if (ace.toGlobalVector(Vec3.atCenterOf(controlsPos), 0)
|
||||
.closerThan(player.position(), 16))
|
||||
ControlsServerHandler.receivePressed(world, ace, controlsPos, uniqueID, activatedButtons, press);
|
||||
});
|
||||
ctx.setPacketHandled(true);
|
||||
}
|
||||
|
|
|
@ -49,7 +49,8 @@ public class NixieTubeBlock extends DoubleFaceAttachedBlock
|
|||
public NixieTubeBlock(Properties properties, DyeColor color) {
|
||||
super(properties);
|
||||
this.color = color;
|
||||
registerDefaultState(defaultBlockState().setValue(FACE, DoubleAttachFace.FLOOR));
|
||||
registerDefaultState(defaultBlockState().setValue(FACE, DoubleAttachFace.FLOOR)
|
||||
.setValue(WATERLOGGED, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,7 +2,6 @@ package com.simibubi.create.content.logistics.trains;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
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;
|
||||
|
|
|
@ -57,6 +57,8 @@ public class GlobalRailwayManager {
|
|||
}
|
||||
}
|
||||
|
||||
public void playerLogout(Player player) {}
|
||||
|
||||
public void levelLoaded(LevelAccessor level) {
|
||||
MinecraftServer server = level.getServer();
|
||||
if (server == null || server.overworld() != level)
|
||||
|
@ -75,13 +77,6 @@ public class GlobalRailwayManager {
|
|||
signalEdgeGroups = savedData.getSignalBlocks();
|
||||
}
|
||||
|
||||
public void levelUnloaded(LevelAccessor level) {
|
||||
// MinecraftServer server = level.getServer();
|
||||
// if (server == null || server.overworld() != level)
|
||||
// return;
|
||||
// cleanUp();
|
||||
}
|
||||
|
||||
public void cleanUp() {
|
||||
trackNetworks = new HashMap<>();
|
||||
signalEdgeGroups = new HashMap<>();
|
||||
|
|
|
@ -136,9 +136,12 @@ public class Carriage {
|
|||
ISignalBoundaryListener passiveListener = point.ignoreSignals();
|
||||
|
||||
toMove += correction + bogeyCorrection;
|
||||
double moved = point.travel(graph, toMove, toMove > 0 ? frontTrackSelector : backTrackSelector,
|
||||
toMove > 0 ? atFront ? frontListener : atBack ? backListener : passiveListener
|
||||
: atFront ? backListener : atBack ? frontListener : passiveListener);
|
||||
double moved =
|
||||
point
|
||||
.travel(graph, toMove, toMove > 0 ? frontTrackSelector : backTrackSelector,
|
||||
toMove > 0 ? atFront ? frontListener : atBack ? backListener : passiveListener
|
||||
: atFront ? backListener : atBack ? frontListener : passiveListener,
|
||||
point.ignoreTurns());
|
||||
blocked |= point.blocked;
|
||||
|
||||
distanceMoved.setValue(moved);
|
||||
|
@ -227,8 +230,17 @@ public class Carriage {
|
|||
entity.setPos(positionAnchor);
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
|
||||
entity.yaw = (float) (Mth.atan2(diffZ, diffX) * 180 / Math.PI) + 180;
|
||||
entity.pitch = (float) (Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)) * 180 / Math.PI) * -1;
|
||||
|
||||
if (entity.firstPositionUpdate) {
|
||||
entity.xo = entity.getX();
|
||||
entity.yo = entity.getY();
|
||||
entity.zo = entity.getZ();
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
}
|
||||
}
|
||||
|
||||
public TravellingPoint getLeadingPoint() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
|||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.foundation.utility.AngleHelper;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
|
||||
|
@ -62,9 +63,15 @@ public class CarriageBogey {
|
|||
xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)));
|
||||
}
|
||||
|
||||
wheelAngle.setValue((wheelAngle.getValue() - angleDiff) % 360);
|
||||
pitch.setValue(xRot);
|
||||
yaw.setValue(-yRot);
|
||||
double newWheelAngle = (wheelAngle.getValue() - angleDiff) % 360;
|
||||
|
||||
for (boolean twice : Iterate.trueAndFalse) {
|
||||
if (twice && !entity.firstPositionUpdate)
|
||||
continue;
|
||||
wheelAngle.setValue(newWheelAngle);
|
||||
pitch.setValue(xRot);
|
||||
yaw.setValue(-yRot);
|
||||
}
|
||||
}
|
||||
|
||||
public TravellingPoint leading() {
|
||||
|
|
|
@ -32,6 +32,8 @@ import net.minecraft.world.level.Level;
|
|||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
public class CarriageContraption extends Contraption {
|
||||
|
||||
|
@ -177,6 +179,7 @@ public class CarriageContraption extends Contraption {
|
|||
}
|
||||
|
||||
@Override
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public ContraptionLighter<?> makeLighter() {
|
||||
return new NonStationaryLighter<>(this);
|
||||
}
|
||||
|
|
|
@ -61,10 +61,12 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
public boolean movingBackwards;
|
||||
|
||||
public boolean leftTickingChunks;
|
||||
public boolean firstPositionUpdate;
|
||||
|
||||
public CarriageContraptionEntity(EntityType<?> type, Level world) {
|
||||
super(type, world);
|
||||
validForRender = false;
|
||||
firstPositionUpdate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -172,12 +174,15 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
carriage.alignEntity(this);
|
||||
|
||||
Vec3 diff = position().subtract(xo, yo, zo);
|
||||
Vec3 relativeDiff = VecHelper.rotate(diff, yaw, Axis.Y);
|
||||
double signum = Math.signum(-relativeDiff.x);
|
||||
double distanceTo = diff.length() * signum;
|
||||
double distanceTo = 0;
|
||||
if (!firstPositionUpdate) {
|
||||
Vec3 diff = position().subtract(xo, yo, zo);
|
||||
Vec3 relativeDiff = VecHelper.rotate(diff, yaw, Axis.Y);
|
||||
double signum = Math.signum(-relativeDiff.x);
|
||||
distanceTo = diff.length() * signum;
|
||||
movingBackwards = signum < 0;
|
||||
}
|
||||
|
||||
movingBackwards = signum < 0;
|
||||
carriage.bogeys.getFirst()
|
||||
.updateAngles(this, distanceTo);
|
||||
if (carriage.isOnTwoBogeys())
|
||||
|
@ -187,6 +192,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
if (carriage.train.derailed)
|
||||
spawnDerailParticles(carriage);
|
||||
|
||||
firstPositionUpdate = false;
|
||||
validForRender = true;
|
||||
}
|
||||
|
||||
|
@ -200,6 +206,18 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClientRemoval() {
|
||||
super.onClientRemoval();
|
||||
entityData.set(CARRIAGE_DATA, new CarriageSyncData());
|
||||
if (carriage != null) {
|
||||
carriage.pointsInitialised = false;
|
||||
carriage.leadingBogey().couplingAnchors = Couple.create(null, null);
|
||||
carriage.trailingBogey().couplingAnchors = Couple.create(null, null);
|
||||
}
|
||||
firstPositionUpdate = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void writeAdditional(CompoundTag compound, boolean spawnPacket) {
|
||||
super.writeAdditional(compound, spawnPacket);
|
||||
|
@ -250,7 +268,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
return false;
|
||||
if (carriage.train.derailed)
|
||||
return false;
|
||||
if (!level.isClientSide && carriage.train.heldForAssembly) {
|
||||
if (carriage.train.heldForAssembly) {
|
||||
player.displayClientMessage(Lang.translate("schedule.train_still_assembling"), true);
|
||||
return false;
|
||||
}
|
||||
|
@ -260,6 +278,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
train.status.manualControls();
|
||||
train.navigation.cancelNavigation();
|
||||
train.runtime.paused = true;
|
||||
train.navigation.waitingForSignal = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -347,7 +366,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
if (lookAhead != null) {
|
||||
if (spaceDown) {
|
||||
nav.startNavigation(lookAhead, false);
|
||||
nav.startNavigation(lookAhead, -1, false);
|
||||
navDistanceTotal = nav.distanceToDestination;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
bogey.couplingAnchors.replace(v -> null);
|
||||
if (!super.shouldRender(entity, clippingHelper, cameraX, cameraY, cameraZ))
|
||||
return false;
|
||||
return entity.validForRender;
|
||||
return entity.validForRender && !entity.firstPositionUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -239,8 +239,8 @@ public class CarriageSyncData {
|
|||
TravellingPoint toApproach = pointsToApproach[index];
|
||||
|
||||
point.travel(graph, partial * f,
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)),
|
||||
point.ignoreSignals());
|
||||
point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)), point.ignoreSignals(),
|
||||
point.ignoreTurns());
|
||||
|
||||
// could not pathfind to server location
|
||||
if (!success.booleanValue()) {
|
||||
|
|
|
@ -6,10 +6,14 @@ import java.util.IdentityHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.PriorityQueue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
|
@ -49,6 +53,7 @@ public class Navigation {
|
|||
private TravellingPoint signalScout;
|
||||
public Pair<UUID, Boolean> waitingForSignal;
|
||||
public double distanceToSignal;
|
||||
public int ticksWaitingForSignal;
|
||||
|
||||
public Navigation(Train train) {
|
||||
this.train = train;
|
||||
|
@ -84,9 +89,11 @@ public class Navigation {
|
|||
destination.reserveFor(train);
|
||||
|
||||
double acceleration = AllConfigs.SERVER.trains.getAccelerationMPTT();
|
||||
double turnTopSpeed = AllConfigs.SERVER.trains.getTurningTopSpeedMPT();
|
||||
double brakingDistance = (train.speed * train.speed) / (2 * acceleration);
|
||||
double speedMod = destinationBehindTrain ? -1 : 1;
|
||||
double preDepartureLookAhead = train.getCurrentStation() != null ? 4.5 : 0;
|
||||
double distanceToNextCurve = -1;
|
||||
|
||||
// Signals
|
||||
if (train.graph != null) {
|
||||
|
@ -98,10 +105,14 @@ public class Navigation {
|
|||
: train.carriages.get(train.carriages.size() - 1)
|
||||
.getTrailingPoint();
|
||||
|
||||
if (waitingForSignal == null)
|
||||
if (waitingForSignal == null) {
|
||||
distanceToSignal = Double.MAX_VALUE;
|
||||
ticksWaitingForSignal = 0;
|
||||
}
|
||||
|
||||
if (distanceToSignal > 1 / 16f) {
|
||||
MutableDouble curveDistanceTracker = new MutableDouble(-1);
|
||||
|
||||
signalScout.node1 = leadingPoint.node1;
|
||||
signalScout.node2 = leadingPoint.node2;
|
||||
signalScout.edge = leadingPoint.edge;
|
||||
|
@ -124,7 +135,15 @@ public class Navigation {
|
|||
return;
|
||||
}
|
||||
signalEdgeGroup.reserved = boundary;
|
||||
}, (distance, edge) -> {
|
||||
float current = curveDistanceTracker.floatValue();
|
||||
if (current == -1 || distance < current)
|
||||
curveDistanceTracker.setValue(distance);
|
||||
});
|
||||
|
||||
distanceToNextCurve = curveDistanceTracker.floatValue();
|
||||
} else {
|
||||
ticksWaitingForSignal++;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -165,7 +184,17 @@ public class Navigation {
|
|||
}
|
||||
}
|
||||
|
||||
train.targetSpeed = targetDistance > brakingDistance ? topSpeed * speedMod : 0;
|
||||
double targetSpeed = targetDistance > brakingDistance ? topSpeed * speedMod : 0;
|
||||
|
||||
if (distanceToNextCurve != -1) {
|
||||
double slowingDistance = brakingDistance - (turnTopSpeed * turnTopSpeed) / (2 * acceleration);
|
||||
double targetTurnSpeed =
|
||||
distanceToNextCurve > slowingDistance ? topSpeed * speedMod : turnTopSpeed * speedMod;
|
||||
if (Math.abs(targetTurnSpeed) < Math.abs(targetSpeed))
|
||||
targetSpeed = targetTurnSpeed;
|
||||
}
|
||||
|
||||
train.targetSpeed = targetSpeed;
|
||||
train.approachTargetSpeed(1);
|
||||
}
|
||||
|
||||
|
@ -228,16 +257,17 @@ public class Navigation {
|
|||
train.runtime.transitInterrupted();
|
||||
}
|
||||
|
||||
public double startNavigation(GlobalStation destination, boolean simulate) {
|
||||
Pair<Double, List<Couple<TrackNode>>> pathTo = findPathTo(destination);
|
||||
boolean noneFound = pathTo.getFirst() == null;
|
||||
double distance = noneFound ? -1 : Math.abs(pathTo.getFirst());
|
||||
public double startNavigation(GlobalStation destination, double maxCost, boolean simulate) {
|
||||
DiscoveredPath pathTo = findPathTo(destination, maxCost);
|
||||
boolean noneFound = pathTo == null;
|
||||
double distance = noneFound ? -1 : Math.abs(pathTo.distance);
|
||||
double cost = noneFound ? -1 : pathTo.cost;
|
||||
|
||||
if (simulate)
|
||||
return distance;
|
||||
return cost;
|
||||
|
||||
distanceToDestination = distance;
|
||||
currentPath = pathTo.getSecond();
|
||||
currentPath = pathTo.path;
|
||||
|
||||
if (noneFound) {
|
||||
distanceToDestination = 0;
|
||||
|
@ -246,7 +276,7 @@ public class Navigation {
|
|||
return -1;
|
||||
}
|
||||
|
||||
destinationBehindTrain = pathTo.getFirst() < 0;
|
||||
destinationBehindTrain = pathTo.distance < 0;
|
||||
|
||||
if (this.destination == destination)
|
||||
return 0;
|
||||
|
@ -274,24 +304,20 @@ public class Navigation {
|
|||
}
|
||||
|
||||
this.destination = destination;
|
||||
return distanceToDestination;
|
||||
return cost;
|
||||
}
|
||||
|
||||
private Pair<Double, List<Couple<TrackNode>>> findPathTo(GlobalStation destination) {
|
||||
@Nullable
|
||||
private DiscoveredPath findPathTo(GlobalStation destination, double maxCost) {
|
||||
TrackGraph graph = train.graph;
|
||||
List<Couple<TrackNode>> path = new ArrayList<>();
|
||||
|
||||
if (graph == null)
|
||||
return Pair.of(null, path);
|
||||
|
||||
MutableObject<Pair<Double, List<Couple<TrackNode>>>> frontResult = new MutableObject<>(Pair.of(null, path));
|
||||
MutableObject<Pair<Double, List<Couple<TrackNode>>>> backResult = new MutableObject<>(Pair.of(null, path));
|
||||
return null;
|
||||
|
||||
Couple<DiscoveredPath> results = Couple.create(null, null);
|
||||
for (boolean forward : Iterate.trueAndFalse) {
|
||||
if (this.destination == destination && destinationBehindTrain == forward)
|
||||
continue;
|
||||
|
||||
List<Couple<TrackNode>> currentPath = new ArrayList<>();
|
||||
TravellingPoint initialPoint = forward ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
|
@ -300,7 +326,7 @@ public class Navigation {
|
|||
: graph.getConnectionsFrom(initialPoint.node2)
|
||||
.get(initialPoint.node1);
|
||||
|
||||
search(Double.MAX_VALUE, forward, (distance, reachedVia, currentEntry, globalStation) -> {
|
||||
search(Double.MAX_VALUE, maxCost, forward, (distance, cost, reachedVia, currentEntry, globalStation) -> {
|
||||
if (globalStation != destination)
|
||||
return false;
|
||||
|
||||
|
@ -310,6 +336,7 @@ public class Navigation {
|
|||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
List<Couple<TrackNode>> currentPath = new ArrayList<>();
|
||||
Pair<Boolean, Couple<TrackNode>> backTrack = reachedVia.get(edge);
|
||||
Couple<TrackNode> toReach = Couple.create(node1, node2);
|
||||
TrackEdge edgeReached = edge;
|
||||
|
@ -325,11 +352,7 @@ public class Navigation {
|
|||
|
||||
double position = edge.getLength(node1, node2) - destination.getLocationOn(node1, node2, edge);
|
||||
double distanceToDestination = distance - position;
|
||||
|
||||
if (forward)
|
||||
frontResult.setValue(Pair.of(distanceToDestination, currentPath));
|
||||
else
|
||||
backResult.setValue(Pair.of(-distanceToDestination, currentPath));
|
||||
results.set(forward, new DiscoveredPath((forward ? 1 : -1) * distanceToDestination, cost, currentPath));
|
||||
return true;
|
||||
});
|
||||
|
||||
|
@ -337,11 +360,11 @@ public class Navigation {
|
|||
break;
|
||||
}
|
||||
|
||||
Pair<Double, List<Couple<TrackNode>>> front = frontResult.getValue();
|
||||
Pair<Double, List<Couple<TrackNode>>> back = backResult.getValue();
|
||||
DiscoveredPath front = results.getFirst();
|
||||
DiscoveredPath back = results.getSecond();
|
||||
|
||||
boolean frontEmpty = front.getFirst() == null;
|
||||
boolean backEmpty = back.getFirst() == null;
|
||||
boolean frontEmpty = front == null;
|
||||
boolean backEmpty = back == null;
|
||||
if (backEmpty)
|
||||
return front;
|
||||
if (frontEmpty)
|
||||
|
@ -354,10 +377,22 @@ public class Navigation {
|
|||
if (!canDriveForward)
|
||||
return back;
|
||||
|
||||
boolean frontBetter = -back.getFirst() > front.getFirst();
|
||||
boolean frontBetter = maxCost == -1 ? -back.distance > front.distance : back.cost > front.cost;
|
||||
return frontBetter ? front : back;
|
||||
}
|
||||
|
||||
public class DiscoveredPath {
|
||||
List<Couple<TrackNode>> path;
|
||||
double distance;
|
||||
double cost;
|
||||
|
||||
public DiscoveredPath(double distance, double cost, List<Couple<TrackNode>> path) {
|
||||
this.distance = distance;
|
||||
this.cost = cost;
|
||||
this.path = path;
|
||||
}
|
||||
}
|
||||
|
||||
public GlobalStation findNearestApproachable(boolean forward) {
|
||||
TrackGraph graph = train.graph;
|
||||
if (graph == null)
|
||||
|
@ -368,7 +403,7 @@ public class Navigation {
|
|||
double minDistance = .75f * (train.speed * train.speed) / (2 * acceleration);
|
||||
double maxDistance = Math.max(32, 1.5f * (train.speed * train.speed) / (2 * acceleration));
|
||||
|
||||
search(maxDistance, forward, (distance, reachedVia, currentEntry, globalStation) -> {
|
||||
search(maxDistance, forward, (distance, cost, reachedVia, currentEntry, globalStation) -> {
|
||||
if (distance < minDistance)
|
||||
return false;
|
||||
|
||||
|
@ -389,10 +424,36 @@ public class Navigation {
|
|||
}
|
||||
|
||||
public void search(double maxDistance, boolean forward, StationTest stationTest) {
|
||||
search(maxDistance, -1, forward, stationTest);
|
||||
}
|
||||
|
||||
public void search(double maxDistance, double maxCost, boolean forward, StationTest stationTest) {
|
||||
TrackGraph graph = train.graph;
|
||||
if (graph == null)
|
||||
return;
|
||||
|
||||
Map<TrackEdge, Integer> penalties = new IdentityHashMap<>();
|
||||
boolean costRelevant = maxCost >= 0;
|
||||
if (costRelevant) {
|
||||
for (Train otherTrain : Create.RAILWAYS.trains.values()) {
|
||||
if (otherTrain.graph != graph)
|
||||
continue;
|
||||
int navigationPenalty = otherTrain.getNavigationPenalty();
|
||||
otherTrain.getEndpointEdges()
|
||||
.forEach(nodes -> {
|
||||
if (nodes.either(Objects::isNull))
|
||||
return;
|
||||
for (boolean flip : Iterate.trueAndFalse) {
|
||||
TrackEdge e = graph.getConnection(flip ? nodes.swap() : nodes);
|
||||
if (e == null)
|
||||
continue;
|
||||
int existing = penalties.getOrDefault(e, 0);
|
||||
penalties.put(e, existing + navigationPenalty / 2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TravellingPoint startingPoint = forward ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
|
@ -400,8 +461,7 @@ public class Navigation {
|
|||
|
||||
Set<TrackEdge> visited = new HashSet<>();
|
||||
Map<TrackEdge, Pair<Boolean, Couple<TrackNode>>> reachedVia = new IdentityHashMap<>();
|
||||
PriorityQueue<Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> frontier =
|
||||
new PriorityQueue<>((p1, p2) -> Double.compare(p1.getFirst(), p2.getFirst()));
|
||||
PriorityQueue<FrontierEntry> frontier = new PriorityQueue<>();
|
||||
|
||||
TrackNode initialNode1 = forward ? startingPoint.node1 : startingPoint.node2;
|
||||
TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1;
|
||||
|
@ -410,20 +470,23 @@ public class Navigation {
|
|||
double distanceToNode2 = forward ? initialEdge.getLength(initialNode1, initialNode2) - startingPoint.position
|
||||
: startingPoint.position;
|
||||
|
||||
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
||||
frontier.add(new FrontierEntry(distanceToNode2, 0, initialNode1, initialNode2, initialEdge));
|
||||
|
||||
Search: while (!frontier.isEmpty()) {
|
||||
Pair<Double, Pair<Couple<TrackNode>, TrackEdge>> poll = frontier.poll();
|
||||
double distance = poll.getFirst();
|
||||
FrontierEntry entry = frontier.poll();
|
||||
|
||||
double distance = entry.distance;
|
||||
int penalty = entry.penalty;
|
||||
|
||||
if (distance > maxDistance)
|
||||
continue;
|
||||
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
TrackEdge edge = entry.edge;
|
||||
TrackNode node1 = entry.node1;
|
||||
TrackNode node2 = entry.node2;
|
||||
|
||||
if (costRelevant)
|
||||
penalty += penalties.getOrDefault(edge, 0);
|
||||
|
||||
EdgeData signalData = edge.getEdgeData();
|
||||
if (signalData.hasPoints()) {
|
||||
|
@ -431,44 +494,78 @@ public class Navigation {
|
|||
if (node1 == initialNode1
|
||||
&& point.getLocationOn(node1, node2, edge) < edge.getLength(node1, node2) - distanceToNode2)
|
||||
continue;
|
||||
if (costRelevant && distance + penalty > maxCost)
|
||||
continue Search;
|
||||
if (!point.canNavigateVia(node2))
|
||||
continue Search;
|
||||
if (point instanceof GlobalStation station && station.canApproachFrom(node2)
|
||||
&& stationTest.test(distance, reachedVia, currentEntry, station))
|
||||
return;
|
||||
if (point instanceof GlobalStation station) {
|
||||
if (station.getPresentTrain() != null)
|
||||
penalty += Train.Penalties.STATION_WITH_TRAIN;
|
||||
if (station.canApproachFrom(node2) && stationTest.test(distance, distance + penalty, reachedVia,
|
||||
Pair.of(Couple.create(node1, node2), edge), station))
|
||||
return;
|
||||
penalty += Train.Penalties.STATION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (costRelevant && distance + penalty > maxCost)
|
||||
continue;
|
||||
|
||||
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
|
||||
Map<TrackNode, TrackEdge> connectionsFrom = graph.getConnectionsFrom(node2);
|
||||
for (Entry<TrackNode, TrackEdge> entry : connectionsFrom.entrySet()) {
|
||||
TrackNode newNode = entry.getKey();
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
for (Entry<TrackNode, TrackEdge> connection : connectionsFrom.entrySet()) {
|
||||
TrackNode newNode = connection.getKey();
|
||||
TrackEdge newEdge = connection.getValue();
|
||||
Vec3 currentDirection = edge.getDirection(node1, node2, false);
|
||||
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||
continue;
|
||||
if (!visited.add(entry.getValue()))
|
||||
if (!visited.add(connection.getValue()))
|
||||
continue;
|
||||
validTargets.add(entry);
|
||||
validTargets.add(connection);
|
||||
}
|
||||
|
||||
if (validTargets.isEmpty())
|
||||
continue;
|
||||
|
||||
for (Entry<TrackNode, TrackEdge> entry : validTargets) {
|
||||
TrackNode newNode = entry.getKey();
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
for (Entry<TrackNode, TrackEdge> target : validTargets) {
|
||||
TrackNode newNode = target.getKey();
|
||||
TrackEdge newEdge = target.getValue();
|
||||
double newDistance = newEdge.getLength(node2, newNode) + distance;
|
||||
int newPenalty = penalty;
|
||||
reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, Couple.create(node1, node2)));
|
||||
frontier.add(Pair.of(newEdge.getLength(node2, newNode) + distance,
|
||||
Pair.of(Couple.create(node2, newNode), newEdge)));
|
||||
frontier.add(new FrontierEntry(newDistance, newPenalty, node2, newNode, newEdge));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FrontierEntry implements Comparable<FrontierEntry> {
|
||||
|
||||
double distance;
|
||||
int penalty;
|
||||
TrackNode node1;
|
||||
TrackNode node2;
|
||||
TrackEdge edge;
|
||||
|
||||
public FrontierEntry(double distance, int penalty, TrackNode node1, TrackNode node2, TrackEdge edge) {
|
||||
this.distance = distance;
|
||||
this.penalty = penalty;
|
||||
this.node1 = node1;
|
||||
this.node2 = node2;
|
||||
this.edge = edge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(FrontierEntry o) {
|
||||
return Double.compare(distance + penalty, o.distance + o.penalty);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface StationTest {
|
||||
boolean test(double distance, Map<TrackEdge, Pair<Boolean, Couple<TrackNode>>> reachedVia,
|
||||
boolean test(double distance, double cost, Map<TrackEdge, Pair<Boolean, Couple<TrackNode>>> reachedVia,
|
||||
Pair<Couple<TrackNode>, TrackEdge> current, GlobalStation station);
|
||||
}
|
||||
|
||||
|
@ -491,6 +588,7 @@ public class Navigation {
|
|||
tag.putUUID("BlockingSignal", waitingForSignal.getFirst());
|
||||
tag.putBoolean("BlockingSignalSide", waitingForSignal.getSecond());
|
||||
tag.putDouble("DistanceToSignal", distanceToSignal);
|
||||
tag.putInt("TicksWaitingForSignal", ticksWaitingForSignal);
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -513,6 +611,7 @@ public class Navigation {
|
|||
if (waitingForSignal == null)
|
||||
return;
|
||||
distanceToSignal = tag.getDouble("DistanceToSignal");
|
||||
ticksWaitingForSignal = tag.getInt("TicksWaitingForSignal");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import com.simibubi.create.content.logistics.trains.management.schedule.Schedule
|
|||
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime.State;
|
||||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
@ -246,24 +247,34 @@ public class Train {
|
|||
}
|
||||
|
||||
private void updateNavigationTarget(double distance) {
|
||||
if (navigation.destination != null) {
|
||||
boolean recalculate = navigation.distanceToDestination % 100 > 20;
|
||||
boolean imminentRecalculate = navigation.distanceToDestination > 5;
|
||||
double toSubstract = navigation.destinationBehindTrain ? -distance : distance;
|
||||
navigation.distanceToDestination -= toSubstract;
|
||||
boolean signalMode = navigation.waitingForSignal != null;
|
||||
if (navigation.destination == null)
|
||||
return;
|
||||
|
||||
boolean recalculate = navigation.distanceToDestination % 100 > 20;
|
||||
boolean imminentRecalculate = navigation.distanceToDestination > 5;
|
||||
double toSubstract = navigation.destinationBehindTrain ? -distance : distance;
|
||||
navigation.distanceToDestination -= toSubstract;
|
||||
boolean signalMode = navigation.waitingForSignal != null;
|
||||
boolean navigatingManually = runtime.paused;
|
||||
|
||||
if (signalMode) {
|
||||
navigation.distanceToSignal -= toSubstract;
|
||||
recalculate = navigation.distanceToSignal % 100 > 20;
|
||||
}
|
||||
|
||||
if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20
|
||||
|| imminentRecalculate && navigation.distanceToDestination <= 5) {
|
||||
if (signalMode) {
|
||||
navigation.distanceToSignal -= toSubstract;
|
||||
recalculate = navigation.distanceToSignal % 100 > 20;
|
||||
navigation.waitingForSignal = null;
|
||||
return;
|
||||
}
|
||||
if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20
|
||||
|| imminentRecalculate && navigation.distanceToDestination <= 5) {
|
||||
if (signalMode) {
|
||||
navigation.waitingForSignal = null;
|
||||
return;
|
||||
}
|
||||
navigation.startNavigation(navigation.destination, false);
|
||||
GlobalStation destination = navigation.destination;
|
||||
if (!navigatingManually) {
|
||||
GlobalStation preferredDestination = runtime.findNextStation();
|
||||
if (preferredDestination != null)
|
||||
destination = preferredDestination;
|
||||
}
|
||||
navigation.startNavigation(destination, navigatingManually ? -1 : Double.MAX_VALUE, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -680,11 +691,36 @@ public class Train {
|
|||
return;
|
||||
occupiedSignalBlocks.add(id);
|
||||
prevGroup.setValue(id);
|
||||
}));
|
||||
}), signalScout.ignoreTurns());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public Couple<Couple<TrackNode>> getEndpointEdges() {
|
||||
return Couple.create(carriages.get(0)
|
||||
.getLeadingPoint(),
|
||||
carriages.get(carriages.size() - 1)
|
||||
.getTrailingPoint())
|
||||
.map(tp -> Couple.create(tp.node1, tp.node2));
|
||||
}
|
||||
|
||||
public static class Penalties {
|
||||
static final int STATION = 200, STATION_WITH_TRAIN = 300;
|
||||
static final int MANUAL_TRAIN = 200, IDLE_TRAIN = 700, ARRIVING_TRAIN = 50, WAITING_TRAIN = 50, ANY_TRAIN = 25;
|
||||
}
|
||||
|
||||
public int getNavigationPenalty() {
|
||||
if (manualTick)
|
||||
return Penalties.MANUAL_TRAIN;
|
||||
if (runtime.getSchedule() == null || runtime.paused)
|
||||
return Penalties.IDLE_TRAIN;
|
||||
if (navigation.waitingForSignal != null && navigation.ticksWaitingForSignal > 0)
|
||||
return Penalties.WAITING_TRAIN + Math.min(navigation.ticksWaitingForSignal / 20, 1000);
|
||||
if (navigation.destination != null && navigation.distanceToDestination < 50 || navigation.distanceToSignal < 20)
|
||||
return Penalties.ARRIVING_TRAIN;
|
||||
return Penalties.ANY_TRAIN;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("Id", id);
|
||||
|
|
|
@ -24,6 +24,7 @@ import com.simibubi.create.content.logistics.trains.TrackGraphHelper;
|
|||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ISignalBoundaryListener;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
||||
import com.simibubi.create.foundation.item.TooltipHelper;
|
||||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
|
@ -63,7 +64,7 @@ public class TrainRelocator {
|
|||
public static boolean isRelocating() {
|
||||
return relocatingTrain != null;
|
||||
}
|
||||
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onClicked(ClickInputEvent event) {
|
||||
if (relocatingTrain == null)
|
||||
|
@ -105,7 +106,7 @@ public class TrainRelocator {
|
|||
return null;
|
||||
BlockPos blockPos = blockhit.getBlockPos();
|
||||
|
||||
if (simulate && toVisualise != null) {
|
||||
if (simulate && toVisualise != null && lastHoveredResult != null) {
|
||||
for (int i = 0; i < toVisualise.size() - 1; i++) {
|
||||
Vec3 vec1 = toVisualise.get(i);
|
||||
Vec3 vec2 = toVisualise.get(i + 1);
|
||||
|
@ -158,6 +159,7 @@ public class TrainRelocator {
|
|||
|
||||
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position);
|
||||
ISignalBoundaryListener ignoreSignals = probe.ignoreSignals();
|
||||
ITurnListener ignoreTurns = probe.ignoreTurns();
|
||||
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();
|
||||
List<Vec3> recordedVecs = new ArrayList<>();
|
||||
Consumer<TravellingPoint> recorder = tp -> {
|
||||
|
@ -171,7 +173,7 @@ public class TrainRelocator {
|
|||
train.forEachTravellingPointBackwards((tp, d) -> {
|
||||
if (blocked.booleanValue())
|
||||
return;
|
||||
probe.travel(graph, d, steer, ignoreSignals);
|
||||
probe.travel(graph, d, steer, ignoreSignals, ignoreTurns);
|
||||
recorder.accept(probe);
|
||||
if (probe.blocked) {
|
||||
blocked.setTrue();
|
||||
|
|
|
@ -56,6 +56,9 @@ public class TravellingPoint {
|
|||
public static interface ISignalBoundaryListener extends BiConsumer<Double, Pair<SignalBoundary, Couple<UUID>>> {
|
||||
};
|
||||
|
||||
public static interface ITurnListener extends BiConsumer<Double, TrackEdge> {
|
||||
};
|
||||
|
||||
public TravellingPoint() {}
|
||||
|
||||
public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) {
|
||||
|
@ -70,6 +73,11 @@ public class TravellingPoint {
|
|||
};
|
||||
}
|
||||
|
||||
public ITurnListener ignoreTurns() {
|
||||
return (d, c) -> {
|
||||
};
|
||||
}
|
||||
|
||||
public ITrackSelector random() {
|
||||
return (graph, pair) -> pair.getSecond()
|
||||
.get(Create.RANDOM.nextInt(pair.getSecond()
|
||||
|
@ -170,7 +178,7 @@ public class TravellingPoint {
|
|||
}
|
||||
|
||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||
ISignalBoundaryListener signalListener) {
|
||||
ISignalBoundaryListener signalListener, ITurnListener turnListener) {
|
||||
blocked = false;
|
||||
double edgeLength = edge.getLength(node1, node2);
|
||||
if (distance == 0)
|
||||
|
@ -185,7 +193,7 @@ public class TravellingPoint {
|
|||
|
||||
boolean forward = distance > 0;
|
||||
double collectedDistance = forward ? -prevPos : -edgeLength + prevPos;
|
||||
edgeTraversedFrom(graph, forward, signalListener, prevPos, collectedDistance);
|
||||
edgeTraversedFrom(graph, forward, signalListener, turnListener, prevPos, collectedDistance);
|
||||
|
||||
if (forward) {
|
||||
// Moving forward
|
||||
|
@ -223,7 +231,9 @@ public class TravellingPoint {
|
|||
position -= edgeLength;
|
||||
|
||||
collectedDistance += edgeLength;
|
||||
edgeTraversedFrom(graph, forward, signalListener, 0, collectedDistance);
|
||||
if (edge.isTurn())
|
||||
turnListener.accept(collectedDistance, edge);
|
||||
edgeTraversedFrom(graph, forward, signalListener, turnListener, 0, collectedDistance);
|
||||
prevPos = 0;
|
||||
|
||||
edgeLength = edge.getLength(node1, node2);
|
||||
|
@ -268,7 +278,7 @@ public class TravellingPoint {
|
|||
edgeLength = edge.getLength(node1, node2);
|
||||
position += edgeLength;
|
||||
|
||||
edgeTraversedFrom(graph, forward, signalListener, edgeLength, collectedDistance);
|
||||
edgeTraversedFrom(graph, forward, signalListener, turnListener, edgeLength, collectedDistance);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -277,7 +287,10 @@ public class TravellingPoint {
|
|||
}
|
||||
|
||||
private void edgeTraversedFrom(TrackGraph graph, boolean forward, ISignalBoundaryListener signalListener,
|
||||
double prevPos, double totalDistance) {
|
||||
ITurnListener turnListener, double prevPos, double totalDistance) {
|
||||
if (edge.isTurn())
|
||||
turnListener.accept(Math.max(0, totalDistance), edge);
|
||||
|
||||
EdgeData signalsOnEdge = edge.getEdgeData();
|
||||
if (!signalsOnEdge.hasSignalBoundaries())
|
||||
return;
|
||||
|
|
|
@ -97,7 +97,7 @@ public class ScheduleRuntime {
|
|||
destinationReached();
|
||||
return;
|
||||
}
|
||||
if (train.navigation.startNavigation(nextStation, false) != -1)
|
||||
if (train.navigation.startNavigation(nextStation, Double.MAX_VALUE, false) != -1)
|
||||
state = State.IN_TRANSIT;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ public class ScheduleRuntime {
|
|||
if (!globalStation.name.matches(regex))
|
||||
continue;
|
||||
boolean matchesCurrent = train.currentStation != null && train.currentStation.equals(globalStation.id);
|
||||
double cost = matchesCurrent ? 0 : train.navigation.startNavigation(globalStation, true);
|
||||
double cost = matchesCurrent ? 0 : train.navigation.startNavigation(globalStation, bestCost, true);
|
||||
if (cost < 0)
|
||||
continue;
|
||||
if (cost > bestCost)
|
||||
|
|
|
@ -58,9 +58,10 @@ public class TrackBlockItem extends BlockItem {
|
|||
}
|
||||
|
||||
boolean placing = !(state.getBlock() instanceof ITrackBlock);
|
||||
if (placing && !state.getMaterial()
|
||||
.isReplaceable()) {
|
||||
pos = pos.relative(pContext.getClickedFace());
|
||||
if (placing) {
|
||||
if (!state.getMaterial()
|
||||
.isReplaceable())
|
||||
pos = pos.relative(pContext.getClickedFace());
|
||||
state = getPlacementState(pContext);
|
||||
if (state == null)
|
||||
return InteractionResult.FAIL;
|
||||
|
|
|
@ -6,12 +6,11 @@ import java.util.Map;
|
|||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
import com.simibubi.create.content.curiosities.girder.GirderBlock;
|
||||
import com.simibubi.create.content.logistics.trains.BezierConnection;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
@ -33,7 +32,7 @@ public class TrackPaver {
|
|||
if (defaultBlockState.hasProperty(SlabBlock.TYPE))
|
||||
defaultBlockState = defaultBlockState.setValue(SlabBlock.TYPE, SlabType.DOUBLE);
|
||||
boolean wallLike = isWallLike(defaultBlockState);
|
||||
|
||||
|
||||
if (defaultBlockState.getBlock() instanceof GirderBlock)
|
||||
for (Direction d : Iterate.horizontalDirections)
|
||||
if (Vec3.atLowerCornerOf(d.getNormal())
|
||||
|
@ -144,9 +143,9 @@ public class TrackPaver {
|
|||
int floor = Mth.floor(yValue);
|
||||
boolean placeSlab = slab && yValue - floor >= .5;
|
||||
BlockPos targetPos = new BlockPos(entry.getKey()
|
||||
.getKey(), floor,
|
||||
.getFirst(), floor,
|
||||
entry.getKey()
|
||||
.getValue());
|
||||
.getSecond());
|
||||
targetPos = targetPos.offset(tePosition)
|
||||
.above(placeSlab ? 1 : 0);
|
||||
BlockState stateToPlace =
|
||||
|
|
|
@ -159,14 +159,13 @@ public class ClientEvents {
|
|||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRenderSelection(DrawSelectionEvent event) {
|
||||
}
|
||||
public static void onRenderSelection(DrawSelectionEvent event) {}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onJoin(ClientPlayerNetworkEvent.LoggedInEvent event) {
|
||||
CreateClient.checkGraphicsFanciness();
|
||||
}
|
||||
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onLeave(ClientPlayerNetworkEvent.LoggedOutEvent event) {
|
||||
CreateClient.RAILWAYS.cleanUp();
|
||||
|
@ -183,12 +182,13 @@ public class ClientEvents {
|
|||
|
||||
@SubscribeEvent
|
||||
public static void onUnloadWorld(WorldEvent.Unload event) {
|
||||
if (event.getWorld()
|
||||
.isClientSide()) {
|
||||
CreateClient.invalidateRenderers();
|
||||
CreateClient.SOUL_PULSE_EFFECT_HANDLER.refresh();
|
||||
AnimationTickHolder.reset();
|
||||
}
|
||||
if (!event.getWorld()
|
||||
.isClientSide())
|
||||
return;
|
||||
CreateClient.invalidateRenderers();
|
||||
CreateClient.SOUL_PULSE_EFFECT_HANDLER.refresh();
|
||||
AnimationTickHolder.reset();
|
||||
ControlsHandler.levelUnloaded(event.getWorld());
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
@ -281,13 +281,15 @@ public class ClientEvents {
|
|||
|
||||
Fluid fluid = fluidstate.getType();
|
||||
|
||||
if (AllFluids.CHOCOLATE.get().isSame(fluid)) {
|
||||
if (AllFluids.CHOCOLATE.get()
|
||||
.isSame(fluid)) {
|
||||
event.setDensity(5f);
|
||||
event.setCanceled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (AllFluids.HONEY.get().isSame(fluid)) {
|
||||
if (AllFluids.HONEY.get()
|
||||
.isSame(fluid)) {
|
||||
event.setDensity(1.5f);
|
||||
event.setCanceled(true);
|
||||
return;
|
||||
|
@ -307,18 +309,20 @@ public class ClientEvents {
|
|||
Level level = Minecraft.getInstance().level;
|
||||
BlockPos blockPos = info.getBlockPosition();
|
||||
FluidState fluidstate = level.getFluidState(blockPos);
|
||||
if (info.getPosition().y > blockPos.getY() + fluidstate.getHeight(level, blockPos))
|
||||
return;
|
||||
if (info.getPosition().y > blockPos.getY() + fluidstate.getHeight(level, blockPos))
|
||||
return;
|
||||
|
||||
Fluid fluid = fluidstate.getType();
|
||||
|
||||
if (AllFluids.CHOCOLATE.get().isSame(fluid)) {
|
||||
if (AllFluids.CHOCOLATE.get()
|
||||
.isSame(fluid)) {
|
||||
event.setRed(98 / 256f);
|
||||
event.setGreen(32 / 256f);
|
||||
event.setBlue(32 / 256f);
|
||||
}
|
||||
|
||||
if (AllFluids.HONEY.get().isSame(fluid)) {
|
||||
if (AllFluids.HONEY.get()
|
||||
.isSame(fluid)) {
|
||||
event.setRed(234 / 256f);
|
||||
event.setGreen(174 / 256f);
|
||||
event.setBlue(47 / 256f);
|
||||
|
|
|
@ -49,6 +49,7 @@ import net.minecraftforge.event.entity.living.LivingEvent.LivingUpdateEvent;
|
|||
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedInEvent;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent.PlayerLoggedOutEvent;
|
||||
import net.minecraftforge.event.server.ServerStoppingEvent;
|
||||
import net.minecraftforge.event.world.BiomeLoadingEvent;
|
||||
import net.minecraftforge.event.world.BlockEvent.FluidPlaceBlockEvent;
|
||||
|
@ -82,6 +83,12 @@ public class CommonEvents {
|
|||
ToolboxHandler.playerLogin(player);
|
||||
Create.RAILWAYS.playerLogin(player);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void playerLoggedOut(PlayerLoggedOutEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
Create.RAILWAYS.playerLogout(player);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void whenFluidsMeet(FluidPlaceBlockEvent event) {
|
||||
|
@ -188,7 +195,6 @@ public class CommonEvents {
|
|||
Create.REDSTONE_LINK_NETWORK_HANDLER.onUnloadWorld(world);
|
||||
Create.TORQUE_PROPAGATOR.onUnloadWorld(world);
|
||||
WorldAttached.invalidateWorld(world);
|
||||
Create.RAILWAYS.levelUnloaded(world);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
|
|
|
@ -2,19 +2,24 @@ package com.simibubi.create.foundation.config;
|
|||
|
||||
public class CTrains extends ConfigBase {
|
||||
|
||||
public final ConfigFloat trainTopSpeed = f(40, 0, "trainTopSpeed", Comments.mps, Comments.trainTopSpeed);
|
||||
public final ConfigFloat trainAcceleration =
|
||||
f(6, 0, "trainAcceleration", Comments.acc, Comments.trainAcceleration);
|
||||
public final ConfigFloat trainTopSpeed = f(36, 0, "trainTopSpeed", Comments.mps, Comments.trainTopSpeed);
|
||||
public final ConfigFloat trainTurningTopSpeed =
|
||||
f(18, 0, "trainTurningTopSpeed", Comments.mps, Comments.trainTurningTopSpeed);
|
||||
public final ConfigFloat trainAcceleration = f(4, 0, "trainAcceleration", Comments.acc, Comments.trainAcceleration);
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "trains";
|
||||
}
|
||||
|
||||
|
||||
public double getTopSpeedMPT() {
|
||||
return trainTopSpeed.getF() / 20;
|
||||
}
|
||||
|
||||
|
||||
public double getTurningTopSpeedMPT() {
|
||||
return trainTurningTopSpeed.getF() / 20;
|
||||
}
|
||||
|
||||
public double getAccelerationMPTT() {
|
||||
return trainAcceleration.getF() / 400;
|
||||
}
|
||||
|
@ -23,6 +28,7 @@ public class CTrains extends ConfigBase {
|
|||
static String mps = "[in Blocks/Second]";
|
||||
static String acc = "[in Blocks/Second²]";
|
||||
static String trainTopSpeed = "The top speed of any assembled Train.";
|
||||
static String trainTurningTopSpeed = "The top speed of Trains during a turn.";
|
||||
static String trainAcceleration = "The acceleration of any assembled Train.";
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import java.util.Random;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.jozufozu.flywheel.repack.joml.Math;
|
||||
import com.mojang.math.Quaternion;
|
||||
import com.mojang.math.Vector3f;
|
||||
|
||||
|
|
Loading…
Reference in a new issue