Create/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlock.java
simibubi e5c6ca157c Squashed commit of the following:
commit 053dd09df6c426ab5e570f42a1edb5df3d0fbd01
Merge: 6d1e1c71d ecc645eba
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

commit ecc645eba7
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

commit 205e47352e
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 21:02:19 2023 -0700

    Fix up ItemOutline

commit 6cf204f6af
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

commit fe049bc771
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:26:16 2023 -0700

    Revert "Revert "Rewrite outline buffering""

    This reverts commit 726bfaf0

commit 435b4c1c16
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

commit 662da6bab1
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

commit 122fe77afa
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 8 20:15:46 2023 -0700

    Fix up upside down rendering

commit d83285e8a4
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

commit cdb0ad210b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 10:15:47 2023 +0100

    Fixed merge artifact

commit 457d5f33ed
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

commit 00e953a585
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

commit a7a25896c1
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

commit 4e4e227a35
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 10:10:30 2023 +0100

    Cleanup to cycle groups

commit aa94fc97d1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun May 7 09:50:50 2023 +0100

    Removed unused import of Railways

commit 7622128bec
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

commit 1e4d5504ee
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 18:03:39 2023 -0700

    Don't revert non-buggy changes

commit b306cf2124
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 18:00:59 2023 -0700

    Take materials into consideration when trains pathfind

commit fca02ae4bf
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat May 6 10:25:51 2023 -0700

    Add materials to track graph

commit 726bfaf0b5
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 21:16:49 2023 -0700

    Revert "Rewrite outline buffering"

    This reverts commit d4106d545b.

commit 171897bed2
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 20:55:25 2023 -0700

    Fix up style cycling

commit cbd0cf20da
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Fri May 5 07:32:06 2023 -0700

    clean up nether portal carriage handling

commit d556f08876
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

commit da26c0ccbf
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

commit 81eeadb853
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 16:15:28 2023 +0100

    Small cleanup

commit c7e9df973c
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 16:13:51 2023 +0100

    Fixed issue raised in #1

commit 2f285b6eb7
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Mon May 1 08:13:27 2023 -0700

    add data gen

commit 206de01311
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

commit 6564f4fa73
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

commit e5d7595822
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon May 1 10:09:03 2023 +0100

    Connected Custom Bogey Particle Types To CarriageParticles

commit e91753a33c
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 30 19:51:26 2023 -0700

    Fix up some problems

commit 9815f1490f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:12:43 2023 +0100

    Implemented default data when shifting styles

commit da30e78815
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:12:14 2023 +0100

    Added Particles To Bogey Style (And Respective Builder)

commit 08c000b8ba
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:01:19 2023 +0100

    Added Backup Rendering If A Size Is Not Present

commit 2b76e8d7b3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 21:00:40 2023 +0100

    Added Common Renderer To Remove Function

commit 411ec36f57
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:59:50 2023 +0100

    Added Display Name To Standard Bogey Style

commit 112306d5d4
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:59:30 2023 +0100

    Displayed new style name when changing betweeen them

commit 5634670b27
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:06:00 2023 +0100

    General Cleanup

commit 0f7a8b7b24
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:05:50 2023 +0100

    Implemented Changes To Remaining Classes

commit 8aedc00f96
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:02:06 2023 +0100

    Removed Bogey Style Handling From Registrate

commit edf8079abf
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:40 2023 +0100

    Removed Unused Registry Handling

commit 6a185c4e72
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:16 2023 +0100

    Refactored Bogey Sizes

commit e10d07ddc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 30 20:01:00 2023 +0100

    Overhauled Bogey Style

commit 74d98a2ad5
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

commit e629d02f50
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 9 07:18:22 2023 -0700

    Track API

    Clean up code a bit

commit d9ce6ce995
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sun Apr 9 07:14:46 2023 -0700

    Track API?

    Fix placement

commit 7fbf08ba54
Author: techno-sam <linux.techno.sam@gmail.com>
Date:   Sat Apr 8 11:11:24 2023 -0700

    Track API?

    Fix up some placement issues

commit 35644f1434
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

commit f7c56b867a
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

commit 2a59fd7e8a
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

commit 5ba30d6a85
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

commit d52065808c
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

commit 53240bd42f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 21:42:29 2023 +0100

    Corrected Bogey InteractionResult To Pass

commit 69326e361a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 21:30:28 2023 +0100

    Fixed Default Values When Used Styles Are Removed

commit 4f176979de
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 19:33:17 2023 +0100

    Fixed Carriage Sounds (Again)

commit 1e80af3303
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 19:27:58 2023 +0100

    Refactored Bogey Sizes To Seperate Class

commit 129be61fee
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 17:20:17 2023 +0100

    Fixed Bogey Sound Loading

commit 2543185a55
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Mon Apr 3 09:45:23 2023 +0100

    Added Bogey Sound Customisation

commit 1ad5ae9514
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

commit 96566b1614
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

commit eedd984738
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:53:55 2023 +0100

    Fixed Large Bogey Size

commit 68ca0974c6
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:47:58 2023 +0100

    Implemented Style Cycling & Default Values

commit a55ba4267a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:46:15 2023 +0100

    Implemented renderer instance creator

commit 43523302c2
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sun Apr 2 16:45:33 2023 +0100

    Removed Unused Standard Bogey Instance

commit 773e084422
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

commit 0c0b5a1ed6
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Apr 1 18:39:58 2023 +0100

    Linked Style Registry To Bogey Blocks

commit 71f839ee51
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Apr 1 18:39:03 2023 +0100

    Replaced size boolean with direct use of size enum

commit 50ff081704
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:47:13 2023 +0100

    Added Resource Location To NBT helper methods

commit d1e1f7ec5a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:47:13 2023 +0100

    Re-worked BogeyStyles

commit da593fccb1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 30 18:46:02 2023 +0100

    Refactored IBogeyBlock to AbstractBogeyBlock and extracted relevant StandardBogeyBlock implementations

commit 17432c9113
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Sat Mar 25 10:20:50 2023 +0000

    Fixed Incorrect Registry Loading

commit c7d899369a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:44:03 2023 +0000

    Registered Registers

commit 6d862290d7
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:43:23 2023 +0000

    Added BogeyStyleBuilder To Registrate

commit 3dfb9e3b3b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:43:08 2023 +0000

    Implemented AllBogeyStyles

commit c9e71b462d
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:42:56 2023 +0000

    Created BogeyStyleBuilder

commit a90977d642
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:42:25 2023 +0000

    Created AllRegistries and BogeyStyle Registry

commit 154d455f3f
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Fri Mar 24 23:41:56 2023 +0000

    Added BogeyStyle Wrapper

commit dfb7640bfc
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:50:41 2023 +0000

    Removed left over logging statement

commit 9920536cc3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:50:18 2023 +0000

    Implemented Secondary Shaft To Large Renderer

commit 6cd40cc6f9
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

commit 06fb901144
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:39:11 2023 +0000

    Implemented Common Rendering For StandardBogeyRenderer

commit 435b0f8266
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:38:40 2023 +0000

    Added Common Renderer

commit 96a0623dab
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 18:38:29 2023 +0000

    Implemented BlockState Models For Rendering

commit 469d9d592b
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:42:28 2023 +0000

    Added Standard Bogey Instance (Might be redundant)

commit 2661d260d8
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:42:06 2023 +0000

    Refactored Changes To Existing Methods

commit 9ded16fbab
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:41:15 2023 +0000

    Integrated BogeyRenderer To BogeyInstance (Also Corrected Rendering In Contraption)

commit 4a82fcbca1
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:40:13 2023 +0000

    Implemented Changes To StandardBogeyBlock

commit 7238fb93f3
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Thu Mar 23 17:39:51 2023 +0000

    Added Renderer To IBogeyBlock

commit ded4c1f613
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

commit 91727cc84a
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Wed Mar 22 17:03:28 2023 +0000

    Implemented Model Data Initializer to StandardBogeyRenderer

commit 6d98a1f469
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Wed Mar 22 17:03:00 2023 +0000

    Added Contraption Model Instance Initializer

commit 3c02fe6ecc
Author: Rabbitminers <79579164+Rabbitminers@users.noreply.github.com>
Date:   Tue Mar 21 22:45:34 2023 +0000

    Added missing render type check

commit 6672c49649
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Tue Mar 21 22:37:36 2023 +0000

    Re-created standard bogey with test api

commit a8a9491fa0
Author: Rabbitminers <Rabbitminers2.0@gmail.com>
Date:   Tue Mar 21 22:34:54 2023 +0000

    Implemented Proof Of Concept Generic Bogey Renderer

commit e4e5ac1c40
Author: SpottyTheTurtle <69260662+SpottyTheTurtle@users.noreply.github.com>
Date:   Sat Mar 11 21:34:59 2023 +0000

    init
2023-05-09 18:23:47 +02:00

823 lines
29 KiB
Java

package com.simibubi.create.content.logistics.trains.track;
import static com.simibubi.create.AllShapes.TRACK_ASC;
import static com.simibubi.create.AllShapes.TRACK_CROSS;
import static com.simibubi.create.AllShapes.TRACK_CROSS_DIAG;
import static com.simibubi.create.AllShapes.TRACK_CROSS_DIAG_ORTHO;
import static com.simibubi.create.AllShapes.TRACK_CROSS_ORTHO_DIAG;
import static com.simibubi.create.AllShapes.TRACK_DIAG;
import static com.simibubi.create.AllShapes.TRACK_ORTHO;
import static com.simibubi.create.AllShapes.TRACK_ORTHO_LONG;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import java.util.function.Consumer;
import com.simibubi.create.AllTags;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import it.unimi.dsi.fastutil.objects.Object2IntArrayMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import org.jetbrains.annotations.Nullable;
import com.google.common.base.Predicates;
import com.jozufozu.flywheel.core.PartialModel;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueEntity;
import com.simibubi.create.content.contraptions.particle.CubeParticleData;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.content.curiosities.girder.GirderBlock;
import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
import com.simibubi.create.content.logistics.trains.TrackNodeLocation.DiscoveredLocation;
import com.simibubi.create.content.logistics.trains.TrackPropagator;
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour.RenderedTrackOverlayType;
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.StationTileEntity;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.block.render.MultiPosDestructionHandler;
import com.simibubi.create.foundation.block.render.ReducedDestroyEffects;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.core.Direction.AxisDirection;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.NetherPortalBlock;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.pathfinder.BlockPathTypes;
import net.minecraft.world.level.portal.PortalForcer;
import net.minecraft.world.level.portal.PortalInfo;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraft.world.ticks.LevelTickAccess;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.client.IBlockRenderProperties;
//init
public class TrackBlock extends Block
implements ITE<TrackTileEntity>, IWrenchable, ITrackBlock, ISpecialBlockItemRequirement, ProperWaterloggedBlock {
public static final EnumProperty<TrackShape> SHAPE = EnumProperty.create("shape", TrackShape.class);
public static final BooleanProperty HAS_TE = BooleanProperty.create("turn");
protected final TrackMaterial material;
public TrackBlock(Properties p_49795_, TrackMaterial material) {
super(p_49795_);
registerDefaultState(defaultBlockState().setValue(SHAPE, TrackShape.ZO)
.setValue(HAS_TE, false)
.setValue(WATERLOGGED, false));
this.material = material;
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> p_49915_) {
super.createBlockStateDefinition(p_49915_.add(SHAPE, HAS_TE, WATERLOGGED));
}
@Override
public BlockPathTypes getAiPathNodeType(BlockState state, BlockGetter world, BlockPos pos, Mob entity) {
return BlockPathTypes.RAIL;
}
@Override
public FluidState getFluidState(BlockState state) {
return fluidState(state);
}
@OnlyIn(Dist.CLIENT)
public void initializeClient(Consumer<IBlockRenderProperties> consumer) {
consumer.accept(new RenderProperties());
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
BlockState stateForPlacement = withWater(super.getStateForPlacement(ctx), ctx);
if (ctx.getPlayer() == null)
return stateForPlacement;
Vec3 lookAngle = ctx.getPlayer()
.getLookAngle();
lookAngle = lookAngle.multiply(1, 0, 1);
if (Mth.equal(lookAngle.length(), 0))
lookAngle = VecHelper.rotate(new Vec3(0, 0, 1), -ctx.getPlayer()
.getYRot(), Axis.Y);
lookAngle = lookAngle.normalize();
TrackShape best = TrackShape.ZO;
double bestValue = Float.MAX_VALUE;
for (TrackShape shape : TrackShape.values()) {
if (shape.isJunction() || shape.isPortal())
continue;
Vec3 axis = shape.getAxes()
.get(0);
double distance = Math.min(axis.distanceToSqr(lookAngle), axis.normalize()
.scale(-1)
.distanceToSqr(lookAngle));
if (distance > bestValue)
continue;
bestValue = distance;
best = shape;
}
Level level = ctx.getLevel();
Vec3 bestAxis = best.getAxes()
.get(0);
if (bestAxis.lengthSqr() == 1)
for (boolean neg : Iterate.trueAndFalse) {
BlockPos offset = ctx.getClickedPos()
.offset(new BlockPos(bestAxis.scale(neg ? -1 : 1)));
if (level.getBlockState(offset)
.isFaceSturdy(level, offset, Direction.UP)
&& !level.getBlockState(offset.above())
.isFaceSturdy(level, offset, Direction.DOWN)) {
if (best == TrackShape.XO)
best = neg ? TrackShape.AW : TrackShape.AE;
if (best == TrackShape.ZO)
best = neg ? TrackShape.AN : TrackShape.AS;
}
}
return stateForPlacement.setValue(SHAPE, best);
}
@Override
public PushReaction getPistonPushReaction(BlockState pState) {
return PushReaction.BLOCK;
}
@Override
public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) {
super.playerWillDestroy(pLevel, pPos, pState, pPlayer);
if (pLevel.isClientSide())
return;
if (!pPlayer.isCreative())
return;
withTileEntityDo(pLevel, pPos, te -> {
te.cancelDrops = true;
te.removeInboundConnections();
});
}
@Override
public void onPlace(BlockState pState, Level pLevel, BlockPos pPos, BlockState pOldState, boolean pIsMoving) {
if (pOldState.getBlock() == this && pState.setValue(HAS_TE, true) == pOldState.setValue(HAS_TE, true))
return;
if (pLevel.isClientSide)
return;
LevelTickAccess<Block> blockTicks = pLevel.getBlockTicks();
if (!blockTicks.hasScheduledTick(pPos, this))
pLevel.scheduleTick(pPos, this, 1);
updateGirders(pState, pLevel, pPos, blockTicks);
}
@Override
public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) {
super.setPlacedBy(pLevel, pPos, pState, pPlacer, pStack);
withTileEntityDo(pLevel, pPos, TrackTileEntity::validateConnections);
}
@Override
public void tick(BlockState state, ServerLevel level, BlockPos pos, Random p_60465_) {
TrackPropagator.onRailAdded(level, pos, state);
if (!state.getValue(SHAPE)
.isPortal())
connectToNether(level, pos, state);
}
protected void connectToNether(ServerLevel level, BlockPos pos, BlockState state) {
TrackShape shape = state.getValue(TrackBlock.SHAPE);
Axis portalTest = shape == TrackShape.XO ? Axis.X : shape == TrackShape.ZO ? Axis.Z : null;
if (portalTest == null)
return;
boolean pop = false;
String fail = null;
BlockPos failPos = null;
for (Direction d : Iterate.directionsInAxis(portalTest)) {
BlockPos portalPos = pos.relative(d);
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof NetherPortalBlock))
continue;
pop = true;
Pair<ServerLevel, BlockFace> otherSide = getOtherSide(level, new BlockFace(pos, d));
if (otherSide == null) {
fail = "missing";
continue;
}
ServerLevel otherLevel = otherSide.getFirst();
BlockFace otherTrack = otherSide.getSecond();
BlockPos otherTrackPos = otherTrack.getPos();
BlockState existing = otherLevel.getBlockState(otherTrackPos);
if (!existing.getMaterial()
.isReplaceable()) {
fail = "blocked";
failPos = otherTrackPos;
continue;
}
level.setBlock(pos, state.setValue(SHAPE, TrackShape.asPortal(d))
.setValue(HAS_TE, true), 3);
BlockEntity te = level.getBlockEntity(pos);
if (te instanceof TrackTileEntity tte)
tte.bind(otherLevel.dimension(), otherTrackPos);
otherLevel.setBlock(otherTrackPos, state.setValue(SHAPE, TrackShape.asPortal(otherTrack.getFace()))
.setValue(HAS_TE, true), 3);
BlockEntity otherTe = otherLevel.getBlockEntity(otherTrackPos);
if (otherTe instanceof TrackTileEntity tte)
tte.bind(level.dimension(), pos);
pop = false;
}
if (!pop)
return;
level.destroyBlock(pos, true);
if (fail == null)
return;
Player player = level.getNearestPlayer(pos.getX(), pos.getY(), pos.getZ(), 10, Predicates.alwaysTrue());
if (player == null)
return;
player.displayClientMessage(Components.literal("<!> ").append(Lang.translateDirect("portal_track.failed"))
.withStyle(ChatFormatting.GOLD), false);
MutableComponent component =
failPos != null ? Lang.translateDirect("portal_track." + fail, failPos.getX(), failPos.getY(), failPos.getZ())
: Lang.translateDirect("portal_track." + fail);
player.displayClientMessage(Components.literal(" - ").withStyle(ChatFormatting.GRAY)
.append(component.withStyle(st -> st.withColor(0xFFD3B4))), false);
}
protected Pair<ServerLevel, BlockFace> getOtherSide(ServerLevel level, BlockFace inboundTrack) {
BlockPos portalPos = inboundTrack.getConnectedPos();
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof NetherPortalBlock))
return null;
MinecraftServer minecraftserver = level.getServer();
ResourceKey<Level> resourcekey = level.dimension() == Level.NETHER ? Level.OVERWORLD : Level.NETHER;
ServerLevel otherLevel = minecraftserver.getLevel(resourcekey);
if (otherLevel == null || !minecraftserver.isNetherEnabled())
return null;
PortalForcer teleporter = otherLevel.getPortalForcer();
SuperGlueEntity probe = new SuperGlueEntity(level, new AABB(portalPos));
probe.setYRot(inboundTrack.getFace()
.toYRot());
PortalInfo portalinfo = teleporter.getPortalInfo(probe, otherLevel, probe::findDimensionEntryPoint);
if (portalinfo == null)
return null;
BlockPos otherPortalPos = new BlockPos(portalinfo.pos);
BlockState otherPortalState = otherLevel.getBlockState(otherPortalPos);
if (!(otherPortalState.getBlock() instanceof NetherPortalBlock))
return null;
Direction targetDirection = inboundTrack.getFace();
if (targetDirection.getAxis() == otherPortalState.getValue(NetherPortalBlock.AXIS))
targetDirection = targetDirection.getClockWise();
BlockPos otherPos = otherPortalPos.relative(targetDirection);
return Pair.of(otherLevel, new BlockFace(otherPos, targetDirection.getOpposite()));
}
@Override
public BlockState updateShape(BlockState state, Direction pDirection, BlockState pNeighborState,
LevelAccessor level, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(level, state, pCurrentPos);
TrackShape shape = state.getValue(SHAPE);
if (!shape.isPortal())
return state;
for (Direction d : Iterate.horizontalDirections) {
if (TrackShape.asPortal(d) != state.getValue(SHAPE))
continue;
if (pDirection != d)
continue;
BlockPos portalPos = pCurrentPos.relative(d);
BlockState portalState = level.getBlockState(portalPos);
if (!(portalState.getBlock() instanceof NetherPortalBlock))
return Blocks.AIR.defaultBlockState();
}
return state;
}
@Override
public Collection<DiscoveredLocation> getConnected(BlockGetter worldIn, BlockPos pos, BlockState state,
boolean linear, TrackNodeLocation connectedTo) {
Collection<DiscoveredLocation> list;
BlockGetter world = connectedTo != null && worldIn instanceof ServerLevel sl ? sl.getServer()
.getLevel(connectedTo.dimension) : worldIn;
if (getTrackAxes(world, pos, state).size() > 1) {
Vec3 center = Vec3.atBottomCenterOf(pos)
.add(0, getElevationAtCenter(world, pos, state), 0);
TrackShape shape = state.getValue(TrackBlock.SHAPE);
list = new ArrayList<>();
for (Vec3 axis : getTrackAxes(world, pos, state))
for (boolean fromCenter : Iterate.trueAndFalse)
ITrackBlock.addToListIfConnected(connectedTo, list,
(d, b) -> axis.scale(b ? 0 : fromCenter ? -d : d)
.add(center),
b -> shape.getNormal(), b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, axis,
null, (b, v) -> ITrackBlock.getMaterialSimple(world, v));
} else
list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo);
if (!state.getValue(HAS_TE))
return list;
if (linear)
return list;
BlockEntity blockEntity = world.getBlockEntity(pos);
if (!(blockEntity instanceof TrackTileEntity trackTE))
return list;
Map<BlockPos, BezierConnection> connections = trackTE.getConnections();
connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list,
(d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get,
b -> world instanceof Level l ? l.dimension() : Level.OVERWORLD, null, bc, (b, v) -> ITrackBlock.getMaterialSimple(world, v, bc.getMaterial())));
if (trackTE.boundLocation == null || !(world instanceof ServerLevel level))
return list;
ResourceKey<Level> otherDim = trackTE.boundLocation.getFirst();
ServerLevel otherLevel = level.getServer()
.getLevel(otherDim);
if (otherLevel == null)
return list;
BlockPos boundPos = trackTE.boundLocation.getSecond();
BlockState boundState = otherLevel.getBlockState(boundPos);
if (!AllTags.AllBlockTags.TRACKS.matches(boundState))
return list;
Vec3 center = Vec3.atBottomCenterOf(pos)
.add(0, getElevationAtCenter(world, pos, state), 0);
Vec3 boundCenter = Vec3.atBottomCenterOf(boundPos)
.add(0, getElevationAtCenter(otherLevel, boundPos, boundState), 0);
TrackShape shape = state.getValue(TrackBlock.SHAPE);
TrackShape boundShape = boundState.getValue(TrackBlock.SHAPE);
Vec3 boundAxis = getTrackAxes(otherLevel, boundPos, boundState).get(0);
getTrackAxes(world, pos, state).forEach(axis -> {
ITrackBlock.addToListIfConnected(connectedTo, list, (d, b) -> (b ? axis : boundAxis).scale(d)
.add(b ? center : boundCenter), b -> (b ? shape : boundShape).getNormal(),
b -> b ? level.dimension() : otherLevel.dimension(), axis, null, (b, v) -> ITrackBlock.getMaterialSimple(b ? level : otherLevel, v));
});
return list;
}
public void animateTick(BlockState pState, Level pLevel, BlockPos pPos, Random pRand) {
if (!pState.getValue(SHAPE)
.isPortal())
return;
Vec3 v = Vec3.atLowerCornerOf(pPos)
.subtract(.125f, 0, .125f);
CubeParticleData data =
new CubeParticleData(1, pRand.nextFloat(), 1, .0125f + .0625f * pRand.nextFloat(), 30, false);
pLevel.addParticle(data, v.x + pRand.nextFloat() * 1.5f, v.y + .25f, v.z + pRand.nextFloat() * 1.5f, 0.0D,
0.04D, 0.0D);
}
@Override
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
boolean removeTE = false;
if (pState.getValue(HAS_TE) && (!pState.is(pNewState.getBlock()) || !pNewState.getValue(HAS_TE))) {
BlockEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof TrackTileEntity && !pLevel.isClientSide)
((TrackTileEntity) blockEntity).removeInboundConnections();
removeTE = true;
}
if (pNewState.getBlock() != this || pState.setValue(HAS_TE, true) != pNewState.setValue(HAS_TE, true))
TrackPropagator.onRailRemoved(pLevel, pPos, pState);
if (removeTE)
pLevel.removeBlockEntity(pPos);
if (!pLevel.isClientSide)
updateGirders(pState, pLevel, pPos, pLevel.getBlockTicks());
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult hit) {
if (world.isClientSide)
return InteractionResult.SUCCESS;
for (Entry<BlockPos, BoundingBox> entry : StationTileEntity.assemblyAreas.get(world)
.entrySet()) {
if (!entry.getValue()
.isInside(pos))
continue;
if (world.getBlockEntity(entry.getKey()) instanceof StationTileEntity station)
if (station.trackClicked(player, hand, this, state, pos))
return InteractionResult.SUCCESS;
}
return InteractionResult.PASS;
}
private void updateGirders(BlockState pState, Level pLevel, BlockPos pPos, LevelTickAccess<Block> blockTicks) {
for (Vec3 vec3 : getTrackAxes(pLevel, pPos, pState)) {
if (vec3.length() > 1 || vec3.y != 0)
continue;
for (int side : Iterate.positiveAndNegative) {
BlockPos girderPos = pPos.below()
.offset(vec3.z * side, 0, vec3.x * side);
BlockState girderState = pLevel.getBlockState(girderPos);
if (girderState.getBlock() instanceof GirderBlock girderBlock
&& !blockTicks.hasScheduledTick(girderPos, girderBlock))
pLevel.scheduleTick(girderPos, girderBlock, 1);
}
}
}
@Override
public boolean canSurvive(BlockState state, LevelReader reader, BlockPos pos) {
return reader.getBlockState(pos.below())
.getBlock() != this;
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter p_60556_, BlockPos p_60557_, CollisionContext p_60558_) {
return getFullShape(state);
}
@Override
public VoxelShape getInteractionShape(BlockState state, BlockGetter pLevel, BlockPos pPos) {
return getFullShape(state);
}
private VoxelShape getFullShape(BlockState state) {
switch (state.getValue(SHAPE)) {
case AE:
return TRACK_ASC.get(Direction.EAST);
case AW:
return TRACK_ASC.get(Direction.WEST);
case AN:
return TRACK_ASC.get(Direction.NORTH);
case AS:
return TRACK_ASC.get(Direction.SOUTH);
case CR_D:
return TRACK_CROSS_DIAG;
case CR_NDX:
return TRACK_CROSS_ORTHO_DIAG.get(Direction.SOUTH);
case CR_NDZ:
return TRACK_CROSS_DIAG_ORTHO.get(Direction.SOUTH);
case CR_O:
return TRACK_CROSS;
case CR_PDX:
return TRACK_CROSS_DIAG_ORTHO.get(Direction.EAST);
case CR_PDZ:
return TRACK_CROSS_ORTHO_DIAG.get(Direction.EAST);
case ND:
return TRACK_DIAG.get(Direction.SOUTH);
case PD:
return TRACK_DIAG.get(Direction.EAST);
case XO:
return TRACK_ORTHO.get(Direction.EAST);
case ZO:
return TRACK_ORTHO.get(Direction.SOUTH);
case TE:
return TRACK_ORTHO_LONG.get(Direction.EAST);
case TW:
return TRACK_ORTHO_LONG.get(Direction.WEST);
case TS:
return TRACK_ORTHO_LONG.get(Direction.SOUTH);
case TN:
return TRACK_ORTHO_LONG.get(Direction.NORTH);
case NONE:
default:
}
return AllShapes.TRACK_FALLBACK;
}
@Override
public VoxelShape getCollisionShape(BlockState pState, BlockGetter pLevel, BlockPos pPos,
CollisionContext pContext) {
switch (pState.getValue(SHAPE)) {
case AE, AW, AN, AS:
return Shapes.empty();
default:
return AllShapes.TRACK_COLLISION;
}
}
@Override
public BlockEntity newBlockEntity(BlockPos p_153215_, BlockState state) {
if (!state.getValue(HAS_TE))
return null;
return AllTileEntities.TRACK.create(p_153215_, state);
}
@Override
public Class<TrackTileEntity> getTileEntityClass() {
return TrackTileEntity.class;
}
@Override
public BlockEntityType<? extends TrackTileEntity> getTileEntityType() {
return AllTileEntities.TRACK.get();
}
@Override
public Vec3 getUpNormal(BlockGetter world, BlockPos pos, BlockState state) {
return state.getValue(SHAPE)
.getNormal();
}
@Override
public List<Vec3> getTrackAxes(BlockGetter world, BlockPos pos, BlockState state) {
return state.getValue(SHAPE)
.getAxes();
}
@Override
public Vec3 getCurveStart(BlockGetter world, BlockPos pos, BlockState state, Vec3 axis) {
boolean vertical = axis.y != 0;
return VecHelper.getCenterOf(pos)
.add(0, (vertical ? 0 : -.5f), 0)
.add(axis.scale(.5));
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
return InteractionResult.SUCCESS;
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
Player player = context.getPlayer();
Level level = context.getLevel();
if (!level.isClientSide && !player.isCreative() && state.getValue(HAS_TE)) {
BlockEntity blockEntity = level.getBlockEntity(context.getClickedPos());
if (blockEntity instanceof TrackTileEntity trackTE) {
trackTE.cancelDrops = true;
trackTE.connections.values()
.forEach(bc -> bc.addItemsToPlayer(player));
}
}
return IWrenchable.super.onSneakWrenched(state, context);
}
@Override
public BlockState overlay(BlockGetter world, BlockPos pos, BlockState existing, BlockState placed) {
if (placed.getBlock() != this)
return existing;
TrackShape existingShape = existing.getValue(SHAPE);
TrackShape placedShape = placed.getValue(SHAPE);
TrackShape combinedShape = null;
for (boolean flip : Iterate.trueAndFalse) {
TrackShape s1 = flip ? existingShape : placedShape;
TrackShape s2 = flip ? placedShape : existingShape;
if (s1 == TrackShape.XO && s2 == TrackShape.ZO)
combinedShape = TrackShape.CR_O;
if (s1 == TrackShape.PD && s2 == TrackShape.ND)
combinedShape = TrackShape.CR_D;
if (s1 == TrackShape.XO && s2 == TrackShape.PD)
combinedShape = TrackShape.CR_PDX;
if (s1 == TrackShape.ZO && s2 == TrackShape.PD)
combinedShape = TrackShape.CR_PDZ;
if (s1 == TrackShape.XO && s2 == TrackShape.ND)
combinedShape = TrackShape.CR_NDX;
if (s1 == TrackShape.ZO && s2 == TrackShape.ND)
combinedShape = TrackShape.CR_NDZ;
}
if (combinedShape != null)
existing = existing.setValue(SHAPE, combinedShape);
return existing;
}
@Override
public BlockState rotate(BlockState state, Rotation pRotation) {
return state.setValue(SHAPE, state.getValue(SHAPE)
.rotate(pRotation));
}
@Override
public BlockState mirror(BlockState state, Mirror pMirror) {
return state.setValue(SHAPE, state.getValue(SHAPE)
.mirror(pMirror));
}
@Override
public BlockState getBogeyAnchor(BlockGetter world, BlockPos pos, BlockState state) {
return AllBlocks.SMALL_BOGEY.getDefaultState()
.setValue(BlockStateProperties.HORIZONTAL_AXIS, state.getValue(SHAPE) == TrackShape.XO ? Axis.X : Axis.Z);
}
@Override
@OnlyIn(Dist.CLIENT)
public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction,
PoseStack ms) {
TransformStack.cast(ms)
.rotateCentered(Direction.UP, AngleHelper.rad(AngleHelper.horizontalAngle(direction)));
return AllBlockPartials.TRACK_ASSEMBLING_OVERLAY;
}
@Override
@OnlyIn(Dist.CLIENT)
public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state,
BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack ms, RenderedTrackOverlayType type) {
TransformStack msr = TransformStack.cast(ms);
Vec3 axis = null;
Vec3 diff = null;
Vec3 normal = null;
Vec3 offset = null;
if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackTileEntity trackTE) {
BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget());
if (bc != null) {
double length = Mth.floor(bc.getLength() * 2);
int seg = bezierPoint.segment() + 1;
double t = seg / length;
double tpre = (seg - 1) / length;
double tpost = (seg + 1) / length;
offset = bc.getPosition(t);
normal = bc.getNormal(t);
diff = bc.getPosition(tpost)
.subtract(bc.getPosition(tpre))
.normalize();
msr.translate(offset.subtract(Vec3.atBottomCenterOf(pos)));
msr.translate(0, -4 / 16f, 0);
} else
return null;
}
if (normal == null) {
axis = state.getValue(SHAPE)
.getAxes()
.get(0);
diff = axis.scale(direction.getStep())
.normalize();
normal = getUpNormal(world, pos, state);
}
Vec3 angles = TrackRenderer.getModelAngles(normal, diff);
msr.centre()
.rotateYRadians(angles.y)
.rotateXRadians(angles.x)
.unCentre();
if (axis != null)
msr.translate(0, axis.y != 0 ? 7 / 16f : 0, axis.y != 0 ? direction.getStep() * 2.5f / 16f : 0);
else {
msr.translate(0, 4 / 16f, 0);
if (direction == AxisDirection.NEGATIVE)
msr.rotateCentered(Direction.UP, Mth.PI);
}
return switch (type) {
case DUAL_SIGNAL -> AllBlockPartials.TRACK_SIGNAL_DUAL_OVERLAY;
case OBSERVER -> AllBlockPartials.TRACK_OBSERVER_OVERLAY;
case SIGNAL -> AllBlockPartials.TRACK_SIGNAL_OVERLAY;
case STATION -> AllBlockPartials.TRACK_STATION_OVERLAY;
};
}
@Override
public boolean trackEquals(BlockState state1, BlockState state2) {
return state1.getBlock() == this && state2.getBlock() == this
&& state1.setValue(HAS_TE, false) == state2.setValue(HAS_TE, false);
}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
int sameTypeTrackAmount = 1;
Object2IntMap<TrackMaterial> otherTrackAmounts = new Object2IntArrayMap<>();
int girderAmount = 0;
if (te instanceof TrackTileEntity track) {
for (BezierConnection bezierConnection : track.getConnections()
.values()) {
if (!bezierConnection.isPrimary())
continue;
TrackMaterial material = bezierConnection.getMaterial();
if (material == getMaterial()) {
sameTypeTrackAmount += bezierConnection.getTrackItemCost();
} else {
otherTrackAmounts.put(material, otherTrackAmounts.getOrDefault(material, 0) + 1);
}
girderAmount += bezierConnection.getGirderItemCost();
}
}
List<ItemStack> stacks = new ArrayList<>();
while (sameTypeTrackAmount > 0) {
stacks.add(new ItemStack(state.getBlock(), Math.min(sameTypeTrackAmount, 64)));
sameTypeTrackAmount -= 64;
}
for (TrackMaterial material : otherTrackAmounts.keySet()) {
int amt = otherTrackAmounts.getOrDefault(material, 0);
while (amt > 0) {
stacks.add(new ItemStack(material.getTrackBlock().get(), Math.min(amt, 64)));
amt -= 64;
}
}
while (girderAmount > 0) {
stacks.add(AllBlocks.METAL_GIRDER.asStack(Math.min(girderAmount, 64)));
girderAmount -= 64;
}
return new ItemRequirement(ItemUseType.CONSUME, stacks);
}
@Override
public TrackMaterial getMaterial() {
return material;
}
public static class RenderProperties extends ReducedDestroyEffects implements MultiPosDestructionHandler {
@Override
@Nullable
public Set<BlockPos> getExtraPositions(ClientLevel level, BlockPos pos, BlockState blockState,
int progress) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof TrackTileEntity track) {
return new HashSet<>(track.connections.keySet());
}
return null;
}
}
}