Reincartnated
- Trains now get saved to disk - Trains now sync raw position data to clients while in the derailed state - Trains can no longer be relocated into another train - Train relocation now shows indicators - Fixed single-bogey carriages not sending enough position context when derailed
This commit is contained in:
parent
ed6712fd0b
commit
9e0f35e4d7
34 changed files with 611 additions and 175 deletions
|
@ -541,21 +541,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
|
|||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||
255e47ab7894ba35851a2f34c82be3dc9c9e8784 assets/create/lang/en_ud.json
|
||||
3610238d5807c0d4f04a7632a871487ba8cc2c1f assets/create/lang/en_us.json
|
||||
6a67c98238de2e57b5f2b36b3e988e70616c2ab0 assets/create/lang/unfinished/de_de.json
|
||||
f9cb3ca070daff2503223de083c95e7e176b10fd assets/create/lang/unfinished/es_cl.json
|
||||
35bb65eb644b10adbf55bc03913db056bc88f32c assets/create/lang/unfinished/es_es.json
|
||||
9e7c2ea229f44ff57fc7ba2bc6f94638d2a68af0 assets/create/lang/unfinished/fr_fr.json
|
||||
0e4bc37cd97dd28107593eb11d936101a2a3ebb6 assets/create/lang/unfinished/it_it.json
|
||||
11034cb1b7e049c403f4a1e4774c2e1611af5b10 assets/create/lang/unfinished/ja_jp.json
|
||||
626ef47b3ee504f922b6fa7cde416ae284f22236 assets/create/lang/unfinished/ko_kr.json
|
||||
1025d8531ada9f4a521aba15a153de59a3bfd596 assets/create/lang/unfinished/nl_nl.json
|
||||
4113a74ef44f7c30285b578eea239fee70646702 assets/create/lang/unfinished/pl_pl.json
|
||||
ecb8680bae4a7ce8c6e7f1ae45f74992a6f152a6 assets/create/lang/unfinished/pt_br.json
|
||||
db520fa1663bbecea9e39a1acfa6514740e74445 assets/create/lang/unfinished/pt_pt.json
|
||||
718e9841f70866b4fbbe397f8fdd1600e2c044a8 assets/create/lang/unfinished/ru_ru.json
|
||||
c8094e8ebf65b51fe1156955e2968709543c0592 assets/create/lang/unfinished/zh_cn.json
|
||||
949a8d2f792ff994dbe2339dda5d08543d62fd55 assets/create/lang/unfinished/zh_tw.json
|
||||
b908dd7c47b286d05a57b8a58c60051363ffff86 assets/create/lang/en_us.json
|
||||
29ad91d27ee183b9d4de8d152d0fb8ed2a388a0c assets/create/lang/unfinished/de_de.json
|
||||
8d33ba82d3cca307c5ae0dda41a49ec16f1c7b74 assets/create/lang/unfinished/es_cl.json
|
||||
ae674553b564a9e09a7d10c9c2d8c1be1307f40a assets/create/lang/unfinished/es_es.json
|
||||
318149855f383fb90439f2f0818e8e83fee3924e assets/create/lang/unfinished/fr_fr.json
|
||||
e7321dbe8f98c96e778b5c46823c98500b3001bc assets/create/lang/unfinished/it_it.json
|
||||
5a2da425fd0dd276c3d7cf66f6bb43f229574306 assets/create/lang/unfinished/ja_jp.json
|
||||
98fc1956e8b25aec27e889ada3a160800b958dfd assets/create/lang/unfinished/ko_kr.json
|
||||
67cefb6690f5cccce93d776a760ebdadc7f2631e assets/create/lang/unfinished/nl_nl.json
|
||||
9a7f4d369d2a54aaf5c422fae740244025a13af4 assets/create/lang/unfinished/pl_pl.json
|
||||
3656897ffc5c89bf16a32ad11efe33cd5b4bfb23 assets/create/lang/unfinished/pt_br.json
|
||||
c84995ec524b6469fc42f39574be21b9dbee24e3 assets/create/lang/unfinished/pt_pt.json
|
||||
bcf41d9fd8454296dc56326b6e26ee41e2ad52e5 assets/create/lang/unfinished/ru_ru.json
|
||||
d3dfdab017748fa82f9e952a35bd6e82fe063771 assets/create/lang/unfinished/zh_cn.json
|
||||
dda3aee2ece5503edd53dbd4aa9db7363e4beafc assets/create/lang/unfinished/zh_tw.json
|
||||
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
|
||||
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
|
||||
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
|
||||
|
|
|
@ -1421,7 +1421,7 @@
|
|||
"create.train.relocate.abort": "Relocation aborted",
|
||||
"create.train.relocate.success": "Relocation successful",
|
||||
"create.train.relocate.valid": "Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -1422,7 +1422,7 @@
|
|||
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
|
||||
"create.train.relocate.success": "UNLOCALIZED: Relocation successful",
|
||||
"create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||
|
|
|
@ -64,8 +64,8 @@ public class ControlsInputPacket extends SimplePacketBase {
|
|||
Entity entity = world.getEntity(contraptionEntityId);
|
||||
if (!(entity instanceof AbstractContraptionEntity ace))
|
||||
return;
|
||||
if (ace.toGlobalVector(Vec3.atCenterOf(controlsPos), 0)
|
||||
.distanceTo(player.position()) > 10)
|
||||
if (!ace.toGlobalVector(Vec3.atCenterOf(controlsPos), 0)
|
||||
.closerThan(player.position(), 16))
|
||||
return;
|
||||
|
||||
ControlsServerHandler.receivePressed(world, ace, controlsPos, uniqueID, activatedButtons, press);
|
||||
|
|
|
@ -53,7 +53,7 @@ public class GlobalRailwayManager {
|
|||
sync.sendEdgeGroups(signalEdgeGroups.keySet(), serverPlayer);
|
||||
for (Train train : trains.values())
|
||||
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> serverPlayer),
|
||||
new TrainPacket(train, false));
|
||||
new TrainPacket(train, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,7 @@ public class GlobalRailwayManager {
|
|||
if (savedData != null)
|
||||
return;
|
||||
savedData = RailwaySavedData.load(server);
|
||||
trains = savedData.getTrains();
|
||||
trackNetworks = savedData.getTrackNetworks();
|
||||
signalEdgeGroups = savedData.getSignalBlocks();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import java.util.Map;
|
|||
import java.util.UUID;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
|
@ -17,23 +18,33 @@ public class RailwaySavedData extends SavedData {
|
|||
|
||||
private Map<UUID, TrackGraph> trackNetworks = new HashMap<>();
|
||||
private Map<UUID, SignalEdgeGroup> signalEdgeGroups = new HashMap<>();
|
||||
private Map<UUID, Train> trains = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public CompoundTag save(CompoundTag nbt) {
|
||||
nbt.put("RailGraphs", NBTHelper.writeCompoundList(Create.RAILWAYS.trackNetworks.values(), TrackGraph::write));
|
||||
GlobalRailwayManager railways = Create.RAILWAYS;
|
||||
Create.LOGGER.info("Saving Railway Information...");
|
||||
nbt.put("RailGraphs", NBTHelper.writeCompoundList(railways.trackNetworks.values(), TrackGraph::write));
|
||||
nbt.put("SignalBlocks",
|
||||
NBTHelper.writeCompoundList(Create.RAILWAYS.signalEdgeGroups.values(), SignalEdgeGroup::write));
|
||||
NBTHelper.writeCompoundList(railways.signalEdgeGroups.values(), SignalEdgeGroup::write));
|
||||
nbt.put("Trains", NBTHelper.writeCompoundList(railways.trains.values(), Train::write));
|
||||
return nbt;
|
||||
}
|
||||
|
||||
private static RailwaySavedData load(CompoundTag nbt) {
|
||||
RailwaySavedData sd = new RailwaySavedData();//TODO load trains before everything else
|
||||
RailwaySavedData sd = new RailwaySavedData();
|
||||
sd.trackNetworks = new HashMap<>();
|
||||
sd.signalEdgeGroups = new HashMap<>();
|
||||
sd.trains = new HashMap<>();
|
||||
Create.LOGGER.info("Loading Railway Information...");
|
||||
NBTHelper.iterateCompoundList(nbt.getList("RailGraphs", Tag.TAG_COMPOUND), c -> {
|
||||
TrackGraph graph = TrackGraph.read(c);
|
||||
sd.trackNetworks.put(graph.id, graph);
|
||||
});
|
||||
NBTHelper.iterateCompoundList(nbt.getList("Trains", Tag.TAG_COMPOUND), c -> {
|
||||
Train train = Train.read(c, sd.trackNetworks);
|
||||
sd.trains.put(train.id, train);
|
||||
});
|
||||
NBTHelper.iterateCompoundList(nbt.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> {
|
||||
SignalEdgeGroup group = SignalEdgeGroup.read(c);
|
||||
sd.signalEdgeGroups.put(group.id, group);
|
||||
|
@ -45,6 +56,10 @@ public class RailwaySavedData extends SavedData {
|
|||
return trackNetworks;
|
||||
}
|
||||
|
||||
public Map<UUID, Train> getTrains() {
|
||||
return trains;
|
||||
}
|
||||
|
||||
public Map<UUID, SignalEdgeGroup> getSignalBlocks() {
|
||||
return signalEdgeGroups;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.
|
|||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
@ -307,6 +308,10 @@ public class TrackGraph {
|
|||
return connectionsByNode.getOrDefault(node, new HashMap<>());
|
||||
}
|
||||
|
||||
public TrackEdge getConnection(Couple<TrackNode> nodes) {
|
||||
return getConnectionsFrom(nodes.getFirst()).get(nodes.getSecond());
|
||||
}
|
||||
|
||||
public void connectNodes(TrackNodeLocation location, TrackNodeLocation location2, TrackEdge edge) {
|
||||
TrackNode node1 = nodes.get(location);
|
||||
TrackNode node2 = nodes.get(location2);
|
||||
|
|
|
@ -15,9 +15,11 @@ import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ISign
|
|||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Entity.RemovalReason;
|
||||
|
@ -37,7 +39,10 @@ public class Carriage {
|
|||
public Couple<Boolean> presentConductors;
|
||||
|
||||
public int bogeySpacing;
|
||||
Couple<CarriageBogey> bogeys;
|
||||
public Couple<CarriageBogey> bogeys;
|
||||
|
||||
public Vec3 positionAnchor;
|
||||
public Couple<Vec3> rotationAnchors;
|
||||
|
||||
CompoundTag serialisedEntity;
|
||||
WeakReference<CarriageContraptionEntity> entity;
|
||||
|
@ -54,6 +59,9 @@ public class Carriage {
|
|||
this.id = netIdGenerator.incrementAndGet();
|
||||
this.serialisedEntity = new CompoundTag();
|
||||
this.pointsInitialised = false;
|
||||
this.rotationAnchors = Couple.create(null, null);
|
||||
|
||||
updateContraptionAnchors();
|
||||
|
||||
bogey1.carriage = this;
|
||||
if (bogey2 != null)
|
||||
|
@ -69,9 +77,7 @@ public class Carriage {
|
|||
entity.setCarriage(this);
|
||||
contraption.startMoving(level);
|
||||
contraption.onEntityInitialize(level, entity);
|
||||
for (CarriageBogey carriageBogey : bogeys)
|
||||
if (carriageBogey != null)
|
||||
carriageBogey.updateAnchorPosition();
|
||||
updateContraptionAnchors();
|
||||
alignEntity(entity);
|
||||
|
||||
List<Entity> players = new ArrayList<>();
|
||||
|
@ -89,10 +95,8 @@ public class Carriage {
|
|||
public double travel(Level level, TrackGraph graph, double distance,
|
||||
Function<TravellingPoint, ITrackSelector> forwardControl,
|
||||
Function<TravellingPoint, ITrackSelector> backwardControl, int type) {
|
||||
Vec3 leadingAnchor = leadingBogey().anchorPosition;
|
||||
Vec3 trailingAnchor = trailingBogey().anchorPosition;
|
||||
boolean onTwoBogeys = isOnTwoBogeys();
|
||||
double stress = onTwoBogeys ? bogeySpacing - leadingAnchor.distanceTo(trailingAnchor) : 0;
|
||||
double stress = onTwoBogeys ? bogeySpacing - leadingAnchor().distanceTo(trailingAnchor()) : 0;
|
||||
blocked = false;
|
||||
|
||||
MutableDouble distanceMoved = new MutableDouble(distance);
|
||||
|
@ -139,13 +143,11 @@ public class Carriage {
|
|||
|
||||
distanceMoved.setValue(moved);
|
||||
}
|
||||
|
||||
bogey.updateAnchorPosition();
|
||||
}
|
||||
|
||||
double actualMovement = distanceMoved.getValue();
|
||||
manageEntity(level, actualMovement);
|
||||
return actualMovement;
|
||||
updateContraptionAnchors();
|
||||
manageEntity(level);
|
||||
return distanceMoved.getValue();
|
||||
}
|
||||
|
||||
public void updateConductors() {
|
||||
|
@ -162,7 +164,7 @@ public class Carriage {
|
|||
if (!(entity instanceof CarriageContraptionEntity cce))
|
||||
return;
|
||||
|
||||
Vec3 pos = leadingBogey().anchorPosition;
|
||||
Vec3 pos = positionAnchor;
|
||||
cce.setPos(pos);
|
||||
cce.setCarriage(this);
|
||||
cce.setGraph(train.graph == null ? null : train.graph.id);
|
||||
|
@ -171,10 +173,10 @@ public class Carriage {
|
|||
}
|
||||
|
||||
public ChunkPos getChunk() {
|
||||
return new ChunkPos(new BlockPos(leadingBogey().anchorPosition));
|
||||
return new ChunkPos(new BlockPos(positionAnchor));
|
||||
}
|
||||
|
||||
protected void manageEntity(Level level, double actualMovement) {
|
||||
public void manageEntity(Level level) {
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity == null) {
|
||||
if (CarriageEntityHandler.isActiveChunk(level, getChunk()))
|
||||
|
@ -182,12 +184,7 @@ public class Carriage {
|
|||
} else {
|
||||
CarriageEntityHandler.validateCarriageEntity(entity);
|
||||
if (!entity.isAlive() || entity.leftTickingChunks) {
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
if (!(passenger instanceof Player))
|
||||
passenger.remove(RemovalReason.UNLOADED_WITH_PLAYER);
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
entity.discard();
|
||||
this.entity.clear();
|
||||
removeAndSaveEntity(entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -200,19 +197,34 @@ public class Carriage {
|
|||
entity.syncCarriage();
|
||||
}
|
||||
|
||||
private void removeAndSaveEntity(CarriageContraptionEntity entity) {
|
||||
for (Entity passenger : entity.getPassengers())
|
||||
if (!(passenger instanceof Player))
|
||||
passenger.remove(RemovalReason.UNLOADED_WITH_PLAYER);
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
entity.discard();
|
||||
this.entity.clear();
|
||||
}
|
||||
|
||||
public void updateContraptionAnchors() {
|
||||
CarriageBogey leadingBogey = leadingBogey();
|
||||
if (leadingBogey.points.either(t -> t.edge == null))
|
||||
return;
|
||||
positionAnchor = leadingBogey.getAnchorPosition();
|
||||
rotationAnchors = bogeys.mapWithContext((b, first) -> isOnTwoBogeys() ? b.getAnchorPosition()
|
||||
: leadingBogey.points.get(first)
|
||||
.getPosition());
|
||||
}
|
||||
|
||||
public void alignEntity(CarriageContraptionEntity entity) {
|
||||
Vec3 positionVec = isOnTwoBogeys() ? leadingBogey().anchorPosition
|
||||
: leadingBogey().leading()
|
||||
.getPosition();
|
||||
Vec3 coupledVec = isOnTwoBogeys() ? trailingBogey().anchorPosition
|
||||
: leadingBogey().trailing()
|
||||
.getPosition();
|
||||
Vec3 positionVec = rotationAnchors.getFirst();
|
||||
Vec3 coupledVec = rotationAnchors.getSecond();
|
||||
|
||||
double diffX = positionVec.x - coupledVec.x;
|
||||
double diffY = positionVec.y - coupledVec.y;
|
||||
double diffZ = positionVec.z - coupledVec.z;
|
||||
|
||||
entity.setPos(leadingBogey().anchorPosition);
|
||||
entity.setPos(positionAnchor);
|
||||
entity.prevYaw = entity.yaw;
|
||||
entity.prevPitch = entity.pitch;
|
||||
entity.yaw = (float) (Mth.atan2(diffZ, diffX) * 180 / Math.PI) + 180;
|
||||
|
@ -239,4 +251,54 @@ public class Carriage {
|
|||
return bogeys.getSecond() != null;
|
||||
}
|
||||
|
||||
public Vec3 leadingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getFirst() : positionAnchor;
|
||||
}
|
||||
|
||||
public Vec3 trailingAnchor() {
|
||||
return isOnTwoBogeys() ? rotationAnchors.getSecond() : positionAnchor;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.put("FirstBogey", bogeys.getFirst()
|
||||
.write());
|
||||
if (isOnTwoBogeys())
|
||||
tag.put("SecondBogey", bogeys.getSecond()
|
||||
.write());
|
||||
tag.putInt("Spacing", bogeySpacing);
|
||||
tag.putBoolean("FrontConductor", presentConductors.getFirst());
|
||||
tag.putBoolean("BackConductor", presentConductors.getSecond());
|
||||
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity != null)
|
||||
serialisedEntity = entity.serializeNBT();
|
||||
|
||||
tag.put("Entity", serialisedEntity.copy());
|
||||
tag.put("PositionAnchor", VecHelper.writeNBT(positionAnchor));
|
||||
tag.put("RotationAnchors", rotationAnchors.serializeEach(VecHelper::writeNBTCompound));
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static Carriage read(CompoundTag tag, TrackGraph graph) {
|
||||
CarriageBogey bogey1 = CarriageBogey.read(tag.getCompound("FirstBogey"), graph);
|
||||
CarriageBogey bogey2 =
|
||||
tag.contains("SecondBogey") ? CarriageBogey.read(tag.getCompound("SecondBogey"), graph) : null;
|
||||
|
||||
Carriage carriage = new Carriage(bogey1, bogey2, tag.getInt("Spacing"));
|
||||
|
||||
carriage.presentConductors = Couple.create(tag.getBoolean("FrontConductor"), tag.getBoolean("BackConductor"));
|
||||
carriage.serialisedEntity = tag.getCompound("Entity")
|
||||
.copy();
|
||||
|
||||
if (carriage.positionAnchor == null) {
|
||||
carriage.positionAnchor = VecHelper.readNBT(tag.getList("PositionAnchor", Tag.TAG_DOUBLE));
|
||||
carriage.rotationAnchors =
|
||||
Couple.deserializeEach(tag.getList("RotationAnchors", Tag.TAG_COMPOUND), VecHelper::readNBTCompound);
|
||||
}
|
||||
|
||||
return carriage;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
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.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
||||
public class CarriageBogey {
|
||||
|
||||
|
@ -17,14 +25,12 @@ public class CarriageBogey {
|
|||
|
||||
IBogeyBlock type;
|
||||
Couple<TravellingPoint> points;
|
||||
Vec3 anchorPosition;
|
||||
|
||||
LerpedFloat wheelAngle;
|
||||
LerpedFloat yaw;
|
||||
LerpedFloat pitch;
|
||||
|
||||
public Vec3 leadingCouplingAnchor;
|
||||
public Vec3 trailingCouplingAnchor;
|
||||
public Couple<Vec3> couplingAnchors;
|
||||
|
||||
int derailAngle;
|
||||
|
||||
|
@ -34,22 +40,27 @@ public class CarriageBogey {
|
|||
wheelAngle = LerpedFloat.angular();
|
||||
yaw = LerpedFloat.angular();
|
||||
pitch = LerpedFloat.angular();
|
||||
updateAnchorPosition();
|
||||
derailAngle = Create.RANDOM.nextInt(90) - 45;
|
||||
derailAngle = Create.RANDOM.nextInt(60) - 30;
|
||||
couplingAnchors = Couple.create(null, null);
|
||||
}
|
||||
|
||||
public void updateAngles(double distanceMoved) {
|
||||
public void updateAngles(CarriageContraptionEntity entity, double distanceMoved) {
|
||||
double angleDiff = 360 * distanceMoved / (Math.PI * 2 * type.getWheelRadius());
|
||||
Vec3 positionVec = leading().getPosition();
|
||||
Vec3 coupledVec = trailing().getPosition();
|
||||
double diffX = positionVec.x - coupledVec.x;
|
||||
double diffY = positionVec.y - coupledVec.y;
|
||||
double diffZ = positionVec.z - coupledVec.z;
|
||||
float yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90;
|
||||
float xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)));
|
||||
|
||||
if (carriage.train.derailed)
|
||||
yRot += derailAngle;
|
||||
float xRot = 0;
|
||||
float yRot = 0;
|
||||
|
||||
if (leading().edge == null || carriage.train.derailed) {
|
||||
yRot = -90 + entity.yaw - derailAngle;
|
||||
} else {
|
||||
Vec3 positionVec = leading().getPosition();
|
||||
Vec3 coupledVec = trailing().getPosition();
|
||||
double diffX = positionVec.x - coupledVec.x;
|
||||
double diffY = positionVec.y - coupledVec.y;
|
||||
double diffZ = positionVec.z - coupledVec.z;
|
||||
yRot = AngleHelper.deg(Mth.atan2(diffZ, diffX)) + 90;
|
||||
xRot = AngleHelper.deg(Math.atan2(diffY, Math.sqrt(diffX * diffX + diffZ * diffZ)));
|
||||
}
|
||||
|
||||
wheelAngle.setValue((wheelAngle.getValue() - angleDiff) % 360);
|
||||
pitch.setValue(xRot);
|
||||
|
@ -69,10 +80,11 @@ public class CarriageBogey {
|
|||
.distanceTo(trailing().getPosition());
|
||||
}
|
||||
|
||||
public void updateAnchorPosition() {
|
||||
if (points.getFirst().node1 == null)
|
||||
return;
|
||||
anchorPosition = points.getFirst()
|
||||
@Nullable
|
||||
public Vec3 getAnchorPosition() {
|
||||
if (leading().edge == null)
|
||||
return null;
|
||||
return points.getFirst()
|
||||
.getPosition()
|
||||
.add(points.getSecond()
|
||||
.getPosition())
|
||||
|
@ -94,10 +106,24 @@ public class CarriageBogey {
|
|||
thisOffset = VecHelper.rotate(thisOffset, -entityXRot, Axis.X);
|
||||
thisOffset = VecHelper.rotate(thisOffset, entityYRot + 90, Axis.Y);
|
||||
|
||||
if (leading)
|
||||
leadingCouplingAnchor = entityPos.add(thisOffset);
|
||||
else
|
||||
trailingCouplingAnchor = entityPos.add(thisOffset);
|
||||
couplingAnchors.set(leading, entityPos.add(thisOffset));
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putString("Type", ((Block) type).getRegistryName()
|
||||
.toString());
|
||||
tag.put("Points", points.serializeEach(TravellingPoint::write));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static CarriageBogey read(CompoundTag tag, TrackGraph graph) {
|
||||
ResourceLocation location = new ResourceLocation(tag.getString("Type"));
|
||||
IBogeyBlock type = (IBogeyBlock) ForgeRegistries.BLOCKS.getValue(location);
|
||||
Couple<TravellingPoint> points =
|
||||
Couple.deserializeEach(tag.getList("Points", Tag.TAG_COMPOUND), c -> TravellingPoint.read(c, graph));
|
||||
CarriageBogey carriageBogey = new CarriageBogey(type, points.getFirst(), points.getSecond());
|
||||
return carriageBogey;
|
||||
}
|
||||
|
||||
}
|
|
@ -163,11 +163,8 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
carriageData.approach(this, carriage, 1f / getType().updateInterval());
|
||||
|
||||
carriage.bogeys.getFirst()
|
||||
.updateAnchorPosition();
|
||||
if (carriage.isOnTwoBogeys())
|
||||
carriage.bogeys.getSecond()
|
||||
.updateAnchorPosition();
|
||||
if (!carriage.train.derailed)
|
||||
carriage.updateContraptionAnchors();
|
||||
|
||||
xo = getX();
|
||||
yo = getY();
|
||||
|
@ -182,10 +179,10 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
movingBackwards = signum < 0;
|
||||
carriage.bogeys.getFirst()
|
||||
.updateAngles(distanceTo);
|
||||
.updateAngles(this, distanceTo);
|
||||
if (carriage.isOnTwoBogeys())
|
||||
carriage.bogeys.getSecond()
|
||||
.updateAngles(distanceTo);
|
||||
.updateAngles(this, distanceTo);
|
||||
|
||||
if (carriage.train.derailed)
|
||||
spawnDerailParticles(carriage);
|
||||
|
@ -278,7 +275,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
return true;
|
||||
if (player.isSpectator())
|
||||
return false;
|
||||
if (!toGlobalVector(VecHelper.getCenterOf(controlsLocalPos), 1).closerThan(player.position(), 10))
|
||||
if (!toGlobalVector(VecHelper.getCenterOf(controlsLocalPos), 1).closerThan(player.position(), 8))
|
||||
return false;
|
||||
if (heldControls.contains(5))
|
||||
return false;
|
||||
|
|
|
@ -22,7 +22,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
|
|||
if (carriage != null)
|
||||
for (CarriageBogey bogey : carriage.bogeys)
|
||||
if (bogey != null)
|
||||
bogey.leadingCouplingAnchor = bogey.trailingCouplingAnchor = null;
|
||||
bogey.couplingAnchors.replace(v -> null);
|
||||
if (!super.shouldRender(entity, clippingHelper, cameraX, cameraY, cameraZ))
|
||||
return false;
|
||||
return entity.validForRender;
|
||||
|
|
|
@ -49,8 +49,8 @@ public class CarriageCouplingRenderer {
|
|||
|
||||
CarriageBogey bogey1 = carriage.trailingBogey();
|
||||
CarriageBogey bogey2 = carriage2.leadingBogey();
|
||||
Vec3 anchor = bogey1.trailingCouplingAnchor;
|
||||
Vec3 anchor2 = bogey2.leadingCouplingAnchor;
|
||||
Vec3 anchor = bogey1.couplingAnchors.getSecond();
|
||||
Vec3 anchor2 = bogey2.couplingAnchors.getFirst();
|
||||
|
||||
if (anchor == null || anchor2 == null)
|
||||
continue;
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.simibubi.create.content.logistics.trains.TrackNode;
|
|||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.Mth;
|
||||
|
@ -27,18 +28,22 @@ import net.minecraft.world.phys.Vec3;
|
|||
public class CarriageSyncData {
|
||||
|
||||
public Vector<Pair<Couple<Integer>, Float>> wheelLocations;
|
||||
public Pair<Vec3, Couple<Vec3>> fallbackLocations;
|
||||
public float distanceToDestination;
|
||||
public boolean leadingCarriage;
|
||||
|
||||
// For Client interpolation
|
||||
private Pair<Vec3, Couple<Vec3>> fallbackPointSnapshot;
|
||||
private TravellingPoint[] pointsToApproach;
|
||||
private float[] pointDistanceSnapshot;
|
||||
private float destinationDistanceSnapshot;
|
||||
|
||||
public CarriageSyncData() {
|
||||
wheelLocations = new Vector<>(4);
|
||||
fallbackLocations = null;
|
||||
pointDistanceSnapshot = new float[4];
|
||||
pointsToApproach = new TravellingPoint[4];
|
||||
fallbackPointSnapshot = null;
|
||||
destinationDistanceSnapshot = 0;
|
||||
leadingCarriage = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
|
@ -51,12 +56,26 @@ public class CarriageSyncData {
|
|||
CarriageSyncData data = new CarriageSyncData();
|
||||
for (int i = 0; i < 4; i++)
|
||||
data.wheelLocations.set(i, wheelLocations.get(i));
|
||||
if (fallbackLocations != null)
|
||||
data.fallbackLocations = fallbackLocations.copy();
|
||||
data.distanceToDestination = distanceToDestination;
|
||||
data.leadingCarriage = leadingCarriage;
|
||||
return data;
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf buffer) {
|
||||
buffer.writeBoolean(leadingCarriage);
|
||||
buffer.writeBoolean(fallbackLocations != null);
|
||||
|
||||
if (fallbackLocations != null) {
|
||||
Vec3 contraptionAnchor = fallbackLocations.getFirst();
|
||||
Couple<Vec3> rotationAnchors = fallbackLocations.getSecond();
|
||||
VecHelper.write(contraptionAnchor, buffer);
|
||||
VecHelper.write(rotationAnchors.getFirst(), buffer);
|
||||
VecHelper.write(rotationAnchors.getSecond(), buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
for (Pair<Couple<Integer>, Float> pair : wheelLocations) {
|
||||
buffer.writeBoolean(pair == null);
|
||||
if (pair == null)
|
||||
|
@ -66,24 +85,37 @@ public class CarriageSyncData {
|
|||
buffer.writeFloat(pair.getSecond());
|
||||
}
|
||||
buffer.writeFloat(distanceToDestination);
|
||||
buffer.writeBoolean(leadingCarriage);
|
||||
}
|
||||
|
||||
public void read(FriendlyByteBuf buffer) {
|
||||
leadingCarriage = buffer.readBoolean();
|
||||
boolean fallback = buffer.readBoolean();
|
||||
|
||||
if (fallback) {
|
||||
fallbackLocations =
|
||||
Pair.of(VecHelper.read(buffer), Couple.create(VecHelper.read(buffer), VecHelper.read(buffer)));
|
||||
return;
|
||||
}
|
||||
|
||||
fallbackLocations = null;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (buffer.readBoolean())
|
||||
break;
|
||||
wheelLocations.set(i, Pair.of(Couple.create(buffer::readInt), buffer.readFloat()));
|
||||
}
|
||||
distanceToDestination = buffer.readFloat();
|
||||
leadingCarriage = buffer.readBoolean();
|
||||
}
|
||||
|
||||
public void update(CarriageContraptionEntity entity, Carriage carriage) {
|
||||
TrackGraph graph = carriage.train.graph;
|
||||
if (graph == null)
|
||||
if (graph == null) {
|
||||
fallbackLocations = Pair.of(carriage.positionAnchor, carriage.rotationAnchors);
|
||||
carriage.pointsInitialised = true;
|
||||
setDirty(true);
|
||||
return;
|
||||
}
|
||||
|
||||
fallbackLocations = null;
|
||||
leadingCarriage = entity.carriageIndex == (carriage.train.speed >= 0 ? 0 : carriage.train.carriages.size() - 1);
|
||||
|
||||
for (boolean first : Iterate.trueAndFalse) {
|
||||
|
@ -104,6 +136,13 @@ public class CarriageSyncData {
|
|||
}
|
||||
|
||||
public void apply(CarriageContraptionEntity entity, Carriage carriage) {
|
||||
fallbackPointSnapshot = null;
|
||||
if (fallbackLocations != null) {
|
||||
fallbackPointSnapshot = Pair.of(carriage.positionAnchor, carriage.rotationAnchors);
|
||||
carriage.pointsInitialised = true;
|
||||
return;
|
||||
}
|
||||
|
||||
TrackGraph graph = carriage.train.graph;
|
||||
if (graph == null)
|
||||
return;
|
||||
|
@ -168,6 +207,17 @@ public class CarriageSyncData {
|
|||
}
|
||||
|
||||
public void approach(CarriageContraptionEntity entity, Carriage carriage, float partial) {
|
||||
if (fallbackLocations != null && fallbackPointSnapshot != null) {
|
||||
carriage.positionAnchor = approachVector(partial, carriage.positionAnchor, fallbackLocations.getFirst(),
|
||||
fallbackPointSnapshot.getFirst());
|
||||
carriage.rotationAnchors.replaceWithContext((current, first) -> approachVector(partial, current,
|
||||
fallbackLocations.getSecond()
|
||||
.get(first),
|
||||
fallbackPointSnapshot.getSecond()
|
||||
.get(first)));
|
||||
return;
|
||||
}
|
||||
|
||||
TrackGraph graph = carriage.train.graph;
|
||||
if (graph == null)
|
||||
return;
|
||||
|
@ -204,6 +254,13 @@ public class CarriageSyncData {
|
|||
}
|
||||
}
|
||||
|
||||
private Vec3 approachVector(float partial, Vec3 current, Vec3 target, Vec3 snapshot) {
|
||||
if (current == null || snapshot == null)
|
||||
return target;
|
||||
return current.add(target.subtract(snapshot)
|
||||
.scale(partial));
|
||||
}
|
||||
|
||||
public float getDistanceTo(TrackGraph graph, TravellingPoint current, TravellingPoint target, float maxDistance,
|
||||
boolean forward) {
|
||||
if (maxDistance == -1)
|
||||
|
|
|
@ -16,6 +16,7 @@ import com.simibubi.create.Create;
|
|||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
|
@ -26,18 +27,24 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.station
|
|||
import com.simibubi.create.foundation.config.AllConfigs;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class Navigation {
|
||||
|
||||
Train train;
|
||||
public Train train;
|
||||
|
||||
public GlobalStation destination;
|
||||
public double distanceToDestination;
|
||||
public boolean destinationBehindTrain;
|
||||
List<TrackEdge> currentPath;
|
||||
List<Couple<TrackNode>> currentPath;
|
||||
|
||||
private TravellingPoint signalScout;
|
||||
public Pair<UUID, Boolean> waitingForSignal;
|
||||
|
@ -186,39 +193,29 @@ public class Navigation {
|
|||
public ITrackSelector control(TravellingPoint mp) {
|
||||
if (destination == null)
|
||||
return mp.steer(train.manualSteer, new Vec3(0, 1, 0));
|
||||
return (graph, pair) -> {
|
||||
List<Entry<TrackNode, TrackEdge>> options = pair.getSecond();
|
||||
if (currentPath.isEmpty())
|
||||
return options.get(0);
|
||||
TrackEdge target = currentPath.get(0);
|
||||
for (Entry<TrackNode, TrackEdge> entry : options) {
|
||||
if (entry.getValue() != target)
|
||||
continue;
|
||||
currentPath.remove(0);
|
||||
return entry;
|
||||
}
|
||||
return options.get(0);
|
||||
};
|
||||
return (graph, pair) -> navigateOptions(currentPath, graph, pair.getSecond());
|
||||
}
|
||||
|
||||
public ITrackSelector controlSignalScout() {
|
||||
if (destination == null)
|
||||
return signalScout.steer(train.manualSteer, new Vec3(0, 1, 0));
|
||||
List<TrackEdge> pathCopy = new ArrayList<>(currentPath);
|
||||
return (graph, pair) -> {
|
||||
List<Entry<TrackNode, TrackEdge>> options = pair.getSecond();
|
||||
if (pathCopy.isEmpty())
|
||||
return options.get(0);
|
||||
TrackEdge target = pathCopy.get(0);
|
||||
for (Entry<TrackNode, TrackEdge> entry : options) {
|
||||
if (entry.getValue() != target)
|
||||
continue;
|
||||
pathCopy.remove(0);
|
||||
return entry;
|
||||
}
|
||||
return options.get(0);
|
||||
};
|
||||
List<Couple<TrackNode>> pathCopy = new ArrayList<>(currentPath);
|
||||
return (graph, pair) -> navigateOptions(pathCopy, graph, pair.getSecond());
|
||||
}
|
||||
|
||||
private Entry<TrackNode, TrackEdge> navigateOptions(List<Couple<TrackNode>> path, TrackGraph graph,
|
||||
List<Entry<TrackNode, TrackEdge>> options) {
|
||||
if (path.isEmpty())
|
||||
return options.get(0);
|
||||
Couple<TrackNode> nodes = path.get(0);
|
||||
TrackEdge targetEdge = graph.getConnection(nodes);
|
||||
for (Entry<TrackNode, TrackEdge> entry : options) {
|
||||
if (entry.getValue() != targetEdge)
|
||||
continue;
|
||||
path.remove(0);
|
||||
return entry;
|
||||
}
|
||||
return options.get(0);
|
||||
}
|
||||
|
||||
public void cancelNavigation() {
|
||||
|
@ -232,7 +229,7 @@ public class Navigation {
|
|||
}
|
||||
|
||||
public double startNavigation(GlobalStation destination, boolean simulate) {
|
||||
Pair<Double, List<TrackEdge>> pathTo = findPathTo(destination);
|
||||
Pair<Double, List<Couple<TrackNode>>> pathTo = findPathTo(destination);
|
||||
boolean noneFound = pathTo.getFirst() == null;
|
||||
double distance = noneFound ? -1 : Math.abs(pathTo.getFirst());
|
||||
|
||||
|
@ -280,21 +277,21 @@ public class Navigation {
|
|||
return distanceToDestination;
|
||||
}
|
||||
|
||||
private Pair<Double, List<TrackEdge>> findPathTo(GlobalStation destination) {
|
||||
private Pair<Double, List<Couple<TrackNode>>> findPathTo(GlobalStation destination) {
|
||||
TrackGraph graph = train.graph;
|
||||
List<TrackEdge> path = new ArrayList<>();
|
||||
List<Couple<TrackNode>> path = new ArrayList<>();
|
||||
|
||||
if (graph == null)
|
||||
return Pair.of(null, path);
|
||||
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> frontResult = new MutableObject<>(Pair.of(null, path));
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> backResult = new MutableObject<>(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));
|
||||
|
||||
for (boolean forward : Iterate.trueAndFalse) {
|
||||
if (this.destination == destination && destinationBehindTrain == forward)
|
||||
continue;
|
||||
|
||||
List<TrackEdge> currentPath = new ArrayList<>();
|
||||
List<Couple<TrackNode>> currentPath = new ArrayList<>();
|
||||
TravellingPoint initialPoint = forward ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
|
@ -313,13 +310,17 @@ public class Navigation {
|
|||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
|
||||
TrackEdge toReach = edge;
|
||||
while (backTrack != null && toReach != initialEdge) {
|
||||
Pair<Boolean, Couple<TrackNode>> backTrack = reachedVia.get(edge);
|
||||
Couple<TrackNode> toReach = Couple.create(node1, node2);
|
||||
TrackEdge edgeReached = edge;
|
||||
while (backTrack != null) {
|
||||
if (edgeReached == initialEdge)
|
||||
break;
|
||||
if (backTrack.getFirst())
|
||||
currentPath.add(0, toReach);
|
||||
toReach = backTrack.getSecond();
|
||||
backTrack = reachedVia.get(backTrack.getSecond());
|
||||
edgeReached = graph.getConnection(toReach);
|
||||
backTrack = reachedVia.get(edgeReached);
|
||||
}
|
||||
|
||||
double position = edge.getLength(node1, node2) - destination.getLocationOn(node1, node2, edge);
|
||||
|
@ -336,8 +337,8 @@ public class Navigation {
|
|||
break;
|
||||
}
|
||||
|
||||
Pair<Double, List<TrackEdge>> front = frontResult.getValue();
|
||||
Pair<Double, List<TrackEdge>> back = backResult.getValue();
|
||||
Pair<Double, List<Couple<TrackNode>>> front = frontResult.getValue();
|
||||
Pair<Double, List<Couple<TrackNode>>> back = backResult.getValue();
|
||||
|
||||
boolean frontEmpty = front.getFirst() == null;
|
||||
boolean backEmpty = back.getFirst() == null;
|
||||
|
@ -398,7 +399,7 @@ public class Navigation {
|
|||
.getTrailingPoint();
|
||||
|
||||
Set<TrackEdge> visited = new HashSet<>();
|
||||
Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia = new IdentityHashMap<>();
|
||||
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()));
|
||||
|
||||
|
@ -458,7 +459,7 @@ public class Navigation {
|
|||
for (Entry<TrackNode, TrackEdge> entry : validTargets) {
|
||||
TrackNode newNode = entry.getKey();
|
||||
TrackEdge newEdge = entry.getValue();
|
||||
reachedVia.put(newEdge, Pair.of(validTargets.size() > 1, edge));
|
||||
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)));
|
||||
}
|
||||
|
@ -467,8 +468,51 @@ public class Navigation {
|
|||
|
||||
@FunctionalInterface
|
||||
public interface StationTest {
|
||||
boolean test(double distance, Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia,
|
||||
boolean test(double distance, Map<TrackEdge, Pair<Boolean, Couple<TrackNode>>> reachedVia,
|
||||
Pair<Couple<TrackNode>, TrackEdge> current, GlobalStation station);
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
if (destination == null)
|
||||
return tag;
|
||||
tag.putUUID("Destination", destination.id);
|
||||
tag.putDouble("DistanceToDestination", distanceToDestination);
|
||||
tag.putBoolean("BehindTrain", destinationBehindTrain);
|
||||
tag.put("Path", NBTHelper.writeCompoundList(currentPath, c -> {
|
||||
CompoundTag nbt = new CompoundTag();
|
||||
nbt.put("Nodes", c.map(TrackNode::getLocation)
|
||||
.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
return nbt;
|
||||
}));
|
||||
if (waitingForSignal == null)
|
||||
return tag;
|
||||
tag.putUUID("BlockingSignal", waitingForSignal.getFirst());
|
||||
tag.putBoolean("BlockingSignalSide", waitingForSignal.getSecond());
|
||||
tag.putDouble("DistanceToSignal", distanceToSignal);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public void read(CompoundTag tag, TrackGraph graph) {
|
||||
destination =
|
||||
tag.contains("Destination") ? graph.getPoint(EdgePointType.STATION, tag.getUUID("Destination")) : null;
|
||||
if (destination == null)
|
||||
return;
|
||||
distanceToDestination = tag.getDouble("DistanceToDestination");
|
||||
destinationBehindTrain = tag.getBoolean("BehindTrain");
|
||||
currentPath.clear();
|
||||
NBTHelper.iterateCompoundList(tag.getList("Path", Tag.TAG_COMPOUND),
|
||||
c -> currentPath.add(Couple
|
||||
.deserializeEach(c.getList("Nodes", Tag.TAG_COMPOUND),
|
||||
c2 -> TrackNodeLocation.fromPackedPos(NbtUtils.readBlockPos(c2)))
|
||||
.map(graph::locateNode)));
|
||||
waitingForSignal = tag.contains("BlockingSignal")
|
||||
? Pair.of(tag.getUUID("BlockingSignal"), tag.getBoolean("BlockingSignalSide"))
|
||||
: null;
|
||||
if (waitingForSignal == null)
|
||||
return;
|
||||
distanceToSignal = tag.getDouble("DistanceToSignal");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,12 +37,17 @@ import com.simibubi.create.foundation.config.AllConfigs;
|
|||
import com.simibubi.create.foundation.networking.AllPackets;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Direction.Axis;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Explosion.BlockInteraction;
|
||||
|
@ -132,8 +137,13 @@ public class Train {
|
|||
}
|
||||
|
||||
public void tick(Level level) {
|
||||
if (graph == null)
|
||||
Create.RAILWAYS.markTracksDirty();
|
||||
|
||||
if (graph == null) {
|
||||
carriages.forEach(c -> c.manageEntity(level));
|
||||
updateConductors();
|
||||
return;
|
||||
}
|
||||
|
||||
updateConductors();
|
||||
runtime.tick(level);
|
||||
|
@ -151,8 +161,8 @@ public class Train {
|
|||
Carriage carriage = carriages.get(i);
|
||||
if (previousCarriage != null) {
|
||||
int target = carriageSpacing.get(i - 1);
|
||||
Vec3 leadingAnchor = carriage.leadingBogey().anchorPosition;
|
||||
Vec3 trailingAnchor = previousCarriage.trailingBogey().anchorPosition;
|
||||
Vec3 leadingAnchor = carriage.leadingAnchor();
|
||||
Vec3 trailingAnchor = previousCarriage.trailingAnchor();
|
||||
double actual = leadingAnchor.distanceTo(trailingAnchor);
|
||||
stress[i - 1] = target - actual;
|
||||
}
|
||||
|
@ -296,11 +306,31 @@ public class Train {
|
|||
private void collideWithOtherTrains(Level level, Carriage carriage) {
|
||||
if (derailed)
|
||||
return;
|
||||
Collision: for (Train train : Create.RAILWAYS.trains.values()) {
|
||||
if (train == this)
|
||||
|
||||
Vec3 start = (speed < 0 ? carriage.getTrailingPoint() : carriage.getLeadingPoint()).getPosition();
|
||||
Vec3 end = (speed < 0 ? carriage.getLeadingPoint() : carriage.getTrailingPoint()).getPosition();
|
||||
|
||||
Pair<Train, Vec3> collision = findCollidingTrain(level, start, end, this);
|
||||
if (collision == null)
|
||||
return;
|
||||
|
||||
Train train = collision.getFirst();
|
||||
|
||||
double combinedSpeed = Math.abs(speed) + Math.abs(train.speed);
|
||||
if (combinedSpeed > .2f) {
|
||||
Vec3 v = collision.getSecond();
|
||||
level.explode(null, v.x, v.y, v.z, (float) Math.min(3 * combinedSpeed, 5), BlockInteraction.NONE);
|
||||
}
|
||||
|
||||
crash();
|
||||
train.crash();
|
||||
}
|
||||
|
||||
public static Pair<Train, Vec3> findCollidingTrain(Level level, Vec3 start, Vec3 end, Train ignore) {
|
||||
for (Train train : Create.RAILWAYS.sided(level).trains.values()) {
|
||||
if (train == ignore)
|
||||
continue;
|
||||
Vec3 start = (speed < 0 ? carriage.getTrailingPoint() : carriage.getLeadingPoint()).getPosition();
|
||||
Vec3 end = (speed < 0 ? carriage.getLeadingPoint() : carriage.getTrailingPoint()).getPosition();
|
||||
|
||||
Vec3 diff = end.subtract(start);
|
||||
Vec3 lastPoint = null;
|
||||
|
||||
|
@ -309,10 +339,13 @@ public class Train {
|
|||
if (betweenBits && lastPoint == null)
|
||||
continue;
|
||||
|
||||
Vec3 start2 = otherCarriage.getLeadingPoint()
|
||||
.getPosition();
|
||||
Vec3 end2 = otherCarriage.getTrailingPoint()
|
||||
.getPosition();
|
||||
TravellingPoint otherLeading = otherCarriage.getLeadingPoint();
|
||||
TravellingPoint otherTrailing = otherCarriage.getTrailingPoint();
|
||||
if (otherLeading.edge == null || otherTrailing.edge == null)
|
||||
continue;
|
||||
|
||||
Vec3 start2 = otherLeading.getPosition();
|
||||
Vec3 end2 = otherTrailing.getPosition();
|
||||
if (betweenBits) {
|
||||
end2 = start2;
|
||||
start2 = lastPoint;
|
||||
|
@ -328,6 +361,7 @@ public class Train {
|
|||
Vec3 normedDiff = diff.normalize();
|
||||
Vec3 normedDiff2 = diff2.normalize();
|
||||
double[] intersect = VecHelper.intersect(start, start2, normedDiff, normedDiff2, Axis.Y);
|
||||
|
||||
if (intersect == null) {
|
||||
Vec3 intersectSphere = VecHelper.intersectSphere(start2, normedDiff2, start, .125f);
|
||||
if (intersectSphere == null)
|
||||
|
@ -339,6 +373,7 @@ public class Train {
|
|||
intersect[0] = intersectSphere.distanceTo(start) - .125;
|
||||
intersect[1] = intersectSphere.distanceTo(start2) - .125;
|
||||
}
|
||||
|
||||
if (intersect[0] > diff.length())
|
||||
continue;
|
||||
if (intersect[1] > diff2.length())
|
||||
|
@ -348,18 +383,11 @@ public class Train {
|
|||
if (intersect[1] < 0)
|
||||
continue;
|
||||
|
||||
double combinedSpeed = Math.abs(speed) + Math.abs(train.speed);
|
||||
if (combinedSpeed > .2f) {
|
||||
Vec3 v = start.add(normedDiff.scale(intersect[0]));
|
||||
level.explode(null, v.x, v.y, v.z, (float) Math.min(3 * combinedSpeed, 5),
|
||||
BlockInteraction.NONE);
|
||||
}
|
||||
crash();
|
||||
train.crash();
|
||||
break Collision;
|
||||
return Pair.of(train, start.add(normedDiff.scale(intersect[0])));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void crash() {
|
||||
|
@ -552,9 +580,8 @@ public class Train {
|
|||
|
||||
public void leaveStation() {
|
||||
GlobalStation currentStation = getCurrentStation();
|
||||
if (currentStation == null)
|
||||
return;
|
||||
currentStation.trainDeparted(this);
|
||||
if (currentStation != null)
|
||||
currentStation.trainDeparted(this);
|
||||
this.currentStation = null;
|
||||
}
|
||||
|
||||
|
@ -658,4 +685,77 @@ public class Train {
|
|||
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putUUID("Id", id);
|
||||
tag.putUUID("Owner", owner);
|
||||
if (graph != null)
|
||||
tag.putUUID("Graph", graph.id);
|
||||
tag.put("Carriages", NBTHelper.writeCompoundList(carriages, Carriage::write));
|
||||
tag.putIntArray("CarriageSpacing", carriageSpacing);
|
||||
tag.putBoolean("DoubleEnded", doubleEnded);
|
||||
tag.putDouble("Speed", speed);
|
||||
tag.putDouble("TargetSpeed", targetSpeed);
|
||||
tag.putString("IconType", icon.id.toString());
|
||||
tag.putString("Name", Component.Serializer.toJson(name));
|
||||
if (currentStation != null)
|
||||
tag.putUUID("Station", currentStation);
|
||||
tag.putBoolean("Backwards", currentlyBackwards);
|
||||
tag.putBoolean("StillAssembling", heldForAssembly);
|
||||
tag.putBoolean("Derailed", derailed);
|
||||
tag.putBoolean("UpdateSignals", updateSignalBlocks);
|
||||
tag.put("SignalBlocks", NBTHelper.writeCompoundList(occupiedSignalBlocks, uid -> {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.putUUID("Id", uid);
|
||||
return compoundTag;
|
||||
}));
|
||||
tag.put("MigratingPoints", NBTHelper.writeCompoundList(migratingPoints, TrainMigration::write));
|
||||
|
||||
tag.put("Runtime", runtime.write());
|
||||
tag.put("Navigation", navigation.write());
|
||||
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static Train read(CompoundTag tag, Map<UUID, TrackGraph> trackNetworks) {
|
||||
UUID id = tag.getUUID("Id");
|
||||
UUID owner = tag.getUUID("Owner");
|
||||
UUID graphId = tag.contains("Graph") ? tag.getUUID("Graph") : null;
|
||||
TrackGraph graph = graphId == null ? null : trackNetworks.get(graphId);
|
||||
List<Carriage> carriages = new ArrayList<>();
|
||||
NBTHelper.iterateCompoundList(tag.getList("Carriages", Tag.TAG_COMPOUND),
|
||||
c -> carriages.add(Carriage.read(c, graph)));
|
||||
List<Integer> carriageSpacing = new ArrayList<>();
|
||||
for (int i : tag.getIntArray("CarriageSpacing"))
|
||||
carriageSpacing.add(i);
|
||||
boolean doubleEnded = tag.getBoolean("DoubleEnded");
|
||||
|
||||
Train train = new Train(id, owner, graph, carriages, carriageSpacing, doubleEnded);
|
||||
|
||||
train.speed = tag.getDouble("Speed");
|
||||
train.targetSpeed = tag.getDouble("TargetSpeed");
|
||||
train.icon = TrainIconType.byId(new ResourceLocation(tag.getString("IconType")));
|
||||
train.name = Component.Serializer.fromJson(tag.getString("Name"));
|
||||
train.currentStation = tag.contains("Station") ? tag.getUUID("Station") : null;
|
||||
train.currentlyBackwards = tag.getBoolean("Backwards");
|
||||
train.heldForAssembly = tag.getBoolean("StillAssembling");
|
||||
train.derailed = tag.getBoolean("Derailed");
|
||||
train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
|
||||
|
||||
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND),
|
||||
c -> train.occupiedSignalBlocks.add(c.getUUID("Id")));
|
||||
|
||||
NBTHelper.iterateCompoundList(tag.getList("MigratingPoints", Tag.TAG_COMPOUND),
|
||||
c -> train.migratingPoints.add(TrainMigration.read(c)));
|
||||
|
||||
train.runtime.read(tag.getCompound("Runtime"));
|
||||
train.navigation.read(tag.getCompound("Navigation"), graph);
|
||||
|
||||
if (train.getCurrentStation() != null)
|
||||
train.getCurrentStation()
|
||||
.reserveFor(train);
|
||||
|
||||
return train;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
|||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
|
@ -20,6 +24,8 @@ public class TrainMigration {
|
|||
boolean curve;
|
||||
Vec3 fallback;
|
||||
|
||||
public TrainMigration() {}
|
||||
|
||||
public TrainMigration(TravellingPoint point) {
|
||||
double t = point.position / point.edge.getLength(point.node1, point.node2);
|
||||
fallback = point.edge.getPosition(point.node1, point.node2, t);
|
||||
|
@ -94,4 +100,25 @@ public class TrainMigration {
|
|||
return null;
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putBoolean("Curve", curve);
|
||||
tag.put("Fallback", VecHelper.writeNBT(fallback));
|
||||
tag.putDouble("Position", positionOnOldEdge);
|
||||
tag.put("Nodes", locations.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TrainMigration read(CompoundTag tag) {
|
||||
TrainMigration trainMigration = new TrainMigration();
|
||||
trainMigration.curve = tag.getBoolean("Curve");
|
||||
trainMigration.fallback = VecHelper.readNBT(tag.getList("Fallback", Tag.TAG_DOUBLE));
|
||||
trainMigration.positionOnOldEdge = tag.getDouble("Position");
|
||||
trainMigration.locations =
|
||||
Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(TrackNodeLocation::fromPackedPos);
|
||||
return trainMigration;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,6 +13,7 @@ import com.simibubi.create.foundation.utility.Couple;
|
|||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.network.NetworkEvent.Context;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
|
@ -57,8 +58,11 @@ public class TrainPacket extends SimplePacketBase {
|
|||
carriageSpacing.add(buffer.readVarInt());
|
||||
|
||||
boolean doubleEnded = buffer.readBoolean();
|
||||
|
||||
train = new Train(trainId, owner, null, carriages, carriageSpacing, doubleEnded);
|
||||
|
||||
train.heldForAssembly = buffer.readBoolean();
|
||||
train.name = Component.Serializer.fromJson(buffer.readUtf());
|
||||
train.icon = TrainIconType.byId(buffer.readResourceLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,6 +94,9 @@ public class TrainPacket extends SimplePacketBase {
|
|||
train.carriageSpacing.forEach(buffer::writeVarInt);
|
||||
|
||||
buffer.writeBoolean(train.doubleEnded);
|
||||
buffer.writeBoolean(train.heldForAssembly);
|
||||
buffer.writeUtf(Component.Serializer.toJson(train.name));
|
||||
buffer.writeResourceLocation(train.icon.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,9 +9,11 @@ import java.util.function.Consumer;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableBoolean;
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.CreateClient;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandlerClient;
|
||||
import com.simibubi.create.content.logistics.trains.GraphLocation;
|
||||
|
@ -56,6 +58,7 @@ public class TrainRelocator {
|
|||
|
||||
static BlockPos lastHoveredPos;
|
||||
static Boolean lastHoveredResult;
|
||||
static List<Vec3> toVisualise;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void onClicked(ClickInputEvent event) {
|
||||
|
@ -98,10 +101,22 @@ public class TrainRelocator {
|
|||
return null;
|
||||
BlockPos blockPos = blockhit.getBlockPos();
|
||||
|
||||
if (simulate && toVisualise != null) {
|
||||
for (int i = 0; i < toVisualise.size() - 1; i++) {
|
||||
Vec3 vec1 = toVisualise.get(i);
|
||||
Vec3 vec2 = toVisualise.get(i + 1);
|
||||
CreateClient.OUTLINER.showLine(Pair.of(relocating, i), vec1.add(0, -.925f, 0), vec2.add(0, -.925f, 0))
|
||||
.colored(lastHoveredResult || i != toVisualise.size() - 2 ? 0x95CD41 : 0xEA5C2B)
|
||||
.disableNormals()
|
||||
.lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f);
|
||||
}
|
||||
}
|
||||
|
||||
if (simulate) {
|
||||
if (lastHoveredPos != null && lastHoveredPos.equals(blockPos))
|
||||
return lastHoveredResult;
|
||||
lastHoveredPos = blockPos;
|
||||
toVisualise = null;
|
||||
}
|
||||
|
||||
BlockState blockState = mc.level.getBlockState(blockPos);
|
||||
|
@ -113,6 +128,7 @@ public class TrainRelocator {
|
|||
if (!simulate && result)
|
||||
AllPackets.channel
|
||||
.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, lookAngle, relocatingEntityId));
|
||||
|
||||
return lastHoveredResult = result;
|
||||
}
|
||||
|
||||
|
@ -139,22 +155,43 @@ public class TrainRelocator {
|
|||
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position);
|
||||
ISignalBoundaryListener ignoreSignals = probe.ignoreSignals();
|
||||
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();
|
||||
Consumer<TravellingPoint> recorder =
|
||||
tp -> recordedLocations.add(Pair.of(Couple.create(tp.node1, tp.node2), tp.position));
|
||||
List<Vec3> recordedVecs = new ArrayList<>();
|
||||
Consumer<TravellingPoint> recorder = tp -> {
|
||||
recordedLocations.add(Pair.of(Couple.create(tp.node1, tp.node2), tp.position));
|
||||
recordedVecs.add(tp.getPosition());
|
||||
};
|
||||
ITrackSelector steer = probe.steer(SteerDirection.NONE, track.getUpNormal(level, pos, blockState));
|
||||
MutableBoolean blocked = new MutableBoolean(false);
|
||||
|
||||
MutableInt blockingIndex = new MutableInt(0);
|
||||
train.forEachTravellingPointBackwards((tp, d) -> {
|
||||
if (blocked.booleanValue())
|
||||
return;
|
||||
probe.travel(graph, d, steer, ignoreSignals);
|
||||
recorder.accept(probe);
|
||||
if (probe.blocked) {
|
||||
blocked.setTrue();
|
||||
return;
|
||||
}
|
||||
recorder.accept(probe);
|
||||
blockingIndex.increment();
|
||||
});
|
||||
|
||||
if (level.isClientSide && simulate && !recordedVecs.isEmpty()) {
|
||||
toVisualise = new ArrayList<>();
|
||||
toVisualise.add(recordedVecs.get(0));
|
||||
}
|
||||
|
||||
for (int i = 0; i < recordedVecs.size() - 1; i++) {
|
||||
Vec3 vec1 = recordedVecs.get(i);
|
||||
Vec3 vec2 = recordedVecs.get(i + 1);
|
||||
boolean blocking = i >= blockingIndex.intValue() - 1;
|
||||
boolean collided = !blocked.booleanValue() && Train.findCollidingTrain(level, vec1, vec2, train) != null;
|
||||
if (level.isClientSide && simulate)
|
||||
toVisualise.add(vec2);
|
||||
if (collided || blocking)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (blocked.booleanValue())
|
||||
return false;
|
||||
|
||||
|
@ -167,6 +204,7 @@ public class TrainRelocator {
|
|||
train.occupiedSignalBlocks.clear();
|
||||
train.graph = graph;
|
||||
train.speed = 0;
|
||||
train.migratingPoints.clear();
|
||||
|
||||
if (train.navigation.destination != null)
|
||||
train.navigation.cancelNavigation();
|
||||
|
@ -182,11 +220,22 @@ public class TrainRelocator {
|
|||
.get(tp.node2);
|
||||
});
|
||||
|
||||
for (Carriage carriage : train.carriages)
|
||||
carriage.updateContraptionAnchors();
|
||||
|
||||
train.status.successfulMigration();
|
||||
train.collectInitiallyOccupiedSignalBlocks();
|
||||
return true;
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void visualise(Train train, int i, Vec3 v1, Vec3 v2, boolean valid) {
|
||||
CreateClient.OUTLINER.showLine(Pair.of(train, i), v1.add(0, -.825f, 0), v2.add(0, -.825f, 0))
|
||||
.colored(valid ? 0x95CD41 : 0xEA5C2B)
|
||||
.disableNormals()
|
||||
.lineWidth(i % 2 == 1 ? 1 / 6f : 1 / 4f);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void clientTick() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.util.ArrayList;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.Vector;
|
||||
|
@ -18,12 +19,17 @@ import com.simibubi.create.content.logistics.trains.GraphLocation;
|
|||
import com.simibubi.create.content.logistics.trains.TrackEdge;
|
||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public class TravellingPoint {
|
||||
|
@ -331,4 +337,35 @@ public class TravellingPoint {
|
|||
.get(node2);
|
||||
}
|
||||
|
||||
public CompoundTag write() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
Couple<TrackNode> nodes = Couple.create(node1, node2);
|
||||
if (nodes.either(Objects::isNull))
|
||||
return tag;
|
||||
tag.put("Nodes", nodes.map(TrackNode::getLocation)
|
||||
.map(BlockPos::new)
|
||||
.serializeEach(NbtUtils::writeBlockPos));
|
||||
tag.putDouble("Position", position);
|
||||
return tag;
|
||||
}
|
||||
|
||||
public static TravellingPoint read(CompoundTag tag, TrackGraph graph) {
|
||||
if (graph == null)
|
||||
return new TravellingPoint(null, null, null, 0);
|
||||
|
||||
Couple<TrackNode> locs =
|
||||
tag.contains("Nodes")
|
||||
? Couple.deserializeEach(tag.getList("Nodes", Tag.TAG_COMPOUND), NbtUtils::readBlockPos)
|
||||
.map(TrackNodeLocation::fromPackedPos)
|
||||
.map(graph::locateNode)
|
||||
: Couple.create(null, null);
|
||||
|
||||
if (locs.either(Objects::isNull))
|
||||
return new TravellingPoint(null, null, null, 0);
|
||||
|
||||
double position = tag.getDouble("Position");
|
||||
return new TravellingPoint(locs.getFirst(), locs.getSecond(), graph.getConnectionsFrom(locs.getFirst())
|
||||
.get(locs.getSecond()), position);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,8 +9,10 @@ import com.simibubi.create.content.logistics.trains.management.edgePoint.station
|
|||
import com.simibubi.create.content.logistics.trains.management.schedule.condition.ScheduleWaitCondition;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.destination.FilteredDestination;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.destination.ScheduleDestination;
|
||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
public class ScheduleRuntime {
|
||||
|
@ -180,6 +182,9 @@ public class ScheduleRuntime {
|
|||
tag.putBoolean("Paused", paused);
|
||||
if (schedule != null)
|
||||
tag.put("Schedule", schedule.write());
|
||||
NBTHelper.writeEnum(tag, "State", state);
|
||||
tag.putIntArray("ConditionProgress", conditionProgress);
|
||||
tag.put("ConditionContext", NBTHelper.writeCompoundList(conditionContext, CompoundTag::copy));
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -190,6 +195,10 @@ public class ScheduleRuntime {
|
|||
currentEntry = tag.getInt("CurrentEntry");
|
||||
if (tag.contains("Schedule"))
|
||||
schedule = Schedule.fromTag(tag.getCompound("Schedule"));
|
||||
state = NBTHelper.readEnum(tag, "State", State.class);
|
||||
for (int i : tag.getIntArray("ConditionProgress"))
|
||||
conditionProgress.add(i);
|
||||
NBTHelper.iterateCompoundList(tag.getList("ConditionContext", Tag.TAG_COMPOUND), conditionContext::add);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -645,7 +645,7 @@
|
|||
"create.train.relocate.abort": "Relocation aborted",
|
||||
"create.train.relocate.success": "Relocation successful",
|
||||
"create.train.relocate.valid": "Can relocate to here, Click to Confirm",
|
||||
"create.train.relocate.invalid": "Cannot relocate Train to this Track",
|
||||
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
||||
"create.train.relocate.too_far": "Cannot relocate Train this far away",
|
||||
|
||||
"create.contraption.controls.start_controlling": "Now controlling: %1$s",
|
||||
|
|
Loading…
Reference in a new issue