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