mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-05-19 20:13:53 +02:00
e5c6ca157c
commit 053dd09df6c426ab5e570f42a1edb5df3d0fbd01 Merge: 6d1e1c71decc645eba
Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 18:22:42 2023 +0200 Merge branch '1.18/api' of https://github.com/Layers-of-Railways/Create into pr/4692 commitecc645eba7
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Tue May 9 11:24:11 2023 +0100 Implemented support for creating and removing individual blockstate models commit 6d1e1c71de7ce20f6fd9fc8ed4ed9bdd1072829a Author: simibubi <31564874+simibubi@users.noreply.github.com> Date: Tue May 9 12:16:54 2023 +0200 Less error logging when migrating old worlds commit205e47352e
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 21:02:19 2023 -0700 Fix up ItemOutline commit6cf204f6af
Merge:fe049bc77
2e3c906ce
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 20:28:56 2023 -0700 Merge remote-tracking branch 'upstream/mc1.18/dev' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageCouplingRenderer.java commitfe049bc771
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 20:26:16 2023 -0700 Revert "Revert "Rewrite outline buffering"" This reverts commit726bfaf0
commit435b4c1c16
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 20:20:23 2023 -0700 Clean up last bits of upside down rendering commit662da6bab1
Merge:122fe77af
d83285e8a
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 20:16:32 2023 -0700 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api # Conflicts: # src/main/java/com/simibubi/create/content/logistics/trains/StandardBogeyRenderer.java commit122fe77afa
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 8 20:15:46 2023 -0700 Fix up upside down rendering commitd83285e8a4
Merge:00e953a58
cdb0ad210
Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun May 7 07:02:18 2023 -0700 Merge pull request #3 from Layers-of-Railways/1.18/bogey-api Cleanup cycle groups and unused imports commitcdb0ad210b
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun May 7 10:15:47 2023 +0100 Fixed merge artifact commit457d5f33ed
Merge:4e4e227a3
00e953a58
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun May 7 10:14:07 2023 +0100 Merge remote-tracking branch 'origin/1.18/api' into 1.18/api commit00e953a585
Merge:1e4d5504e
a7a25896c
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:49 2023 +0100 Merge pull request #2 from Rabbitminers/mc1.18/dev Added Return Values and Small Cleanup commita7a25896c1
Merge:7622128be
1e4d5504e
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 10:13:40 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commit4e4e227a35
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun May 7 10:10:30 2023 +0100 Cleanup to cycle groups commitaa94fc97d1
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun May 7 09:50:50 2023 +0100 Removed unused import of Railways commit7622128bec
Merge:81eeadb85
d52065808
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Sun May 7 09:11:59 2023 +0100 Merge branch 'Layers-of-Railways:mc1.18/dev' into mc1.18/dev commit1e4d5504ee
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sat May 6 18:03:39 2023 -0700 Don't revert non-buggy changes commitb306cf2124
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sat May 6 18:00:59 2023 -0700 Take materials into consideration when trains pathfind commitfca02ae4bf
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sat May 6 10:25:51 2023 -0700 Add materials to track graph commit726bfaf0b5
Author: techno-sam <linux.techno.sam@gmail.com> Date: Fri May 5 21:16:49 2023 -0700 Revert "Rewrite outline buffering" This reverts commitd4106d545b
. commit171897bed2
Author: techno-sam <linux.techno.sam@gmail.com> Date: Fri May 5 20:55:25 2023 -0700 Fix up style cycling commitcbd0cf20da
Author: techno-sam <linux.techno.sam@gmail.com> Date: Fri May 5 07:32:06 2023 -0700 clean up nether portal carriage handling commitd556f08876
Author: techno-sam <linux.techno.sam@gmail.com> Date: Fri May 5 07:06:02 2023 -0700 upside down bogeys work in nether portals fixed coupling anchor offsets commitda26c0ccbf
Author: techno-sam <linux.techno.sam@gmail.com> Date: Thu May 4 09:32:53 2023 -0700 working on upside down bogeys in nether portals commit81eeadb853
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon May 1 16:15:28 2023 +0100 Small cleanup commitc7e9df973c
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon May 1 16:13:51 2023 +0100 Fixed issue raised in #1 commit2f285b6eb7
Author: techno-sam <linux.techno.sam@gmail.com> Date: Mon May 1 08:13:27 2023 -0700 add data gen commit206de01311
Merge:e91753a33
6564f4fa7
Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Mon May 1 06:49:21 2023 -0700 Merge pull request #1 from Rabbitminers/mc1.18/dev Bogey API commit6564f4fa73
Merge:e5d759582
e91753a33
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Mon May 1 10:40:32 2023 +0100 Merge branch '1.18/api' into mc1.18/dev commite5d7595822
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon May 1 10:09:03 2023 +0100 Connected Custom Bogey Particle Types To CarriageParticles commite91753a33c
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sun Apr 30 19:51:26 2023 -0700 Fix up some problems commit9815f1490f
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 21:12:43 2023 +0100 Implemented default data when shifting styles commitda30e78815
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 21:12:14 2023 +0100 Added Particles To Bogey Style (And Respective Builder) commit08c000b8ba
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 21:01:19 2023 +0100 Added Backup Rendering If A Size Is Not Present commit2b76e8d7b3
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 21:00:40 2023 +0100 Added Common Renderer To Remove Function commit411ec36f57
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:59:50 2023 +0100 Added Display Name To Standard Bogey Style commit112306d5d4
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:59:30 2023 +0100 Displayed new style name when changing betweeen them commit5634670b27
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:06:00 2023 +0100 General Cleanup commit0f7a8b7b24
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:05:50 2023 +0100 Implemented Changes To Remaining Classes commit8aedc00f96
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:02:06 2023 +0100 Removed Bogey Style Handling From Registrate commitedf8079abf
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:01:40 2023 +0100 Removed Unused Registry Handling commit6a185c4e72
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:01:16 2023 +0100 Refactored Bogey Sizes commite10d07ddc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 30 20:01:00 2023 +0100 Overhauled Bogey Style commit74d98a2ad5
Merge:e629d02f5
4ebcf8201
Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Sun Apr 23 07:16:33 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commite629d02f50
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sun Apr 9 07:18:22 2023 -0700 Track API Clean up code a bit commitd9ce6ce995
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sun Apr 9 07:14:46 2023 -0700 Track API? Fix placement commit7fbf08ba54
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sat Apr 8 11:11:24 2023 -0700 Track API? Fix up some placement issues commit35644f1434
Author: techno-sam <linux.techno.sam@gmail.com> Date: Sat Apr 8 08:11:13 2023 -0700 Track API maybe? Datagen Seems to be working commitf7c56b867a
Author: techno-sam <linux.techno.sam@gmail.com> Date: Thu Apr 6 21:24:31 2023 -0700 Track API maybe? Fix build - broken generic Not yet tested, but it is progress commit2a59fd7e8a
Author: techno-sam <linux.techno.sam@gmail.com> Date: Thu Apr 6 21:13:54 2023 -0700 Track API maybe? Not yet tested, but it is progress commit5ba30d6a85
Merge:e4e5ac1c4
c2977bbff
Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:39 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into 1.18/api commitd52065808c
Merge:e4e5ac1c4
c2977bbff
Author: techno-sam <77073745+techno-sam@users.noreply.github.com> Date: Thu Apr 6 17:10:26 2023 -0700 Merge branch 'Creators-of-Create:mc1.18/dev' into mc1.18/dev commit53240bd42f
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 21:42:29 2023 +0100 Corrected Bogey InteractionResult To Pass commit69326e361a
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 21:30:28 2023 +0100 Fixed Default Values When Used Styles Are Removed commit4f176979de
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 19:33:17 2023 +0100 Fixed Carriage Sounds (Again) commit1e80af3303
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 19:27:58 2023 +0100 Refactored Bogey Sizes To Seperate Class commit129be61fee
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 17:20:17 2023 +0100 Fixed Bogey Sound Loading commit2543185a55
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 09:45:23 2023 +0100 Added Bogey Sound Customisation commit1ad5ae9514
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Mon Apr 3 00:44:53 2023 +0100 Added Size Transforms If Size Is Not Available For New Style commit96566b1614
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 2 23:02:02 2023 +0100 Moved Bogey Style Inside Of Bogey Data And Implemented Bogey Data Communication commiteedd984738
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 2 16:53:55 2023 +0100 Fixed Large Bogey Size commit68ca0974c6
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 2 16:47:58 2023 +0100 Implemented Style Cycling & Default Values commita55ba4267a
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 2 16:46:15 2023 +0100 Implemented renderer instance creator commit43523302c2
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sun Apr 2 16:45:33 2023 +0100 Removed Unused Standard Bogey Instance commit773e084422
Merge:0c0b5a1ed
d1e1f7ec5
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sat Apr 1 18:50:15 2023 +0100 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev # Conflicts: # src/main/java/com/simibubi/create/AllBogeyStyles.java # src/main/java/com/simibubi/create/content/logistics/trains/BogeyTileEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/BogeyStyle.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntityRenderer.java # src/main/java/com/simibubi/create/content/logistics/trains/entity/StandardBogeyInstance.java # src/main/java/com/simibubi/create/foundation/data/BogeyStyleBuilder.java commit0c0b5a1ed6
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sat Apr 1 18:39:58 2023 +0100 Linked Style Registry To Bogey Blocks commit71f839ee51
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sat Apr 1 18:39:03 2023 +0100 Replaced size boolean with direct use of size enum commit50ff081704
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 30 18:47:13 2023 +0100 Added Resource Location To NBT helper methods commitd1e1f7ec5a
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 30 18:47:13 2023 +0100 Re-worked BogeyStyles commitda593fccb1
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 30 18:46:02 2023 +0100 Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations commit17432c9113
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Sat Mar 25 10:20:50 2023 +0000 Fixed Incorrect Registry Loading commitc7d899369a
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:44:03 2023 +0000 Registered Registers commit6d862290d7
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:43:23 2023 +0000 Added BogeyStyleBuilder To Registrate commit3dfb9e3b3b
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:43:08 2023 +0000 Implemented AllBogeyStyles commitc9e71b462d
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:42:56 2023 +0000 Created BogeyStyleBuilder commita90977d642
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:42:25 2023 +0000 Created AllRegistries and BogeyStyle Registry commit154d455f3f
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Fri Mar 24 23:41:56 2023 +0000 Added BogeyStyle Wrapper commitdfb7640bfc
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:50:41 2023 +0000 Removed left over logging statement commit9920536cc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:50:18 2023 +0000 Implemented Secondary Shaft To Large Renderer commit6cd40cc6f9
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:49:56 2023 +0000 Prevented Overwrite When Using Two BlockStates Of The Same Type With Different Properties commit06fb901144
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:39:11 2023 +0000 Implemented Common Rendering For StandardBogeyRenderer commit435b0f8266
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:38:40 2023 +0000 Added Common Renderer commit96a0623dab
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 18:38:29 2023 +0000 Implemented BlockState Models For Rendering commit469d9d592b
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 17:42:28 2023 +0000 Added Standard Bogey Instance (Might be redundant) commit2661d260d8
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 17:42:06 2023 +0000 Refactored Changes To Existing Methods commit9ded16fbab
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 17:41:15 2023 +0000 Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption) commit4a82fcbca1
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 17:40:13 2023 +0000 Implemented Changes To StandardBogeyBlock commit7238fb93f3
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Thu Mar 23 17:39:51 2023 +0000 Added Renderer To IBogeyBlock commitded4c1f613
Merge:91727cc84
3c02fe6ec
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Wed Mar 22 17:03:37 2023 +0000 Merge remote-tracking branch 'origin/mc1.18/dev' into mc1.18/dev commit91727cc84a
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Wed Mar 22 17:03:28 2023 +0000 Implemented Model Data Initializer to StandardBogeyRenderer commit6d98a1f469
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Wed Mar 22 17:03:00 2023 +0000 Added Contraption Model Instance Initializer commit3c02fe6ecc
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com> Date: Tue Mar 21 22:45:34 2023 +0000 Added missing render type check commit6672c49649
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Tue Mar 21 22:37:36 2023 +0000 Re-created standard bogey with test api commita8a9491fa0
Author: Rabbitminers <Rabbitminers2.0@gmail.com> Date: Tue Mar 21 22:34:54 2023 +0000 Implemented Proof Of Concept Generic Bogey Renderer commite4e5ac1c40
Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com> Date: Sat Mar 11 21:34:59 2023 +0000 init
1244 lines
40 KiB
Java
1244 lines
40 KiB
Java
package com.simibubi.create.content.logistics.trains.entity;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map.Entry;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
import java.util.function.BiConsumer;
|
|
import java.util.function.Consumer;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import com.simibubi.create.content.logistics.trains.track.AbstractBogeyTileEntity;
|
|
|
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
|
|
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
|
import org.apache.commons.lang3.mutable.MutableObject;
|
|
|
|
import com.simibubi.create.AllMovementBehaviours;
|
|
import com.simibubi.create.Create;
|
|
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
|
|
import com.simibubi.create.content.logistics.item.filter.FilterItem;
|
|
import com.simibubi.create.content.logistics.trains.DimensionPalette;
|
|
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.entity.Carriage.DimensionalCarriageEntity;
|
|
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener;
|
|
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
|
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.observer.TrackObserver;
|
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType;
|
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
|
|
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime;
|
|
import com.simibubi.create.content.logistics.trains.management.schedule.ScheduleRuntime.State;
|
|
import com.simibubi.create.foundation.advancement.AllAdvancements;
|
|
import com.simibubi.create.foundation.config.AllConfigs;
|
|
import com.simibubi.create.foundation.networking.AllPackets;
|
|
import com.simibubi.create.foundation.utility.Couple;
|
|
import com.simibubi.create.foundation.utility.Iterate;
|
|
import com.simibubi.create.foundation.utility.Lang;
|
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
|
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.ResourceKey;
|
|
import net.minecraft.resources.ResourceLocation;
|
|
import net.minecraft.util.Mth;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.Explosion.BlockInteraction;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import net.minecraftforge.common.ForgeHooks;
|
|
import net.minecraftforge.fluids.FluidStack;
|
|
import net.minecraftforge.fluids.capability.IFluidHandler;
|
|
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
|
|
import net.minecraftforge.items.IItemHandlerModifiable;
|
|
import net.minecraftforge.items.ItemHandlerHelper;
|
|
import net.minecraftforge.network.PacketDistributor;
|
|
|
|
public class Train {
|
|
|
|
public double speed = 0;
|
|
public double targetSpeed = 0;
|
|
public Double speedBeforeStall = null;
|
|
public int carriageWaitingForChunks = -1;
|
|
|
|
public double throttle = 1;
|
|
public boolean honk = false;
|
|
|
|
public UUID id;
|
|
public UUID owner;
|
|
public TrackGraph graph;
|
|
public Navigation navigation;
|
|
public ScheduleRuntime runtime;
|
|
public TrainIconType icon;
|
|
public Component name;
|
|
public TrainStatus status;
|
|
|
|
public boolean invalid;
|
|
|
|
public SteerDirection manualSteer;
|
|
public boolean manualTick;
|
|
|
|
public UUID currentStation;
|
|
public boolean currentlyBackwards;
|
|
|
|
public boolean doubleEnded;
|
|
public List<Carriage> carriages;
|
|
public List<Integer> carriageSpacing;
|
|
|
|
public boolean updateSignalBlocks;
|
|
public Map<UUID, UUID> occupiedSignalBlocks;
|
|
public Set<UUID> reservedSignalBlocks;
|
|
|
|
public Set<UUID> occupiedObservers;
|
|
public Map<UUID, Pair<Integer, Boolean>> cachedObserverFiltering;
|
|
|
|
List<TrainMigration> migratingPoints;
|
|
public int migrationCooldown;
|
|
public boolean derailed;
|
|
|
|
public int fuelTicks;
|
|
public int honkTicks;
|
|
|
|
public Boolean lowHonk;
|
|
public int honkPitch;
|
|
|
|
public float accumulatedSteamRelease;
|
|
|
|
int tickOffset;
|
|
double[] stress;
|
|
|
|
// advancements
|
|
public Player backwardsDriver;
|
|
|
|
public Train(UUID id, UUID owner, TrackGraph graph, List<Carriage> carriages, List<Integer> carriageSpacing,
|
|
boolean doubleEnded) {
|
|
|
|
this.id = id;
|
|
this.owner = owner;
|
|
this.graph = graph;
|
|
this.carriages = carriages;
|
|
this.carriageSpacing = carriageSpacing;
|
|
this.icon = TrainIconType.getDefault();
|
|
this.stress = new double[carriageSpacing.size()];
|
|
this.name = Lang.translateDirect("train.unnamed");
|
|
this.status = new TrainStatus(this);
|
|
this.doubleEnded = doubleEnded;
|
|
|
|
carriages.forEach(c -> c.setTrain(this));
|
|
|
|
navigation = new Navigation(this);
|
|
runtime = new ScheduleRuntime(this);
|
|
migratingPoints = new ArrayList<>();
|
|
currentStation = null;
|
|
manualSteer = SteerDirection.NONE;
|
|
occupiedSignalBlocks = new HashMap<>();
|
|
reservedSignalBlocks = new HashSet<>();
|
|
occupiedObservers = new HashSet<>();
|
|
cachedObserverFiltering = new HashMap<>();
|
|
tickOffset = Create.RANDOM.nextInt(100);
|
|
}
|
|
|
|
public void earlyTick(Level level) {
|
|
status.tick(level);
|
|
if (graph == null && !migratingPoints.isEmpty())
|
|
reattachToTracks(level);
|
|
if (graph == null) {
|
|
addToSignalGroups(occupiedSignalBlocks.keySet());
|
|
return;
|
|
}
|
|
|
|
if (updateSignalBlocks) {
|
|
updateSignalBlocks = false;
|
|
collectInitiallyOccupiedSignalBlocks();
|
|
}
|
|
|
|
addToSignalGroups(occupiedSignalBlocks.keySet());
|
|
addToSignalGroups(reservedSignalBlocks);
|
|
|
|
if (occupiedObservers.isEmpty())
|
|
return;
|
|
|
|
tickOccupiedObservers(level);
|
|
}
|
|
|
|
private void tickOccupiedObservers(Level level) {
|
|
int storageVersion = 0;
|
|
for (Carriage carriage : carriages)
|
|
storageVersion += carriage.storage.getVersion();
|
|
|
|
for (UUID uuid : occupiedObservers) {
|
|
TrackObserver observer = graph.getPoint(EdgePointType.OBSERVER, uuid);
|
|
if (observer == null)
|
|
continue;
|
|
|
|
ItemStack filter = observer.getFilter();
|
|
if (filter.isEmpty()) {
|
|
observer.keepAlive(this);
|
|
continue;
|
|
}
|
|
|
|
Pair<Integer, Boolean> cachedMatch = cachedObserverFiltering.computeIfAbsent(uuid, $ -> Pair.of(-1, false));
|
|
boolean shouldActivate = cachedMatch.getSecond();
|
|
|
|
if (cachedMatch.getFirst() == storageVersion) {
|
|
if (shouldActivate)
|
|
observer.keepAlive(this);
|
|
continue;
|
|
}
|
|
|
|
shouldActivate = false;
|
|
for (Carriage carriage : carriages) {
|
|
if (shouldActivate)
|
|
break;
|
|
|
|
IItemHandlerModifiable inv = carriage.storage.getItems();
|
|
if (inv != null) {
|
|
for (int slot = 0; slot < inv.getSlots(); slot++) {
|
|
if (shouldActivate)
|
|
break;
|
|
ItemStack extractItem = inv.extractItem(slot, 1, true);
|
|
if (extractItem.isEmpty())
|
|
continue;
|
|
shouldActivate |= FilterItem.test(level, extractItem, filter);
|
|
}
|
|
}
|
|
|
|
IFluidHandler tank = carriage.storage.getFluids();
|
|
if (tank != null) {
|
|
for (int slot = 0; slot < tank.getTanks(); slot++) {
|
|
if (shouldActivate)
|
|
break;
|
|
FluidStack drain = tank.drain(1, FluidAction.SIMULATE);
|
|
if (drain.isEmpty())
|
|
continue;
|
|
shouldActivate |= FilterItem.test(level, drain, filter);
|
|
}
|
|
}
|
|
}
|
|
|
|
cachedObserverFiltering.put(uuid, Pair.of(storageVersion, shouldActivate));
|
|
|
|
if (shouldActivate)
|
|
observer.keepAlive(this);
|
|
}
|
|
}
|
|
|
|
private void addToSignalGroups(Collection<UUID> groups) {
|
|
Map<UUID, SignalEdgeGroup> groupMap = Create.RAILWAYS.signalEdgeGroups;
|
|
for (Iterator<UUID> iterator = groups.iterator(); iterator.hasNext();) {
|
|
SignalEdgeGroup signalEdgeGroup = groupMap.get(iterator.next());
|
|
if (signalEdgeGroup == null)
|
|
iterator.remove();
|
|
else
|
|
signalEdgeGroup.trains.add(this);
|
|
}
|
|
}
|
|
|
|
public void tick(Level level) {
|
|
Create.RAILWAYS.markTracksDirty();
|
|
|
|
if (graph == null) {
|
|
carriages.forEach(c -> c.manageEntities(level));
|
|
updateConductors();
|
|
return;
|
|
}
|
|
|
|
updateConductors();
|
|
runtime.tick(level);
|
|
navigation.tick(level);
|
|
|
|
tickPassiveSlowdown();
|
|
if (derailed)
|
|
tickDerailedSlowdown();
|
|
|
|
double distance = speed;
|
|
Carriage previousCarriage = null;
|
|
int carriageCount = carriages.size();
|
|
boolean stalled = false;
|
|
double maxStress = 0;
|
|
|
|
if (carriageWaitingForChunks != -1)
|
|
distance = 0;
|
|
|
|
for (int i = 0; i < carriageCount; i++) {
|
|
Carriage carriage = carriages.get(i);
|
|
if (previousCarriage != null) {
|
|
int target = carriageSpacing.get(i - 1);
|
|
double actual = target;
|
|
|
|
TravellingPoint leadingPoint = carriage.getLeadingPoint();
|
|
TravellingPoint trailingPoint = previousCarriage.getTrailingPoint();
|
|
|
|
int entries = 0;
|
|
double total = 0;
|
|
|
|
if (leadingPoint.node1 != null && trailingPoint.node1 != null) {
|
|
ResourceKey<Level> d1 = leadingPoint.node1.getLocation().dimension;
|
|
ResourceKey<Level> d2 = trailingPoint.node1.getLocation().dimension;
|
|
for (boolean b : Iterate.trueAndFalse) {
|
|
ResourceKey<Level> d = b ? d1 : d2;
|
|
if (!b && d1.equals(d2))
|
|
continue;
|
|
if (!d1.equals(d2))
|
|
continue;
|
|
|
|
DimensionalCarriageEntity dimensional = carriage.getDimensionalIfPresent(d);
|
|
DimensionalCarriageEntity dimensional2 = previousCarriage.getDimensionalIfPresent(d);
|
|
if (dimensional == null || dimensional2 == null)
|
|
continue;
|
|
|
|
Vec3 leadingAnchor = dimensional.leadingAnchor();
|
|
Vec3 trailingAnchor = dimensional2.trailingAnchor();
|
|
if (leadingAnchor == null || trailingAnchor == null)
|
|
continue;
|
|
|
|
double distanceTo = leadingAnchor.distanceToSqr(trailingAnchor);
|
|
if (carriage.leadingBogey().isUpsideDown() != previousCarriage.trailingBogey().isUpsideDown()) {
|
|
distanceTo = Math.sqrt(distanceTo - 4);
|
|
} else {
|
|
distanceTo = Math.sqrt(distanceTo);
|
|
}
|
|
total += distanceTo;
|
|
entries++;
|
|
}
|
|
}
|
|
|
|
|
|
if (entries > 0)
|
|
actual = total / entries;
|
|
|
|
stress[i - 1] = target - actual;
|
|
maxStress = Math.max(maxStress, Math.abs(target - actual));
|
|
}
|
|
|
|
previousCarriage = carriage;
|
|
|
|
if (carriage.stalled) {
|
|
if (speedBeforeStall == null)
|
|
speedBeforeStall = speed;
|
|
distance = 0;
|
|
speed = 0;
|
|
stalled = true;
|
|
}
|
|
}
|
|
|
|
if (!stalled && speedBeforeStall != null) {
|
|
speed = Mth.clamp(speedBeforeStall, -1, 1);
|
|
speedBeforeStall = null;
|
|
}
|
|
|
|
// positive stress: carriages should move apart
|
|
// negative stress: carriages should move closer
|
|
|
|
boolean approachingStation = navigation.distanceToDestination < 5;
|
|
double leadingModifier = approachingStation ? 0.75d : 0.5d;
|
|
double trailingModifier = approachingStation ? 0d : 0.125d;
|
|
|
|
boolean blocked = false;
|
|
boolean iterateFromBack = speed < 0;
|
|
|
|
for (int index = 0; index < carriageCount; index++) {
|
|
int i = iterateFromBack ? carriageCount - 1 - index : index;
|
|
double leadingStress = i == 0 ? 0 : stress[i - 1] * -(iterateFromBack ? trailingModifier : leadingModifier);
|
|
double trailingStress =
|
|
i == stress.length ? 0 : stress[i] * (iterateFromBack ? leadingModifier : trailingModifier);
|
|
|
|
Carriage carriage = carriages.get(i);
|
|
|
|
TravellingPoint toFollowForward = i == 0 ? null
|
|
: carriages.get(i - 1)
|
|
.getTrailingPoint();
|
|
|
|
TravellingPoint toFollowBackward = i == carriageCount - 1 ? null
|
|
: carriages.get(i + 1)
|
|
.getLeadingPoint();
|
|
|
|
double totalStress = derailed ? 0 : leadingStress + trailingStress;
|
|
|
|
boolean first = i == 0;
|
|
boolean last = i == carriageCount - 1;
|
|
int carriageType = first ? last ? Carriage.BOTH : Carriage.FIRST : last ? Carriage.LAST : Carriage.MIDDLE;
|
|
double actualDistance =
|
|
carriage.travel(level, graph, distance + totalStress, toFollowForward, toFollowBackward, carriageType);
|
|
blocked |= carriage.blocked || carriage.isOnIncompatibleTrack();
|
|
|
|
boolean onTwoBogeys = carriage.isOnTwoBogeys();
|
|
maxStress = Math.max(maxStress, onTwoBogeys ? carriage.bogeySpacing - carriage.getAnchorDiff() : 0);
|
|
maxStress = Math.max(maxStress, carriage.leadingBogey()
|
|
.getStress());
|
|
if (onTwoBogeys)
|
|
maxStress = Math.max(maxStress, carriage.trailingBogey()
|
|
.getStress());
|
|
|
|
if (index == 0) {
|
|
distance = actualDistance;
|
|
collideWithOtherTrains(level, carriage);
|
|
backwardsDriver = null;
|
|
if (graph == null)
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (blocked) {
|
|
speed = 0;
|
|
navigation.cancelNavigation();
|
|
runtime.tick(level);
|
|
status.endOfTrack();
|
|
|
|
} else if (maxStress > 4) {
|
|
speed = 0;
|
|
navigation.cancelNavigation();
|
|
runtime.tick(level);
|
|
derailed = true;
|
|
status.highStress();
|
|
|
|
} else if (speed != 0)
|
|
status.trackOK();
|
|
|
|
updateNavigationTarget(distance);
|
|
}
|
|
|
|
public IEdgePointListener frontSignalListener() {
|
|
return (distance, couple) -> {
|
|
|
|
if (couple.getFirst()instanceof GlobalStation station) {
|
|
if (!station.canApproachFrom(couple.getSecond()
|
|
.getSecond()) || navigation.destination != station)
|
|
return false;
|
|
speed = 0;
|
|
navigation.distanceToDestination = 0;
|
|
navigation.currentPath.clear();
|
|
arriveAt(navigation.destination);
|
|
navigation.destination = null;
|
|
return true;
|
|
}
|
|
|
|
if (couple.getFirst()instanceof TrackObserver observer) {
|
|
occupiedObservers.add(observer.getId());
|
|
return false;
|
|
}
|
|
|
|
if (!(couple.getFirst()instanceof SignalBoundary signal))
|
|
return false;
|
|
if (navigation.waitingForSignal != null && navigation.waitingForSignal.getFirst()
|
|
.equals(signal.getId())) {
|
|
speed = 0;
|
|
navigation.distanceToSignal = 0;
|
|
return true;
|
|
}
|
|
|
|
UUID groupId = signal.getGroup(couple.getSecond()
|
|
.getSecond());
|
|
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId);
|
|
if (signalEdgeGroup == null)
|
|
return false;
|
|
|
|
if ((runtime.getSchedule() == null || runtime.paused) && signalEdgeGroup.isOccupiedUnless(this))
|
|
carriages.forEach(c -> c.forEachPresentEntity(cce -> cce.getControllingPlayer()
|
|
.ifPresent(uuid -> AllAdvancements.RED_SIGNAL.awardTo(cce.level.getPlayerByUUID(uuid)))));
|
|
|
|
signalEdgeGroup.reserved = signal;
|
|
occupy(groupId, signal.id);
|
|
return false;
|
|
|
|
};
|
|
}
|
|
|
|
public void cancelStall() {
|
|
speedBeforeStall = null;
|
|
carriages.forEach(c -> {
|
|
c.stalled = false;
|
|
c.forEachPresentEntity(cce -> cce.getContraption()
|
|
.getActors()
|
|
.forEach(pair -> {
|
|
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.getKey().state);
|
|
if (behaviour != null)
|
|
behaviour.cancelStall(pair.getValue());
|
|
}));
|
|
});
|
|
}
|
|
|
|
private boolean occupy(UUID groupId, @Nullable UUID boundaryId) {
|
|
reservedSignalBlocks.remove(groupId);
|
|
if (boundaryId != null && occupiedSignalBlocks.containsKey(groupId))
|
|
if (boundaryId.equals(occupiedSignalBlocks.get(groupId)))
|
|
return false;
|
|
return occupiedSignalBlocks.put(groupId, boundaryId) == null;
|
|
}
|
|
|
|
public IEdgePointListener backSignalListener() {
|
|
return (distance, couple) -> {
|
|
if (couple.getFirst()instanceof TrackObserver observer) {
|
|
occupiedObservers.remove(observer.getId());
|
|
cachedObserverFiltering.remove(observer.getId());
|
|
return false;
|
|
}
|
|
if (!(couple.getFirst()instanceof SignalBoundary signal))
|
|
return false;
|
|
UUID groupId = signal.getGroup(couple.getSecond()
|
|
.getFirst());
|
|
occupiedSignalBlocks.remove(groupId);
|
|
return false;
|
|
};
|
|
}
|
|
|
|
private void updateNavigationTarget(double distance) {
|
|
if (navigation.destination == null)
|
|
return;
|
|
|
|
Pair<UUID, Boolean> blockingSignal = navigation.waitingForSignal;
|
|
boolean fullRefresh = navigation.distanceToDestination > 100 && navigation.distanceToDestination % 100 > 20;
|
|
boolean signalRefresh = blockingSignal != null && navigation.distanceToSignal % 50 > 5;
|
|
boolean partialRefresh = navigation.distanceToDestination < 100 && navigation.distanceToDestination % 50 > 5;
|
|
|
|
double toSubstract = navigation.destinationBehindTrain ? -distance : distance;
|
|
boolean navigatingManually = runtime.paused;
|
|
|
|
navigation.distanceToDestination -= toSubstract;
|
|
if (blockingSignal != null) {
|
|
navigation.distanceToSignal -= toSubstract;
|
|
signalRefresh &= navigation.distanceToSignal % 50 < 5;
|
|
}
|
|
|
|
fullRefresh &= navigation.distanceToDestination % 100 <= 20;
|
|
partialRefresh &= navigation.distanceToDestination % 50 <= 5;
|
|
|
|
if (blockingSignal != null && navigation.ticksWaitingForSignal % 100 == 50) {
|
|
SignalBoundary signal = graph.getPoint(EdgePointType.SIGNAL, blockingSignal.getFirst());
|
|
fullRefresh |= signal != null && signal.types.get(blockingSignal.getSecond()) == SignalType.CROSS_SIGNAL;
|
|
}
|
|
|
|
if (signalRefresh)
|
|
navigation.waitingForSignal = null;
|
|
if (!fullRefresh && !partialRefresh)
|
|
return;
|
|
if (!reservedSignalBlocks.isEmpty())
|
|
return;
|
|
|
|
GlobalStation destination = navigation.destination;
|
|
if (!navigatingManually && fullRefresh) {
|
|
GlobalStation preferredDestination = runtime.startCurrentInstruction();
|
|
if (preferredDestination != null)
|
|
destination = preferredDestination;
|
|
}
|
|
|
|
navigation.startNavigation(destination, navigatingManually ? -1 : Double.MAX_VALUE, false);
|
|
}
|
|
|
|
private void tickDerailedSlowdown() {
|
|
speed /= 3f;
|
|
if (Mth.equal(speed, 0))
|
|
speed = 0;
|
|
}
|
|
|
|
private void tickPassiveSlowdown() {
|
|
if (!manualTick && navigation.destination == null && speed != 0) {
|
|
double acceleration = acceleration();
|
|
if (speed > 0) {
|
|
speed = Math.max(speed - acceleration, 0);
|
|
} else
|
|
speed = Math.min(speed + acceleration, 0);
|
|
}
|
|
manualTick = false;
|
|
}
|
|
|
|
private void updateConductors() {
|
|
for (Carriage carriage : carriages)
|
|
carriage.updateConductors();
|
|
}
|
|
|
|
public boolean hasForwardConductor() {
|
|
for (Carriage carriage : carriages)
|
|
if (carriage.presentConductors.getFirst())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
public boolean hasBackwardConductor() {
|
|
for (Carriage carriage : carriages)
|
|
if (carriage.presentConductors.getSecond())
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
private void collideWithOtherTrains(Level level, Carriage carriage) {
|
|
if (derailed)
|
|
return;
|
|
|
|
TravellingPoint trailingPoint = carriage.getTrailingPoint();
|
|
TravellingPoint leadingPoint = carriage.getLeadingPoint();
|
|
|
|
if (leadingPoint.node1 == null || trailingPoint.node1 == null)
|
|
return;
|
|
ResourceKey<Level> dimension = leadingPoint.node1.getLocation().dimension;
|
|
if (!dimension.equals(trailingPoint.node1.getLocation().dimension))
|
|
return;
|
|
|
|
Vec3 start = (speed < 0 ? trailingPoint : leadingPoint).getPosition();
|
|
Vec3 end = (speed < 0 ? leadingPoint : trailingPoint).getPosition();
|
|
|
|
Pair<Train, Vec3> collision = findCollidingTrain(level, start, end, this, dimension);
|
|
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,
|
|
ResourceKey<Level> dimension) {
|
|
for (Train train : Create.RAILWAYS.sided(level).trains.values()) {
|
|
if (train == ignore)
|
|
continue;
|
|
|
|
Vec3 diff = end.subtract(start);
|
|
Vec3 lastPoint = null;
|
|
|
|
for (Carriage otherCarriage : train.carriages) {
|
|
for (boolean betweenBits : Iterate.trueAndFalse) {
|
|
if (betweenBits && lastPoint == null)
|
|
continue;
|
|
|
|
TravellingPoint otherLeading = otherCarriage.getLeadingPoint();
|
|
TravellingPoint otherTrailing = otherCarriage.getTrailingPoint();
|
|
if (otherLeading.edge == null || otherTrailing.edge == null)
|
|
continue;
|
|
ResourceKey<Level> otherDimension = otherLeading.node1.getLocation().dimension;
|
|
if (!otherDimension.equals(otherTrailing.node1.getLocation().dimension))
|
|
continue;
|
|
if (!otherDimension.equals(dimension))
|
|
continue;
|
|
|
|
Vec3 start2 = otherLeading.getPosition();
|
|
Vec3 end2 = otherTrailing.getPosition();
|
|
if (betweenBits) {
|
|
end2 = start2;
|
|
start2 = lastPoint;
|
|
}
|
|
|
|
lastPoint = end2;
|
|
|
|
if ((end.y < end2.y - 3 || end2.y < end.y - 3)
|
|
&& (start.y < start2.y - 3 || start2.y < start.y - 3))
|
|
continue;
|
|
|
|
Vec3 diff2 = end2.subtract(start2);
|
|
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)
|
|
continue;
|
|
if (!Mth.equal(normedDiff2.dot(intersectSphere.subtract(start2)
|
|
.normalize()), 1))
|
|
continue;
|
|
intersect = new double[2];
|
|
intersect[0] = intersectSphere.distanceTo(start) - .125;
|
|
intersect[1] = intersectSphere.distanceTo(start2) - .125;
|
|
}
|
|
|
|
if (intersect[0] > diff.length())
|
|
continue;
|
|
if (intersect[1] > diff2.length())
|
|
continue;
|
|
if (intersect[0] < 0)
|
|
continue;
|
|
if (intersect[1] < 0)
|
|
continue;
|
|
|
|
return Pair.of(train, start.add(normedDiff.scale(intersect[0])));
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void crash() {
|
|
navigation.cancelNavigation();
|
|
if (derailed)
|
|
return;
|
|
speed = -Mth.clamp(speed, -.5, .5);
|
|
derailed = true;
|
|
graph = null;
|
|
status.crash();
|
|
|
|
for (Carriage carriage : carriages)
|
|
carriage.forEachPresentEntity(e -> e.getIndirectPassengers()
|
|
.forEach(entity -> {
|
|
if (!(entity instanceof Player p))
|
|
return;
|
|
Optional<UUID> controllingPlayer = e.getControllingPlayer();
|
|
if (controllingPlayer.isPresent() && controllingPlayer.get()
|
|
.equals(p.getUUID()))
|
|
return;
|
|
AllAdvancements.TRAIN_CRASH.awardTo(p);
|
|
}));
|
|
|
|
if (backwardsDriver != null)
|
|
AllAdvancements.TRAIN_CRASH_BACKWARDS.awardTo(backwardsDriver);
|
|
}
|
|
|
|
public boolean disassemble(Direction assemblyDirection, BlockPos pos) {
|
|
if (!canDisassemble())
|
|
return false;
|
|
|
|
int offset = 1;
|
|
boolean backwards = currentlyBackwards;
|
|
Level level = null;
|
|
|
|
for (int i = 0; i < carriages.size(); i++) {
|
|
|
|
Carriage carriage = carriages.get(backwards ? carriages.size() - i - 1 : i);
|
|
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
|
|
if (entity == null)
|
|
return false;
|
|
level = entity.level;
|
|
|
|
if (entity.getContraption()instanceof CarriageContraption cc)
|
|
cc.returnStorageForDisassembly(carriage.storage);
|
|
entity.setPos(Vec3
|
|
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset).below(carriage.leadingBogey().isUpsideDown() ? 2 : 0)));
|
|
entity.disassemble();
|
|
|
|
for (CarriageBogey bogey : carriage.bogeys) {
|
|
if (bogey == null)
|
|
continue;
|
|
Vec3 bogeyPosition = bogey.getAnchorPosition();
|
|
if (bogeyPosition == null) continue;
|
|
BlockEntity be = level.getBlockEntity(new BlockPos(bogeyPosition));
|
|
if (!(be instanceof AbstractBogeyTileEntity sbte))
|
|
continue;
|
|
sbte.setBogeyData(bogey.bogeyData);
|
|
}
|
|
|
|
offset += carriage.bogeySpacing;
|
|
|
|
if (i < carriageSpacing.size())
|
|
offset += carriageSpacing.get(backwards ? carriageSpacing.size() - i - 1 : i);
|
|
}
|
|
|
|
GlobalStation currentStation = getCurrentStation();
|
|
if (currentStation != null) {
|
|
currentStation.cancelReservation(this);
|
|
BlockPos tilePos = currentStation.getTilePos();
|
|
if (level.getBlockEntity(tilePos)instanceof StationTileEntity ste)
|
|
ste.lastDisassembledTrainName = name.copy();
|
|
}
|
|
|
|
Create.RAILWAYS.removeTrain(id);
|
|
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false));
|
|
return true;
|
|
}
|
|
|
|
public boolean canDisassemble() {
|
|
for (Carriage carriage : carriages) {
|
|
if (carriage.presentInMultipleDimensions())
|
|
return false;
|
|
CarriageContraptionEntity entity = carriage.anyAvailableEntity();
|
|
if (entity == null)
|
|
return false;
|
|
if (!Mth.equal(entity.pitch, 0))
|
|
return false;
|
|
if (!Mth.equal(((entity.yaw % 90) + 360) % 90, 0))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public boolean isTravellingOn(TrackNode node) {
|
|
MutableBoolean affected = new MutableBoolean(false);
|
|
forEachTravellingPoint(tp -> {
|
|
if (tp.node1 == node || tp.node2 == node)
|
|
affected.setTrue();
|
|
});
|
|
return affected.booleanValue();
|
|
}
|
|
|
|
public void detachFromTracks() {
|
|
migratingPoints.clear();
|
|
navigation.cancelNavigation();
|
|
forEachTravellingPoint(tp -> migratingPoints.add(new TrainMigration(tp)));
|
|
graph = null;
|
|
}
|
|
|
|
public void forEachTravellingPoint(Consumer<TravellingPoint> callback) {
|
|
for (Carriage c : carriages) {
|
|
c.leadingBogey().points.forEach(callback::accept);
|
|
if (c.isOnTwoBogeys())
|
|
c.trailingBogey().points.forEach(callback::accept);
|
|
}
|
|
}
|
|
|
|
public void forEachTravellingPointBackwards(BiConsumer<TravellingPoint, Double> callback) {
|
|
double lastWheelOffset = 0;
|
|
for (int i = 0; i < carriages.size(); i++) {
|
|
int index = carriages.size() - i - 1;
|
|
Carriage carriage = carriages.get(index);
|
|
CarriageBogey trailingBogey = carriage.trailingBogey();
|
|
double trailSpacing = trailingBogey.type.getWheelPointSpacing();
|
|
|
|
// trailing point
|
|
callback.accept(trailingBogey.trailing(),
|
|
i == 0 ? 0 : carriageSpacing.get(index) - lastWheelOffset - trailSpacing / 2);
|
|
|
|
// inside 1st bogey
|
|
callback.accept(trailingBogey.leading(), trailSpacing);
|
|
|
|
lastWheelOffset = trailSpacing / 2;
|
|
|
|
if (!carriage.isOnTwoBogeys())
|
|
continue;
|
|
|
|
CarriageBogey leadingBogey = carriage.leadingBogey();
|
|
double leadSpacing = carriage.leadingBogey().type.getWheelPointSpacing();
|
|
|
|
// between bogeys
|
|
callback.accept(leadingBogey.trailing(), carriage.bogeySpacing - lastWheelOffset - leadSpacing / 2);
|
|
|
|
// inside 2nd bogey
|
|
callback.accept(trailingBogey.leading(), leadSpacing);
|
|
|
|
lastWheelOffset = leadSpacing / 2;
|
|
}
|
|
}
|
|
|
|
public void reattachToTracks(Level level) {
|
|
if (migrationCooldown > 0) {
|
|
migrationCooldown--;
|
|
return;
|
|
}
|
|
|
|
Set<Entry<UUID, TrackGraph>> entrySet = new HashSet<>(Create.RAILWAYS.trackNetworks.entrySet());
|
|
Map<UUID, List<GraphLocation>> successfulMigrations = new HashMap<>();
|
|
for (TrainMigration md : migratingPoints) {
|
|
for (Iterator<Entry<UUID, TrackGraph>> iterator = entrySet.iterator(); iterator.hasNext();) {
|
|
Entry<UUID, TrackGraph> entry = iterator.next();
|
|
GraphLocation gl = md.tryMigratingTo(entry.getValue());
|
|
if (gl == null) {
|
|
iterator.remove();
|
|
continue;
|
|
}
|
|
successfulMigrations.computeIfAbsent(entry.getKey(), uuid -> new ArrayList<>())
|
|
.add(gl);
|
|
}
|
|
}
|
|
|
|
if (entrySet.isEmpty()) {
|
|
migrationCooldown = 40;
|
|
status.failedMigration();
|
|
derailed = true;
|
|
return;
|
|
}
|
|
|
|
for (Entry<UUID, TrackGraph> entry : entrySet) {
|
|
graph = entry.getValue();
|
|
List<GraphLocation> locations = successfulMigrations.get(entry.getKey());
|
|
forEachTravellingPoint(tp -> tp.migrateTo(locations));
|
|
migratingPoints.clear();
|
|
if (derailed)
|
|
status.successfulMigration();
|
|
derailed = false;
|
|
if (runtime.getSchedule() != null && runtime.state == State.IN_TRANSIT)
|
|
runtime.state = State.PRE_TRANSIT;
|
|
GlobalStation currentStation = getCurrentStation();
|
|
if (currentStation != null)
|
|
currentStation.reserveFor(this);
|
|
updateSignalBlocks = true;
|
|
migrationCooldown = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
public int getTotalLength() {
|
|
int length = 0;
|
|
for (int i = 0; i < carriages.size(); i++) {
|
|
Carriage carriage = carriages.get(i);
|
|
if (i == 0)
|
|
length += carriage.leadingBogey().type.getWheelPointSpacing() / 2;
|
|
if (i == carriages.size() - 1)
|
|
length += carriage.trailingBogey().type.getWheelPointSpacing() / 2;
|
|
|
|
length += carriage.bogeySpacing;
|
|
if (i < carriageSpacing.size())
|
|
length += carriageSpacing.get(i);
|
|
}
|
|
return length;
|
|
}
|
|
|
|
public void leaveStation() {
|
|
GlobalStation currentStation = getCurrentStation();
|
|
if (currentStation != null)
|
|
currentStation.trainDeparted(this);
|
|
this.currentStation = null;
|
|
}
|
|
|
|
public void arriveAt(GlobalStation station) {
|
|
setCurrentStation(station);
|
|
reservedSignalBlocks.clear();
|
|
runtime.destinationReached();
|
|
}
|
|
|
|
public void setCurrentStation(GlobalStation station) {
|
|
currentStation = station.id;
|
|
}
|
|
|
|
public GlobalStation getCurrentStation() {
|
|
if (currentStation == null)
|
|
return null;
|
|
if (graph == null)
|
|
return null;
|
|
return graph.getPoint(EdgePointType.STATION, currentStation);
|
|
}
|
|
|
|
@Nullable
|
|
public LivingEntity getOwner(Level level) {
|
|
try {
|
|
UUID uuid = owner;
|
|
return uuid == null ? null
|
|
: level.getServer()
|
|
.getPlayerList()
|
|
.getPlayer(uuid);
|
|
} catch (IllegalArgumentException illegalargumentexception) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void approachTargetSpeed(float accelerationMod) {
|
|
double actualTarget = targetSpeed;
|
|
if (Mth.equal(actualTarget, speed))
|
|
return;
|
|
if (manualTick)
|
|
leaveStation();
|
|
double acceleration = acceleration();
|
|
if (speed < actualTarget)
|
|
speed = Math.min(speed + acceleration * accelerationMod, actualTarget);
|
|
else if (speed > actualTarget)
|
|
speed = Math.max(speed - acceleration * accelerationMod, actualTarget);
|
|
}
|
|
|
|
public void collectInitiallyOccupiedSignalBlocks() {
|
|
TravellingPoint trailingPoint = carriages.get(carriages.size() - 1)
|
|
.getTrailingPoint();
|
|
TrackNode node1 = trailingPoint.node1;
|
|
TrackNode node2 = trailingPoint.node2;
|
|
TrackEdge edge = trailingPoint.edge;
|
|
double position = trailingPoint.position;
|
|
EdgeData signalData = edge.getEdgeData();
|
|
|
|
occupiedSignalBlocks.clear();
|
|
reservedSignalBlocks.clear();
|
|
occupiedObservers.clear();
|
|
cachedObserverFiltering.clear();
|
|
|
|
TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position, false);
|
|
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
|
|
MutableObject<UUID> prevGroup = new MutableObject<>(null);
|
|
|
|
if (signalData.hasSignalBoundaries()) {
|
|
SignalBoundary nextBoundary = signalData.next(EdgePointType.SIGNAL, position);
|
|
if (nextBoundary == null) {
|
|
double d = 0;
|
|
SignalBoundary prev = null;
|
|
SignalBoundary current = signalData.next(EdgePointType.SIGNAL, 0);
|
|
while (current != null) {
|
|
prev = current;
|
|
d = current.getLocationOn(edge);
|
|
current = signalData.next(EdgePointType.SIGNAL, d);
|
|
}
|
|
if (prev != null) {
|
|
UUID group = prev.getGroup(node2);
|
|
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
|
occupy(group, null);
|
|
prevGroup.setValue(group);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
UUID group = nextBoundary.getGroup(node1);
|
|
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
|
occupy(group, null);
|
|
prevGroup.setValue(group);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
UUID groupId = signalData.getEffectiveEdgeGroupId(graph);
|
|
if (allGroups.containsKey(groupId)) {
|
|
occupy(groupId, null);
|
|
prevGroup.setValue(groupId);
|
|
}
|
|
}
|
|
|
|
forEachTravellingPointBackwards((tp, d) -> {
|
|
signalScout.travel(graph, d, signalScout.follow(tp), (distance, couple) -> {
|
|
if (couple.getFirst()instanceof TrackObserver observer) {
|
|
occupiedObservers.add(observer.getId());
|
|
return false;
|
|
}
|
|
if (!(couple.getFirst()instanceof SignalBoundary signal))
|
|
return false;
|
|
couple.getSecond()
|
|
.map(signal::getGroup)
|
|
.forEach(id -> {
|
|
if (!Create.RAILWAYS.signalEdgeGroups.containsKey(id))
|
|
return;
|
|
if (id.equals(prevGroup.getValue()))
|
|
return;
|
|
occupy(id, null);
|
|
prevGroup.setValue(id);
|
|
});
|
|
return false;
|
|
}, signalScout.ignoreTurns());
|
|
});
|
|
|
|
}
|
|
|
|
public boolean shouldCarriageSyncThisTick(long gameTicks, int updateInterval) {
|
|
return (gameTicks + tickOffset) % updateInterval == 0;
|
|
}
|
|
|
|
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,
|
|
RED_SIGNAL = 25, REDSTONE_RED_SIGNAL = 400;
|
|
}
|
|
|
|
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 void burnFuel() {
|
|
if (fuelTicks > 0) {
|
|
fuelTicks--;
|
|
return;
|
|
}
|
|
|
|
boolean iterateFromBack = speed < 0;
|
|
int carriageCount = carriages.size();
|
|
|
|
for (int index = 0; index < carriageCount; index++) {
|
|
int i = iterateFromBack ? carriageCount - 1 - index : index;
|
|
Carriage carriage = carriages.get(i);
|
|
IItemHandlerModifiable fuelItems = carriage.storage.getFuelItems();
|
|
if (fuelItems == null)
|
|
continue;
|
|
|
|
for (int slot = 0; slot < fuelItems.getSlots(); slot++) {
|
|
ItemStack stack = fuelItems.extractItem(slot, 1, true);
|
|
int burnTime = ForgeHooks.getBurnTime(stack, null);
|
|
if (burnTime <= 0)
|
|
continue;
|
|
|
|
stack = fuelItems.extractItem(slot, 1, false);
|
|
fuelTicks += burnTime * stack.getCount();
|
|
ItemStack containerItem = stack.getContainerItem();
|
|
if (!containerItem.isEmpty())
|
|
ItemHandlerHelper.insertItemStacked(fuelItems, containerItem, false);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public float maxSpeed() {
|
|
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTopSpeed.getF()
|
|
: AllConfigs.SERVER.trains.trainTopSpeed.getF()) / 20;
|
|
}
|
|
|
|
public float maxTurnSpeed() {
|
|
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainTurningTopSpeed.getF()
|
|
: AllConfigs.SERVER.trains.trainTurningTopSpeed.getF()) / 20;
|
|
}
|
|
|
|
public float acceleration() {
|
|
return (fuelTicks > 0 ? AllConfigs.SERVER.trains.poweredTrainAcceleration.getF()
|
|
: AllConfigs.SERVER.trains.trainAcceleration.getF()) / 400;
|
|
}
|
|
|
|
public CompoundTag write(DimensionPalette dimensions) {
|
|
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, c -> c.write(dimensions)));
|
|
tag.putIntArray("CarriageSpacing", carriageSpacing);
|
|
tag.putBoolean("DoubleEnded", doubleEnded);
|
|
tag.putDouble("Speed", speed);
|
|
tag.putDouble("Throttle", throttle);
|
|
if (speedBeforeStall != null)
|
|
tag.putDouble("SpeedBeforeStall", speedBeforeStall);
|
|
tag.putInt("Fuel", fuelTicks);
|
|
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("Derailed", derailed);
|
|
tag.putBoolean("UpdateSignals", updateSignalBlocks);
|
|
tag.put("SignalBlocks", NBTHelper.writeCompoundList(occupiedSignalBlocks.entrySet(), e -> {
|
|
CompoundTag compoundTag = new CompoundTag();
|
|
compoundTag.putUUID("Id", e.getKey());
|
|
if (e.getValue() != null)
|
|
compoundTag.putUUID("Boundary", e.getValue());
|
|
return compoundTag;
|
|
}));
|
|
tag.put("ReservedSignalBlocks", NBTHelper.writeCompoundList(reservedSignalBlocks, uid -> {
|
|
CompoundTag compoundTag = new CompoundTag();
|
|
compoundTag.putUUID("Id", uid);
|
|
return compoundTag;
|
|
}));
|
|
tag.put("OccupiedObservers", NBTHelper.writeCompoundList(occupiedObservers, uid -> {
|
|
CompoundTag compoundTag = new CompoundTag();
|
|
compoundTag.putUUID("Id", uid);
|
|
return compoundTag;
|
|
}));
|
|
tag.put("MigratingPoints", NBTHelper.writeCompoundList(migratingPoints, tm -> tm.write(dimensions)));
|
|
|
|
tag.put("Runtime", runtime.write());
|
|
tag.put("Navigation", navigation.write(dimensions));
|
|
|
|
return tag;
|
|
}
|
|
|
|
public static Train read(CompoundTag tag, Map<UUID, TrackGraph> trackNetworks, DimensionPalette dimensions) {
|
|
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, dimensions)));
|
|
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.throttle = tag.getDouble("Throttle");
|
|
if (tag.contains("SpeedBeforeStall"))
|
|
train.speedBeforeStall = tag.getDouble("SpeedBeforeStall");
|
|
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.derailed = tag.getBoolean("Derailed");
|
|
train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
|
|
train.fuelTicks = tag.getInt("Fuel");
|
|
|
|
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks
|
|
.put(c.getUUID("Id"), c.contains("Boundary") ? c.getUUID("Boundary") : null));
|
|
NBTHelper.iterateCompoundList(tag.getList("ReservedSignalBlocks", Tag.TAG_COMPOUND),
|
|
c -> train.reservedSignalBlocks.add(c.getUUID("Id")));
|
|
NBTHelper.iterateCompoundList(tag.getList("OccupiedObservers", Tag.TAG_COMPOUND),
|
|
c -> train.occupiedObservers.add(c.getUUID("Id")));
|
|
NBTHelper.iterateCompoundList(tag.getList("MigratingPoints", Tag.TAG_COMPOUND),
|
|
c -> train.migratingPoints.add(TrainMigration.read(c, dimensions)));
|
|
|
|
train.runtime.read(tag.getCompound("Runtime"));
|
|
train.navigation.read(tag.getCompound("Navigation"), graph, dimensions);
|
|
|
|
if (train.getCurrentStation() != null)
|
|
train.getCurrentStation()
|
|
.reserveFor(train);
|
|
|
|
return train;
|
|
}
|
|
|
|
public int countPlayerPassengers() {
|
|
AtomicInteger count = new AtomicInteger();
|
|
for (Carriage carriage : carriages)
|
|
carriage.forEachPresentEntity(e -> e.getIndirectPassengers()
|
|
.forEach(p -> {
|
|
if (p instanceof Player)
|
|
count.incrementAndGet();
|
|
}));
|
|
return count.intValue();
|
|
}
|
|
|
|
public void determineHonk(Level level) {
|
|
if (lowHonk != null)
|
|
return;
|
|
for (int index = 0; index < carriages.size(); index++) {
|
|
Carriage carriage = carriages.get(index);
|
|
DimensionalCarriageEntity dimensional = carriage.getDimensionalIfPresent(level.dimension());
|
|
if (dimensional == null)
|
|
return;
|
|
CarriageContraptionEntity entity = dimensional.entity.get();
|
|
if (entity == null || !(entity.getContraption()instanceof CarriageContraption otherCC))
|
|
break;
|
|
Pair<Boolean, Integer> first = otherCC.soundQueue.getFirstWhistle(entity);
|
|
if (first != null) {
|
|
lowHonk = first.getFirst();
|
|
honkPitch = first.getSecond();
|
|
}
|
|
}
|
|
}
|
|
|
|
public float distanceToLocationSqr(Level level, Vec3 location) {
|
|
float distance = Float.MAX_VALUE;
|
|
for (Carriage carriage : carriages) {
|
|
DimensionalCarriageEntity dce = carriage.getDimensionalIfPresent(level.dimension());
|
|
if (dce == null || dce.positionAnchor == null)
|
|
continue;
|
|
distance = Math.min(distance, (float) dce.positionAnchor.distanceToSqr(location));
|
|
}
|
|
return distance;
|
|
}
|
|
|
|
}
|