Create/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.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

783 lines
25 KiB
Java

package com.simibubi.create.content.logistics.trains.track;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import com.jozufozu.flywheel.util.Color;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.AllTags;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer;
import com.simibubi.create.content.logistics.trains.BezierConnection;
import com.simibubi.create.content.logistics.trains.ITrackBlock;
import com.simibubi.create.content.logistics.trains.TrackMaterial;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
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.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.util.Mth;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.HitResult.Type;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.ItemHandlerHelper;
public class TrackPlacement {
public static class PlacementInfo {
public PlacementInfo(TrackMaterial material) {
this.trackMaterial = material;
}
BezierConnection curve = null;
boolean valid = false;
int end1Extent = 0;
int end2Extent = 0;
String message = null;
public int requiredTracks = 0;
public boolean hasRequiredTracks = false;
public int requiredPavement = 0;
public boolean hasRequiredPavement = false;
public final TrackMaterial trackMaterial;
// for visualisation
Vec3 end1;
Vec3 end2;
Vec3 normal1;
Vec3 normal2;
Vec3 axis1;
Vec3 axis2;
BlockPos pos1;
BlockPos pos2;
public PlacementInfo withMessage(String message) {
this.message = "track." + message;
return this;
}
public PlacementInfo tooJumbly() {
curve = null;
return this;
}
}
public static PlacementInfo cached;
static BlockPos hoveringPos;
static boolean hoveringMaxed;
static int hoveringAngle;
static ItemStack lastItem;
public static PlacementInfo tryConnect(Level level, Player player, BlockPos pos2, BlockState state2,
ItemStack stack, boolean girder, boolean maximiseTurn) {
Vec3 lookVec = player.getLookAngle();
int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8;
int maxLength = AllConfigs.SERVER.trains.maxTrackPlacementLength.get();
if (level.isClientSide && cached != null && pos2.equals(hoveringPos) && stack.equals(lastItem)
&& hoveringMaxed == maximiseTurn && lookAngle == hoveringAngle)
return cached;
PlacementInfo info = new PlacementInfo(TrackMaterial.fromItem(stack.getItem()));
hoveringMaxed = maximiseTurn;
hoveringAngle = lookAngle;
hoveringPos = pos2;
lastItem = stack;
cached = info;
ITrackBlock track = (ITrackBlock) state2.getBlock();
Pair<Vec3, AxisDirection> nearestTrackAxis = track.getNearestTrackAxis(level, pos2, state2, lookVec);
Vec3 axis2 = nearestTrackAxis.getFirst()
.scale(nearestTrackAxis.getSecond() == AxisDirection.POSITIVE ? -1 : 1);
Vec3 normal2 = track.getUpNormal(level, pos2, state2)
.normalize();
Vec3 normedAxis2 = axis2.normalize();
Vec3 end2 = track.getCurveStart(level, pos2, state2, axis2);
CompoundTag itemTag = stack.getTag();
CompoundTag selectionTag = itemTag.getCompound("ConnectingFrom");
BlockPos pos1 = NbtUtils.readBlockPos(selectionTag.getCompound("Pos"));
Vec3 axis1 = VecHelper.readNBT(selectionTag.getList("Axis", Tag.TAG_DOUBLE));
Vec3 normedAxis1 = axis1.normalize();
Vec3 end1 = VecHelper.readNBT(selectionTag.getList("End", Tag.TAG_DOUBLE));
Vec3 normal1 = VecHelper.readNBT(selectionTag.getList("Normal", Tag.TAG_DOUBLE));
boolean front1 = selectionTag.getBoolean("Front");
BlockState state1 = level.getBlockState(pos1);
if (level.isClientSide) {
info.end1 = end1;
info.end2 = end2;
info.normal1 = normal1;
info.normal2 = normal2;
info.axis1 = axis1;
info.axis2 = axis2;
}
if (pos1.equals(pos2))
return info.withMessage("second_point");
if (pos1.distSqr(pos2) > maxLength * maxLength)
return info.withMessage("too_far")
.tooJumbly();
if (!state1.hasProperty(TrackBlock.HAS_TE))
return info.withMessage("original_missing");
if (axis1.dot(end2.subtract(end1)) < 0) {
axis1 = axis1.scale(-1);
normedAxis1 = normedAxis1.scale(-1);
front1 = !front1;
end1 = track.getCurveStart(level, pos1, state1, axis1);
if (level.isClientSide) {
info.end1 = end1;
info.axis1 = axis1;
}
}
double[] intersect = VecHelper.intersect(end1, end2, normedAxis1, normedAxis2, Axis.Y);
boolean parallel = intersect == null;
boolean skipCurve = false;
if ((parallel && normedAxis1.dot(normedAxis2) > 0) || (!parallel && (intersect[0] < 0 || intersect[1] < 0))) {
axis2 = axis2.scale(-1);
normedAxis2 = normedAxis2.scale(-1);
end2 = track.getCurveStart(level, pos2, state2, axis2);
if (level.isClientSide) {
info.end2 = end2;
info.axis2 = axis2;
}
}
Vec3 cross2 = normedAxis2.cross(new Vec3(0, 1, 0));
double a1 = Mth.atan2(normedAxis2.z, normedAxis2.x);
double a2 = Mth.atan2(normedAxis1.z, normedAxis1.x);
double angle = a1 - a2;
double ascend = end2.subtract(end1).y;
double absAscend = Math.abs(ascend);
boolean slope = !normal1.equals(normal2);
if (level.isClientSide) {
Vec3 offset1 = axis1.scale(info.end1Extent);
Vec3 offset2 = axis2.scale(info.end2Extent);
BlockPos targetPos1 = pos1.offset(offset1.x, offset1.y, offset1.z);
BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z);
info.curve = new BezierConnection(Couple.create(targetPos1, targetPos2),
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
}
// S curve or Straight
double dist = 0;
if (parallel) {
double[] sTest = VecHelper.intersect(end1, end2, normedAxis1, cross2, Axis.Y);
if (sTest != null) {
double t = Math.abs(sTest[0]);
double u = Math.abs(sTest[1]);
skipCurve = Mth.equal(u, 0);
if (!skipCurve && sTest[0] < 0)
return info.withMessage("perpendicular")
.tooJumbly();
if (skipCurve) {
dist = VecHelper.getCenterOf(pos1)
.distanceTo(VecHelper.getCenterOf(pos2));
info.end1Extent = (int) Math.round((dist + 1) / axis1.length());
} else {
if (!Mth.equal(ascend, 0))
return info.withMessage("ascending_s_curve");
double targetT = u <= 1 ? 3 : u * 2;
if (t < targetT)
return info.withMessage("too_sharp");
// This is for standardising s curve sizes
if (t > targetT) {
int correction = (int) ((t - targetT) / axis1.length());
info.end1Extent = maximiseTurn ? 0 : correction / 2 + (correction % 2);
info.end2Extent = maximiseTurn ? 0 : correction / 2;
}
}
}
}
// Slope
if (slope) {
if (!skipCurve)
return info.withMessage("slope_turn");
if (Mth.equal(normal1.dot(normal2), 0))
return info.withMessage("opposing_slopes");
if ((axis1.y < 0 || axis2.y > 0) && ascend > 0)
return info.withMessage("leave_slope_ascending");
if ((axis1.y > 0 || axis2.y < 0) && ascend < 0)
return info.withMessage("leave_slope_descending");
skipCurve = false;
info.end1Extent = 0;
info.end2Extent = 0;
Axis plane = Mth.equal(axis1.x, 0) ? Axis.X : Axis.Z;
intersect = VecHelper.intersect(end1, end2, normedAxis1, normedAxis2, plane);
double dist1 = Math.abs(intersect[0] / axis1.length());
double dist2 = Math.abs(intersect[1] / axis2.length());
if (dist1 > dist2)
info.end1Extent = (int) Math.round(dist1 - dist2);
if (dist2 > dist1)
info.end2Extent = (int) Math.round(dist2 - dist1);
double turnSize = Math.min(dist1, dist2);
if (intersect[0] < 0 || intersect[1] < 0)
return info.withMessage("too_sharp")
.tooJumbly();
if (turnSize < 2)
return info.withMessage("too_sharp");
// This is for standardising curve sizes
if (turnSize > 2 && !maximiseTurn) {
info.end1Extent += turnSize - 2;
info.end2Extent += turnSize - 2;
turnSize = 2;
}
}
// Straight ascend
if (skipCurve && !Mth.equal(ascend, 0)) {
int hDistance = info.end1Extent;
if (axis1.y == 0 || !Mth.equal(absAscend + 1, dist / axis1.length())) {
if (axis1.y != 0 && axis1.y == -axis2.y)
return info.withMessage("ascending_s_curve");
info.end1Extent = 0;
double minHDistance = Math.max(absAscend < 4 ? absAscend * 4 : absAscend * 3, 6) / axis1.length();
if (hDistance < minHDistance)
return info.withMessage("too_steep");
if (hDistance > minHDistance) {
int correction = (int) (hDistance - minHDistance);
info.end1Extent = maximiseTurn ? 0 : correction / 2 + (correction % 2);
info.end2Extent = maximiseTurn ? 0 : correction / 2;
}
skipCurve = false;
}
}
// Turn
if (!parallel) {
float absAngle = Math.abs(AngleHelper.deg(angle));
if (absAngle < 60 || absAngle > 300)
return info.withMessage("turn_90")
.tooJumbly();
intersect = VecHelper.intersect(end1, end2, normedAxis1, normedAxis2, Axis.Y);
double dist1 = Math.abs(intersect[0]);
double dist2 = Math.abs(intersect[1]);
float ex1 = 0;
float ex2 = 0;
if (dist1 > dist2)
ex1 = (float) ((dist1 - dist2) / axis1.length());
if (dist2 > dist1)
ex2 = (float) ((dist2 - dist1) / axis2.length());
double turnSize = Math.min(dist1, dist2) - .1d;
boolean ninety = (absAngle + .25f) % 90 < 1;
if (intersect[0] < 0 || intersect[1] < 0)
return info.withMessage("too_sharp")
.tooJumbly();
double minTurnSize = ninety ? 7 : 3.25;
double turnSizeToFitAscend =
minTurnSize + (ninety ? Math.max(0, absAscend - 3) * 2f : Math.max(0, absAscend - 1.5f) * 1.5f);
if (turnSize < minTurnSize)
return info.withMessage("too_sharp");
if (turnSize < turnSizeToFitAscend)
return info.withMessage("too_steep");
// This is for standardising curve sizes
if (!maximiseTurn) {
ex1 += (turnSize - turnSizeToFitAscend) / axis1.length();
ex2 += (turnSize - turnSizeToFitAscend) / axis2.length();
}
info.end1Extent = Mth.floor(ex1);
info.end2Extent = Mth.floor(ex2);
turnSize = turnSizeToFitAscend;
}
Vec3 offset1 = axis1.scale(info.end1Extent);
Vec3 offset2 = axis2.scale(info.end2Extent);
BlockPos targetPos1 = pos1.offset(offset1.x, offset1.y, offset1.z);
BlockPos targetPos2 = pos2.offset(offset2.x, offset2.y, offset2.z);
info.curve = skipCurve ? null
: new BezierConnection(Couple.create(targetPos1, targetPos2),
Couple.create(end1.add(offset1), end2.add(offset2)), Couple.create(normedAxis1, normedAxis2),
Couple.create(normal1, normal2), true, girder, TrackMaterial.fromItem(stack.getItem()));
info.valid = true;
info.pos1 = pos1;
info.pos2 = pos2;
info.axis1 = axis1;
info.axis2 = axis2;
placeTracks(level, info, state1, state2, targetPos1, targetPos2, true);
ItemStack offhandItem = player.getOffhandItem()
.copy();
boolean shouldPave = offhandItem.getItem() instanceof BlockItem;
if (shouldPave) {
BlockItem paveItem = (BlockItem) offhandItem.getItem();
paveTracks(level, info, paveItem, true);
info.hasRequiredPavement = true;
}
info.hasRequiredTracks = true;
if (!player.isCreative()) {
for (boolean simulate : Iterate.trueAndFalse) {
if (level.isClientSide && !simulate)
break;
int tracks = info.requiredTracks;
int pavement = info.requiredPavement;
int foundTracks = 0;
int foundPavement = 0;
Inventory inv = player.getInventory();
int size = inv.items.size();
for (int j = 0; j <= size + 1; j++) {
int i = j;
boolean offhand = j == size + 1;
if (j == size)
i = inv.selected;
else if (offhand)
i = 0;
else if (j == inv.selected)
continue;
ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i);
boolean isTrack = AllTags.AllBlockTags.TRACKS.matches(stackInSlot) && stackInSlot.is(stack.getItem());
if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem()))
continue;
if (isTrack ? foundTracks >= tracks : foundPavement >= pavement)
continue;
int count = stackInSlot.getCount();
if (!simulate) {
int remainingItems =
count - Math.min(isTrack ? tracks - foundTracks : pavement - foundPavement, count);
if (i == inv.selected)
stackInSlot.setTag(null);
ItemStack newItem = ItemHandlerHelper.copyStackWithSize(stackInSlot, remainingItems);
if (offhand)
player.setItemInHand(InteractionHand.OFF_HAND, newItem);
else
inv.setItem(i, newItem);
}
if (isTrack)
foundTracks += count;
else
foundPavement += count;
}
if (simulate && foundTracks < tracks) {
info.valid = false;
info.tooJumbly();
info.hasRequiredTracks = false;
return info.withMessage("not_enough_tracks");
}
if (simulate && foundPavement < pavement) {
info.valid = false;
info.tooJumbly();
info.hasRequiredPavement = false;
return info.withMessage("not_enough_pavement");
}
}
}
if (level.isClientSide())
return info;
if (shouldPave) {
BlockItem paveItem = (BlockItem) offhandItem.getItem();
paveTracks(level, info, paveItem, false);
}
if (info.curve != null && info.curve.getLength() > 29)
AllAdvancements.LONG_BEND.awardTo(player);
return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false);
}
private static void paveTracks(Level level, PlacementInfo info, BlockItem blockItem, boolean simulate) {
Block block = blockItem.getBlock();
info.requiredPavement = 0;
if (block == null || block instanceof EntityBlock || block.defaultBlockState()
.getCollisionShape(level, info.pos1)
.isEmpty())
return;
Set<BlockPos> visited = new HashSet<>();
for (boolean first : Iterate.trueAndFalse) {
int extent = (first ? info.end1Extent : info.end2Extent) + (info.curve != null ? 1 : 0);
Vec3 axis = first ? info.axis1 : info.axis2;
BlockPos pavePos = first ? info.pos1 : info.pos2;
info.requiredPavement +=
TrackPaver.paveStraight(level, pavePos.below(), axis, extent, block, simulate, visited);
}
if (info.curve != null)
info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited);
}
private static BlockState copyProperties(BlockState from, BlockState onto) {
for (Property property : onto.getProperties()) {
if (from.hasProperty(property))
onto = onto.setValue(property, from.getValue(property));
}
return onto;
}
private static BlockState copyProperties(BlockState from, BlockState onto, boolean keepFrom) {
return keepFrom ? from : copyProperties(from, onto);
}
private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2,
BlockPos targetPos1, BlockPos targetPos2, boolean simulate) {
info.requiredTracks = 0;
for (boolean first : Iterate.trueAndFalse) {
int extent = first ? info.end1Extent : info.end2Extent;
Vec3 axis = first ? info.axis1 : info.axis2;
BlockPos pos = first ? info.pos1 : info.pos2;
BlockState state = first ? state1 : state2;
if (state.hasProperty(TrackBlock.HAS_TE) && !simulate)
state = state.setValue(TrackBlock.HAS_TE, false);
switch (state.getValue(TrackBlock.SHAPE)) {
case TE, TW:
state = state.setValue(TrackBlock.SHAPE, TrackShape.XO);
break;
case TN, TS:
state = state.setValue(TrackBlock.SHAPE, TrackShape.ZO);
break;
default:
break;
}
for (int i = 0; i < (info.curve != null ? extent + 1 : extent); i++) {
Vec3 offset = axis.scale(i);
BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z);
BlockState stateAtPos = level.getBlockState(offsetPos);
// copy over all shared properties from the shaped state to the correct track material block
BlockState toPlace = copyProperties(state, info.trackMaterial.getTrackBlock().get().defaultBlockState());
boolean canPlace = stateAtPos.getMaterial()
.isReplaceable();
if (canPlace)
info.requiredTracks++;
if (simulate)
continue;
if (stateAtPos.getBlock() instanceof ITrackBlock trackAtPos) {
toPlace = trackAtPos.overlay(level, offsetPos, stateAtPos, toPlace);
canPlace = true;
}
if (canPlace)
level.setBlock(offsetPos, ProperWaterloggedBlock.withWater(level, toPlace, offsetPos), 3);
}
}
if (info.curve == null)
return info;
if (!simulate) {
BlockState onto = info.trackMaterial.getTrackBlock().get().defaultBlockState();
BlockState stateAtPos = level.getBlockState(targetPos1);
level.setBlock(targetPos1, ProperWaterloggedBlock.withWater(level,
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state1, onto))
.setValue(TrackBlock.HAS_TE, true), targetPos1), 3);
stateAtPos = level.getBlockState(targetPos2);
level.setBlock(targetPos2, ProperWaterloggedBlock.withWater(level,
(AllTags.AllBlockTags.TRACKS.matches(stateAtPos) ? stateAtPos : copyProperties(state2, onto))
.setValue(TrackBlock.HAS_TE, true), targetPos2), 3);
}
BlockEntity te1 = level.getBlockEntity(targetPos1);
BlockEntity te2 = level.getBlockEntity(targetPos2);
int requiredTracksForTurn = (info.curve.getSegmentCount() + 1) / 2;
if (!(te1 instanceof TrackTileEntity) || !(te2 instanceof TrackTileEntity)) {
info.requiredTracks += requiredTracksForTurn;
return info;
}
TrackTileEntity tte1 = (TrackTileEntity) te1;
TrackTileEntity tte2 = (TrackTileEntity) te2;
if (!tte1.getConnections()
.containsKey(tte2.getBlockPos()))
info.requiredTracks += requiredTracksForTurn;
if (simulate)
return info;
tte1.addConnection(info.curve);
tte2.addConnection(info.curve.secondary());
return info;
}
static LerpedFloat animation = LerpedFloat.linear()
.startWithValue(0);
static int lastLineCount = 0;
static BlockPos hintPos;
static int hintAngle;
static Couple<List<BlockPos>> hints;
@OnlyIn(Dist.CLIENT)
public static void clientTick() {
LocalPlayer player = Minecraft.getInstance().player;
ItemStack stack = player.getMainHandItem();
HitResult hitResult = Minecraft.getInstance().hitResult;
if (hitResult == null)
return;
if (hitResult.getType() != Type.BLOCK)
return;
InteractionHand hand = InteractionHand.MAIN_HAND;
if (!AllTags.AllBlockTags.TRACKS.matches(stack)) {
stack = player.getOffhandItem();
hand = InteractionHand.OFF_HAND;
if (!AllTags.AllBlockTags.TRACKS.matches(stack))
return;
}
if (!stack.hasFoil())
return;
TrackBlockItem blockItem = (TrackBlockItem) stack.getItem();
Level level = player.level;
BlockHitResult bhr = (BlockHitResult) hitResult;
BlockPos pos = bhr.getBlockPos();
BlockState hitState = level.getBlockState(pos);
if (!(hitState.getBlock() instanceof TrackBlock) && !hitState.getMaterial()
.isReplaceable()) {
pos = pos.relative(bhr.getDirection());
hitState = blockItem.getPlacementState(new UseOnContext(player, hand, bhr));
if (hitState == null)
return;
}
if (!(hitState.getBlock() instanceof TrackBlock))
return;
boolean maxTurns = Minecraft.getInstance().options.keySprint.isDown();
PlacementInfo info = tryConnect(level, player, pos, hitState, stack, false, maxTurns);
if (!player.isCreative() && (info.valid || !info.hasRequiredTracks || !info.hasRequiredPavement))
BlueprintOverlayRenderer.displayTrackRequirements(info, player.getOffhandItem());
if (info.valid)
player.displayClientMessage(Lang.translateDirect("track.valid_connection")
.withStyle(ChatFormatting.GREEN), true);
else if (info.message != null)
player.displayClientMessage(Lang.translateDirect(info.message)
.withStyle(info.message.equals("track.second_point") ? ChatFormatting.WHITE : ChatFormatting.RED),
true);
if (bhr.getDirection() == Direction.UP) {
Vec3 lookVec = player.getLookAngle();
int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8;
if (!pos.equals(hintPos) || lookAngle != hintAngle) {
hints = Couple.create(ArrayList::new);
hintAngle = lookAngle;
hintPos = pos;
for (int xOffset = -2; xOffset <= 2; xOffset++) {
for (int zOffset = -2; zOffset <= 2; zOffset++) {
BlockPos offset = pos.offset(xOffset, 0, zOffset);
PlacementInfo adjInfo = tryConnect(level, player, offset, hitState, stack, false, maxTurns);
hints.get(adjInfo.valid)
.add(offset.below());
}
}
}
if (hints != null && !hints.either(Collection::isEmpty)) {
CreateClient.OUTLINER.showCluster("track_valid", hints.getFirst())
.withFaceTexture(AllSpecialTextures.THIN_CHECKERED)
.colored(0x95CD41)
.lineWidth(0);
CreateClient.OUTLINER.showCluster("track_invalid", hints.getSecond())
.withFaceTexture(AllSpecialTextures.THIN_CHECKERED)
.colored(0xEA5C2B)
.lineWidth(0);
}
}
animation.chase(info.valid ? 1 : 0, 0.25, Chaser.EXP);
animation.tickChaser();
if (!info.valid) {
info.end1Extent = 0;
info.end2Extent = 0;
}
int color = Color.mixColors(0xEA5C2B, 0x95CD41, animation.getValue());
Vec3 up = new Vec3(0, 4 / 16f, 0);
{
Vec3 v1 = info.end1;
Vec3 a1 = info.axis1.normalize();
Vec3 n1 = info.normal1.cross(a1)
.scale(15 / 16f);
Vec3 o1 = a1.scale(0.125f);
Vec3 ex1 =
a1.scale((info.end1Extent - (info.curve == null && info.end1Extent > 0 ? 2 : 0)) * info.axis1.length());
line(1, v1.add(n1)
.add(up), o1, ex1);
line(2, v1.subtract(n1)
.add(up), o1, ex1);
Vec3 v2 = info.end2;
Vec3 a2 = info.axis2.normalize();
Vec3 n2 = info.normal2.cross(a2)
.scale(15 / 16f);
Vec3 o2 = a2.scale(0.125f);
Vec3 ex2 = a2.scale(info.end2Extent * info.axis2.length());
line(3, v2.add(n2)
.add(up), o2, ex2);
line(4, v2.subtract(n2)
.add(up), o2, ex2);
}
BezierConnection bc = info.curve;
if (bc == null)
return;
Vec3 previous1 = null;
Vec3 previous2 = null;
int railcolor = color;
int segCount = bc.getSegmentCount();
float s = animation.getValue() * 7 / 8f + 1 / 8f;
float lw = animation.getValue() * 1 / 16f + 1 / 16f;
Vec3 end1 = bc.starts.getFirst();
Vec3 end2 = bc.starts.getSecond();
Vec3 finish1 = end1.add(bc.axes.getFirst()
.scale(bc.getHandleLength()));
Vec3 finish2 = end2.add(bc.axes.getSecond()
.scale(bc.getHandleLength()));
String key = "curve";
for (int i = 0; i <= segCount; i++) {
float t = i / (float) segCount;
Vec3 result = VecHelper.bezier(end1, end2, finish1, finish2, t);
Vec3 derivative = VecHelper.bezierDerivative(end1, end2, finish1, finish2, t)
.normalize();
Vec3 normal = bc.getNormal(t)
.cross(derivative)
.scale(15 / 16f);
Vec3 rail1 = result.add(normal)
.add(up);
Vec3 rail2 = result.subtract(normal)
.add(up);
if (previous1 != null) {
Vec3 middle1 = rail1.add(previous1)
.scale(0.5f);
Vec3 middle2 = rail2.add(previous2)
.scale(0.5f);
CreateClient.OUTLINER
.showLine(Pair.of(key, i * 2), VecHelper.lerp(s, middle1, previous1),
VecHelper.lerp(s, middle1, rail1))
.colored(railcolor)
.disableLineNormals()
.lineWidth(lw);
CreateClient.OUTLINER
.showLine(Pair.of(key, i * 2 + 1), VecHelper.lerp(s, middle2, previous2),
VecHelper.lerp(s, middle2, rail2))
.colored(railcolor)
.disableLineNormals()
.lineWidth(lw);
}
previous1 = rail1;
previous2 = rail2;
}
for (int i = segCount + 1; i <= lastLineCount; i++) {
CreateClient.OUTLINER.remove(Pair.of(key, i * 2));
CreateClient.OUTLINER.remove(Pair.of(key, i * 2 + 1));
}
lastLineCount = segCount;
}
@OnlyIn(Dist.CLIENT)
private static void line(int id, Vec3 v1, Vec3 o1, Vec3 ex) {
int color = Color.mixColors(0xEA5C2B, 0x95CD41, animation.getValue());
CreateClient.OUTLINER.showLine(Pair.of("start", id), v1.subtract(o1), v1.add(ex))
.lineWidth(1 / 8f)
.disableLineNormals()
.colored(color);
}
}