mirror of
https://github.com/Creators-of-Create/Create.git
synced 2024-12-27 23:47:38 +01:00
Back & Forth
- Reverse steering is no longer inverted - Fixed previous passengers not being removed from seat when player uses it - Trains with two mounted controls/conductors can now pathfind backwards out of a station - Fixed auto-approach not working properly while reversing or controlling a dual powered train the opposite direction - Fixed icon display order and disassembly location of reversed trains in a station - Fixed inaccurate train length() - Blaze burners can now drive a train - Non player train drivers are now required to sit in front of a controls block - Schedule now interrupts when no conductors are found - Fixed reversing trains not iterating carriages in the correct direction
This commit is contained in:
parent
962975a09d
commit
f64c355816
32 changed files with 587 additions and 169 deletions
|
@ -536,21 +536,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
|
|||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||
9ffe5b3f8a39fa3c3a97a3c534bd82402177e82e assets/create/lang/en_ud.json
|
||||
9dc50a1957cac1967adba6a02f2708f5a82915b6 assets/create/lang/en_us.json
|
||||
60e216704dc824ae189af3927ae06e4c70e53478 assets/create/lang/unfinished/de_de.json
|
||||
c2faed3f8cdc2616dc03d6c9cf6dafd9084c3e14 assets/create/lang/unfinished/es_cl.json
|
||||
f9632799fdf6278d0b0c0a2bff40df099745b076 assets/create/lang/unfinished/es_es.json
|
||||
1d7af6b083679766bb542cf61fc6a835983a055c assets/create/lang/unfinished/fr_fr.json
|
||||
4942f180ef3758a1449108331943e0fa75e1a29b assets/create/lang/unfinished/it_it.json
|
||||
3249596dacdf06bc727676a5cc8acf85742054d0 assets/create/lang/unfinished/ja_jp.json
|
||||
ef7601ee26fdaf0356fe5400bc4f230ccb87eea8 assets/create/lang/unfinished/ko_kr.json
|
||||
6d3914298d06db106d91299729f39cf5406f6768 assets/create/lang/unfinished/nl_nl.json
|
||||
e21bd53612d2e82e9214b94fd6d2d110377089c1 assets/create/lang/unfinished/pl_pl.json
|
||||
56b4b8f892bf4442ac2f5140dc97273d1dfe2f27 assets/create/lang/unfinished/pt_br.json
|
||||
63690bcfce50698d81562fe6cff1d0701a13e23d assets/create/lang/unfinished/pt_pt.json
|
||||
dfa8dc43216673feac87a2a49d08fd8cc9b1d9f2 assets/create/lang/unfinished/ru_ru.json
|
||||
dd18a29b4a76752ea033569ebbb07014e9aa3ab0 assets/create/lang/unfinished/zh_cn.json
|
||||
0b67d5808e2665b5c0414a103b730508e17e01f6 assets/create/lang/unfinished/zh_tw.json
|
||||
8a5aec9b50def31d67404d0bfe4b44e36f4b92fe assets/create/lang/en_us.json
|
||||
d9daa020e298d6ab1420c31347e34d1c44b1754b assets/create/lang/unfinished/de_de.json
|
||||
fb68c11749892f4548065b5a2c9c06d8ea191675 assets/create/lang/unfinished/es_cl.json
|
||||
2c3dd3ce3babc836ca5d7cf7b6674bc82dacab75 assets/create/lang/unfinished/es_es.json
|
||||
031fa6be3a6fa11c6f14dc71c96c75e3bfa29172 assets/create/lang/unfinished/fr_fr.json
|
||||
e683bf4fb4acfb4ba4a545427c9d793905272572 assets/create/lang/unfinished/it_it.json
|
||||
641d5b5066086679364cbf882722ca75b7a1578c assets/create/lang/unfinished/ja_jp.json
|
||||
8260c7075f6e9fdb8a97618636854555a0dc2b72 assets/create/lang/unfinished/ko_kr.json
|
||||
fb7df57cc05f3cf95715b4c1dcf7274beb332c4f assets/create/lang/unfinished/nl_nl.json
|
||||
697fb5eb49f7316c9932fab43346717695c5e0c5 assets/create/lang/unfinished/pl_pl.json
|
||||
e007d6c626a1fca61382838f413d0e40ca702017 assets/create/lang/unfinished/pt_br.json
|
||||
c4b8a2bd6331dd0c703bc70204f9dce24be08cc2 assets/create/lang/unfinished/pt_pt.json
|
||||
b8acd477bf9bef586fe10e58a4120064581ecabc assets/create/lang/unfinished/ru_ru.json
|
||||
44e398366683e2d92ebdbbcdf7b6510b7ee62889 assets/create/lang/unfinished/zh_cn.json
|
||||
0d0016f17bea0cece7b89de092db5517ddfb899e assets/create/lang/unfinished/zh_tw.json
|
||||
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
|
||||
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
|
||||
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
|
||||
|
|
|
@ -1376,6 +1376,8 @@
|
|||
"create.schedule.loop1": "Schedule starts over",
|
||||
"create.schedule.loop2": "when completed",
|
||||
"create.schedule.train_still_assembling": "Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "Selection Cleared",
|
||||
"create.track.valid_connection": "Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1427",
|
||||
"_": "Missing Localizations: 1429",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 438",
|
||||
"_": "Missing Localizations: 440",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 438",
|
||||
"_": "Missing Localizations: 440",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1689",
|
||||
"_": "Missing Localizations: 1691",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1378",
|
||||
"_": "Missing Localizations: 1380",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 108",
|
||||
"_": "Missing Localizations: 110",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 110",
|
||||
"_": "Missing Localizations: 112",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 2042",
|
||||
"_": "Missing Localizations: 2044",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 477",
|
||||
"_": "Missing Localizations: 479",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1661",
|
||||
"_": "Missing Localizations: 1663",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 1661",
|
||||
"_": "Missing Localizations: 1663",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 482",
|
||||
"_": "Missing Localizations: 484",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 108",
|
||||
"_": "Missing Localizations: 110",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"_": "Missing Localizations: 496",
|
||||
"_": "Missing Localizations: 498",
|
||||
|
||||
"_": "->------------------------] Game Elements [------------------------<-",
|
||||
|
||||
|
@ -1377,6 +1377,8 @@
|
|||
"create.schedule.loop1": "UNLOCALIZED: Schedule starts over",
|
||||
"create.schedule.loop2": "UNLOCALIZED: when completed",
|
||||
"create.schedule.train_still_assembling": "UNLOCALIZED: Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "UNLOCALIZED: Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "UNLOCALIZED: Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "UNLOCALIZED: Selection Cleared",
|
||||
"create.track.valid_connection": "UNLOCALIZED: Can Connect ✔",
|
||||
|
|
|
@ -98,6 +98,7 @@ import com.simibubi.create.content.contraptions.processing.BasinGenerator;
|
|||
import com.simibubi.create.content.contraptions.processing.BasinMovementBehaviour;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerInteractionBehaviour;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.LitBlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.GantryShaftBlock;
|
||||
import com.simibubi.create.content.contraptions.relays.advanced.SpeedControllerBlock;
|
||||
|
@ -568,6 +569,7 @@ public class AllBlocks {
|
|||
.tag(AllBlockTags.FAN_TRANSPARENT.tag, AllBlockTags.FAN_HEATERS.tag)
|
||||
.loot((lt, block) -> lt.add(block, BlazeBurnerBlock.buildLootTable()))
|
||||
.blockstate((c, p) -> p.simpleBlock(c.getEntry(), AssetLookup.partialBaseModel(c, p)))
|
||||
.onRegister(addInteractionBehaviour(new BlazeBurnerInteractionBehaviour()))
|
||||
.item(BlazeBurnerBlockItem::withBlaze)
|
||||
.model(AssetLookup.<BlazeBurnerBlockItem>customBlockItemModel("blaze_burner", "block_with_blaze"))
|
||||
.build()
|
||||
|
|
|
@ -99,6 +99,15 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
}
|
||||
|
||||
public void addSittingPassenger(Entity passenger, int seatIndex) {
|
||||
for (Entity entity : getPassengers()) {
|
||||
BlockPos seatOf = contraption.getSeatOf(entity.getUUID());
|
||||
if (seatOf != null && seatOf.equals(contraption.getSeats()
|
||||
.get(seatIndex))) {
|
||||
if (entity instanceof Player)
|
||||
return;
|
||||
entity.stopRiding();
|
||||
}
|
||||
}
|
||||
passenger.startRiding(this, true);
|
||||
if (level.isClientSide)
|
||||
return;
|
||||
|
@ -168,7 +177,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
return getName();
|
||||
}
|
||||
|
||||
public boolean startControlling(BlockPos controlsLocalPos) {
|
||||
public boolean startControlling(BlockPos controlsLocalPos, Player player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -470,7 +479,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
|
||||
contraption.addBlocksToWorld(level, transform);
|
||||
contraption.addPassengersToWorld(level, transform, getPassengers());
|
||||
|
||||
|
||||
for (Entity entity : getPassengers()) {
|
||||
if (!(entity instanceof OrientedContraptionEntity))
|
||||
continue;
|
||||
|
@ -482,7 +491,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
|
|||
entity.setPos(transformed.getX(), transformed.getY(), transformed.getZ());
|
||||
((AbstractContraptionEntity) entity).disassemble();
|
||||
}
|
||||
|
||||
|
||||
discard();
|
||||
|
||||
ejectPassengers();
|
||||
|
|
|
@ -17,6 +17,7 @@ import net.minecraft.client.KeyMapping;
|
|||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public class ControlsHandler {
|
||||
|
||||
|
@ -28,14 +29,14 @@ public class ControlsHandler {
|
|||
static WeakReference<AbstractContraptionEntity> entityRef = new WeakReference<>(null);
|
||||
static BlockPos controlsPos;
|
||||
|
||||
public static void controllerClicked(AbstractContraptionEntity entity, BlockPos controllerLocalPos) {
|
||||
public static void controllerClicked(AbstractContraptionEntity entity, BlockPos controllerLocalPos, Player player) {
|
||||
AbstractContraptionEntity prevEntity = entityRef.get();
|
||||
if (prevEntity != null) {
|
||||
stopControlling();
|
||||
if (prevEntity == entity)
|
||||
return;
|
||||
}
|
||||
if (!entity.startControlling(controllerLocalPos))
|
||||
if (!entity.startControlling(controllerLocalPos, player))
|
||||
return;
|
||||
entityRef = new WeakReference<AbstractContraptionEntity>(entity);
|
||||
controlsPos = controllerLocalPos;
|
||||
|
|
|
@ -13,7 +13,7 @@ public class ControlsInteractionBehaviour extends MovingInteractionBehaviour {
|
|||
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
|
||||
AbstractContraptionEntity contraptionEntity) {
|
||||
if (player.level.isClientSide)
|
||||
ControlsHandler.controllerClicked(contraptionEntity, localPos);
|
||||
ControlsHandler.controllerClicked(contraptionEntity, localPos, player);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
package com.simibubi.create.content.contraptions.processing.burner;
|
||||
|
||||
import com.simibubi.create.AllItems;
|
||||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageContraption;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.ScheduleItem;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
|
||||
|
||||
public class BlazeBurnerInteractionBehaviour extends MovingInteractionBehaviour {
|
||||
|
||||
@Override
|
||||
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
|
||||
AbstractContraptionEntity contraptionEntity) {
|
||||
ItemStack itemInHand = player.getItemInHand(activeHand);
|
||||
if (!AllItems.SCHEDULE.isIn(itemInHand))
|
||||
return false;
|
||||
if (!(contraptionEntity instanceof CarriageContraptionEntity carriage))
|
||||
return false;
|
||||
Contraption contraption = carriage.getContraption();
|
||||
if (!(contraption instanceof CarriageContraption carriageContraption))
|
||||
return false;
|
||||
|
||||
StructureBlockInfo info = carriageContraption.getBlocks()
|
||||
.get(localPos);
|
||||
if (info == null || !info.state.hasProperty(BlazeBurnerBlock.HEAT_LEVEL)
|
||||
|| info.state.getValue(BlazeBurnerBlock.HEAT_LEVEL) == HeatLevel.NONE)
|
||||
return false;
|
||||
|
||||
Direction assemblyDirection = carriageContraption.getAssemblyDirection();
|
||||
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis())) {
|
||||
if (carriageContraption.inControl(localPos, direction)) {
|
||||
|
||||
Schedule schedule = ScheduleItem.getSchedule(itemInHand);
|
||||
if (schedule == null)
|
||||
return false;
|
||||
Train train = carriage.getCarriage().train;
|
||||
if (train == null)
|
||||
return false;
|
||||
if (train.heldForAssembly) {
|
||||
player.displayClientMessage(Lang.translate("schedule.train_still_assembling"), true);
|
||||
AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
train.runtime.setSchedule(schedule, false);
|
||||
AllSoundEvents.CONFIRM.playOnServer(player.level, player.blockPosition(), 1, 1);
|
||||
player.displayClientMessage(Lang.translate("schedule.applied_to_train")
|
||||
.withStyle(ChatFormatting.GREEN), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
player.displayClientMessage(Lang.translate("schedule.non_controlling_seat"), true);
|
||||
AllSoundEvents.DENY.playOnServer(player.level, player.blockPosition(), 1, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@ import java.util.function.Function;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||
import org.apache.commons.lang3.mutable.MutableObject;
|
||||
|
||||
import com.simibubi.create.Create;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
|
@ -15,6 +14,7 @@ import com.simibubi.create.content.logistics.trains.TrackGraph;
|
|||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
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.VecHelper;
|
||||
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
|
||||
|
||||
|
@ -35,6 +35,9 @@ public class Carriage {
|
|||
public int id;
|
||||
public boolean blocked;
|
||||
|
||||
public boolean hasForwardConductor;
|
||||
public boolean hasBackwardConductor;
|
||||
|
||||
WeakReference<CarriageContraptionEntity> entity;
|
||||
Couple<CarriageBogey> bogeys;
|
||||
|
||||
|
@ -67,30 +70,27 @@ public class Carriage {
|
|||
double stress = onTwoBogeys ? bogeySpacing - leadingAnchor.distanceTo(trailingAnchor) : 0;
|
||||
blocked = false;
|
||||
|
||||
// positive stress: points should move apart
|
||||
// negative stress: points should move closer
|
||||
|
||||
double leadingBogeyModifier = 0.5d;
|
||||
double trailingBogeyModifier = -0.5d;
|
||||
double leadingPointModifier = 0.5d;
|
||||
double trailingPointModifier = -0.5d;
|
||||
|
||||
MutableObject<TravellingPoint> previous = new MutableObject<>();
|
||||
MutableDouble distanceMoved = new MutableDouble(distance);
|
||||
boolean iterateFromBack = distance < 0;
|
||||
|
||||
bogeys.forEachWithContext((bogey, firstBogey) -> {
|
||||
for (boolean firstBogey : Iterate.trueAndFalse) {
|
||||
if (!firstBogey && !onTwoBogeys)
|
||||
return;
|
||||
continue;
|
||||
|
||||
double bogeyCorrection = stress * (firstBogey ? leadingBogeyModifier : trailingBogeyModifier);
|
||||
boolean actuallyFirstBogey = !onTwoBogeys || (firstBogey ^ iterateFromBack);
|
||||
CarriageBogey bogey = bogeys.get(actuallyFirstBogey);
|
||||
double bogeyCorrection = stress * (actuallyFirstBogey ? 0.5d : -0.5d);
|
||||
double bogeyStress = bogey.getStress();
|
||||
|
||||
bogey.points.forEachWithContext((point, first) -> {
|
||||
TravellingPoint prevPoint = previous.getValue();
|
||||
TravellingPoint nextPoint = first ? bogey.points.getSecond()
|
||||
: firstBogey && onTwoBogeys ? bogeys.getSecond().points.getFirst() : null;
|
||||
for (boolean firstWheel : Iterate.trueAndFalse) {
|
||||
boolean actuallyFirstWheel = firstWheel ^ iterateFromBack;
|
||||
TravellingPoint point = bogey.points.get(actuallyFirstWheel);
|
||||
TravellingPoint prevPoint = !actuallyFirstWheel ? bogey.points.getFirst()
|
||||
: !actuallyFirstBogey && onTwoBogeys ? bogeys.getFirst().points.getSecond() : null;
|
||||
TravellingPoint nextPoint = actuallyFirstWheel ? bogey.points.getSecond()
|
||||
: actuallyFirstBogey && onTwoBogeys ? bogeys.getSecond().points.getFirst() : null;
|
||||
|
||||
double correction = bogeyStress * (first ? leadingPointModifier : trailingPointModifier);
|
||||
double correction = bogeyStress * (actuallyFirstWheel ? 0.5d : -0.5d);
|
||||
double toMove = distanceMoved.getValue();
|
||||
|
||||
ITrackSelector frontTrackSelector =
|
||||
|
@ -99,21 +99,29 @@ public class Carriage {
|
|||
nextPoint == null ? backwardControl.apply(point) : point.follow(nextPoint);
|
||||
|
||||
double moved = point.travel(graph, toMove, toMove > 0 ? frontTrackSelector : backTrackSelector);
|
||||
point.travel(graph, correction + bogeyCorrection,
|
||||
correction + bogeyCorrection > 0 ? frontTrackSelector : backTrackSelector);
|
||||
double stressCorrection = correction + bogeyCorrection;
|
||||
point.travel(graph, stressCorrection, stressCorrection > 0 ? frontTrackSelector : backTrackSelector);
|
||||
blocked |= point.blocked;
|
||||
|
||||
distanceMoved.setValue(moved);
|
||||
previous.setValue(point);
|
||||
});
|
||||
}
|
||||
|
||||
bogey.updateAnchorPosition();
|
||||
});
|
||||
}
|
||||
|
||||
tickEntity(level);
|
||||
return distanceMoved.getValue();
|
||||
}
|
||||
|
||||
public void updateConductors() {
|
||||
CarriageContraptionEntity entity = this.entity.get();
|
||||
if (entity == null || !entity.isAlive())
|
||||
return;
|
||||
Couple<Boolean> sides = entity.checkConductors();
|
||||
hasForwardConductor = sides.getFirst();
|
||||
hasBackwardConductor = sides.getSecond();
|
||||
}
|
||||
|
||||
public void createEntity(Level level) {
|
||||
contraption.startMoving(level);
|
||||
CarriageContraptionEntity entity = CarriageContraptionEntity.create(level, contraption);
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
package com.simibubi.create.content.logistics.trains.entity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import com.simibubi.create.AllBlocks;
|
||||
|
@ -9,13 +14,19 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con
|
|||
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.NonStationaryLighter;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
|
||||
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
|
||||
import com.simibubi.create.content.logistics.trains.IBogeyBlock;
|
||||
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 net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtUtils;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
@ -24,20 +35,29 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
|
|||
public class CarriageContraption extends Contraption {
|
||||
|
||||
private Direction assemblyDirection;
|
||||
|
||||
private boolean forwardControls;
|
||||
private boolean backwardControls;
|
||||
private boolean sidewaysControls;
|
||||
|
||||
private int bogeys;
|
||||
private BlockPos secondBogeyPos;
|
||||
public Couple<Boolean> blazeBurnerConductors;
|
||||
public Map<BlockPos, Couple<Boolean>> conductorSeats;
|
||||
|
||||
// runtime
|
||||
private Carriage carriage;
|
||||
public int temporaryCarriageIdHolder = -1;
|
||||
|
||||
public CarriageContraption() {}
|
||||
// for assembly only
|
||||
private int bogeys;
|
||||
private boolean sidewaysControls;
|
||||
private BlockPos secondBogeyPos;
|
||||
private List<BlockPos> assembledBlazeBurners;
|
||||
|
||||
public CarriageContraption() {
|
||||
conductorSeats = new HashMap<>();
|
||||
assembledBlazeBurners = new ArrayList<>();
|
||||
blazeBurnerConductors = Couple.create(false, false);
|
||||
}
|
||||
|
||||
public CarriageContraption(Direction assemblyDirection) {
|
||||
this();
|
||||
this.assemblyDirection = assemblyDirection;
|
||||
this.bogeys = 0;
|
||||
}
|
||||
|
@ -54,9 +74,30 @@ public class CarriageContraption extends Contraption {
|
|||
throw new AssemblyException(Lang.translate("train_assembly.too_many_bogeys", bogeys));
|
||||
if (sidewaysControls)
|
||||
throw new AssemblyException(Lang.translate("train_assembly.sideways_controls"));
|
||||
|
||||
for (BlockPos blazePos : assembledBlazeBurners)
|
||||
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
|
||||
if (inControl(blazePos, direction))
|
||||
blazeBurnerConductors.set(direction != assemblyDirection, true);
|
||||
for (BlockPos seatPos : getSeats())
|
||||
for (Direction direction : Iterate.directionsInAxis(assemblyDirection.getAxis()))
|
||||
if (inControl(seatPos, direction))
|
||||
conductorSeats.computeIfAbsent(seatPos, p -> Couple.create(false, false))
|
||||
.set(direction != assemblyDirection, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean inControl(BlockPos pos, Direction direction) {
|
||||
BlockPos controlsPos = pos.relative(direction);
|
||||
if (!blocks.containsKey(controlsPos))
|
||||
return false;
|
||||
StructureBlockInfo info = blocks.get(controlsPos);
|
||||
if (!AllBlocks.CONTROLS.has(info.state))
|
||||
return false;
|
||||
return info.state.getValue(ControlsBlock.FACING) == direction.getOpposite();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isAnchoringBlockAt(BlockPos pos) {
|
||||
return false;
|
||||
|
@ -73,14 +114,21 @@ public class CarriageContraption extends Contraption {
|
|||
return Pair.of(new StructureBlockInfo(pos, blockState, null), null);
|
||||
}
|
||||
|
||||
if (AllBlocks.BLAZE_BURNER.has(blockState)
|
||||
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != HeatLevel.NONE)
|
||||
assembledBlazeBurners.add(toLocalPos(pos));
|
||||
|
||||
if (AllBlocks.CONTROLS.has(blockState)) {
|
||||
Direction facing = blockState.getValue(ControlsBlock.FACING);
|
||||
if (facing.getAxis() != assemblyDirection.getAxis())
|
||||
sidewaysControls = true;
|
||||
else if (facing == assemblyDirection)
|
||||
forwardControls = true;
|
||||
else
|
||||
backwardControls = true;
|
||||
else {
|
||||
boolean forwards = facing == assemblyDirection;
|
||||
if (forwards)
|
||||
forwardControls = true;
|
||||
else
|
||||
backwardControls = true;
|
||||
}
|
||||
}
|
||||
|
||||
return super.capture(world, pos);
|
||||
|
@ -94,6 +142,17 @@ public class CarriageContraption extends Contraption {
|
|||
tag.putInt("CarriageId", carriage.id);
|
||||
tag.putBoolean("FrontControls", forwardControls);
|
||||
tag.putBoolean("BackControls", backwardControls);
|
||||
tag.putBoolean("FrontBlazeConductor", blazeBurnerConductors.getFirst());
|
||||
tag.putBoolean("BackBlazeConductor", blazeBurnerConductors.getSecond());
|
||||
NBTHelper.writeCompoundList(conductorSeats.entrySet(), e -> {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
compoundTag.put("Pos", NbtUtils.writeBlockPos(e.getKey()));
|
||||
compoundTag.putBoolean("Forward", e.getValue()
|
||||
.getFirst());
|
||||
compoundTag.putBoolean("Backward", e.getValue()
|
||||
.getSecond());
|
||||
return compoundTag;
|
||||
});
|
||||
return tag;
|
||||
}
|
||||
|
||||
|
@ -104,6 +163,12 @@ public class CarriageContraption extends Contraption {
|
|||
temporaryCarriageIdHolder = nbt.getInt("CarriageId");
|
||||
forwardControls = nbt.getBoolean("FrontControls");
|
||||
backwardControls = nbt.getBoolean("BackControls");
|
||||
blazeBurnerConductors =
|
||||
Couple.create(nbt.getBoolean("FrontBlazeConductor"), nbt.getBoolean("BackBlazeConductor"));
|
||||
conductorSeats.clear();
|
||||
NBTHelper.iterateCompoundList(nbt.getList("ConductorSeats", Tag.TAG_COMPOUND),
|
||||
c -> conductorSeats.put(NbtUtils.readBlockPos(c.getCompound("Pos")),
|
||||
Couple.create(nbt.getBoolean("Forward"), nbt.getBoolean("Backward"))));
|
||||
super.readNBT(world, nbt, spawnData);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.int
|
|||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
||||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.foundation.utility.Color;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
import com.simibubi.create.foundation.utility.VecHelper;
|
||||
|
||||
|
@ -24,6 +25,7 @@ import net.minecraft.core.particles.ParticleTypes;
|
|||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -62,13 +64,39 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
return contraptionName;
|
||||
}
|
||||
|
||||
public Couple<Boolean> checkConductors() {
|
||||
Couple<Boolean> sides = Couple.create(false, false);
|
||||
|
||||
if (!(contraption instanceof CarriageContraption cc))
|
||||
return sides;
|
||||
sides.setFirst(cc.blazeBurnerConductors.getFirst());
|
||||
sides.setSecond(cc.blazeBurnerConductors.getSecond());
|
||||
|
||||
for (Entity entity : getPassengers()) {
|
||||
BlockPos seatOf = cc.getSeatOf(entity.getUUID());
|
||||
if (seatOf == null)
|
||||
continue;
|
||||
Couple<Boolean> validSides = cc.conductorSeats.get(seatOf);
|
||||
if (validSides == null)
|
||||
continue;
|
||||
sides.setFirst(sides.getFirst() || validSides.getFirst());
|
||||
sides.setSecond(sides.getSecond() || validSides.getSecond());
|
||||
}
|
||||
|
||||
return sides;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean startControlling(BlockPos controlsLocalPos) {
|
||||
public boolean startControlling(BlockPos controlsLocalPos, Player player) {
|
||||
Carriage carriage = getCarriage();
|
||||
if (carriage == null)
|
||||
return false;
|
||||
if (carriage.train.derailed)
|
||||
return false;
|
||||
if (carriage.train.heldForAssembly) {
|
||||
player.displayClientMessage(Lang.translate("schedule.train_still_assembling"), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
Train train = carriage.train;
|
||||
if (train.runtime.getSchedule() != null && !train.runtime.paused)
|
||||
|
@ -110,9 +138,10 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
|
||||
if (inverted) {
|
||||
targetSpeed *= -1;
|
||||
// targetSteer *= -1;
|
||||
targetSteer *= -1;
|
||||
}
|
||||
|
||||
boolean slow = inverted ^ targetSpeed < 0;
|
||||
boolean spaceDown = heldControls.contains(4);
|
||||
GlobalStation currentStation = carriage.train.getCurrentStation();
|
||||
if (currentStation != null && spaceDown) {
|
||||
|
@ -127,7 +156,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
.append(new TextComponent(currentStation.name).withStyle(ChatFormatting.WHITE)), true);
|
||||
}
|
||||
|
||||
if (currentStation == null && targetSpeed >= 0) {
|
||||
if (currentStation == null) {
|
||||
Navigation nav = carriage.train.navigation;
|
||||
if (nav.destination != null) {
|
||||
if (!spaceDown)
|
||||
|
@ -148,7 +177,10 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
}
|
||||
}
|
||||
|
||||
GlobalStation lookAhead = nav.findNearestApproachable();
|
||||
double directedSpeed = targetSpeed != 0 ? targetSpeed : carriage.train.speed;
|
||||
GlobalStation lookAhead = nav.findNearestApproachable(
|
||||
!carriage.train.doubleEnded || (directedSpeed != 0 ? directedSpeed > 0 : !inverted));
|
||||
|
||||
if (lookAhead != null) {
|
||||
if (spaceDown) {
|
||||
nav.startNavigation(lookAhead, false);
|
||||
|
@ -166,7 +198,7 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
|
|||
carriage.train.manualSteer =
|
||||
targetSteer < 0 ? SteerDirection.RIGHT : targetSteer > 0 ? SteerDirection.LEFT : SteerDirection.NONE;
|
||||
carriage.train.targetSpeed = Train.topSpeed * targetSpeed;
|
||||
if (inverted ^ targetSpeed < 0)
|
||||
if (slow)
|
||||
carriage.train.targetSpeed /= 8;
|
||||
boolean counteringAcceleration = Math.abs(Math.signum(targetSpeed) - Math.signum(carriage.train.speed)) > 1.5f;
|
||||
carriage.train.manualTick = true;
|
||||
|
|
|
@ -19,6 +19,7 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
|||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||
import com.simibubi.create.content.logistics.trains.management.GlobalStation;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Iterate;
|
||||
import com.simibubi.create.foundation.utility.Pair;
|
||||
|
||||
import net.minecraft.world.level.Level;
|
||||
|
@ -29,6 +30,7 @@ public class Navigation {
|
|||
Train train;
|
||||
public GlobalStation destination;
|
||||
public double distanceToDestination;
|
||||
public boolean destinationBehindTrain;
|
||||
List<TrackEdge> currentPath;
|
||||
|
||||
public Navigation(Train train, TrackGraph graph) {
|
||||
|
@ -40,6 +42,27 @@ public class Navigation {
|
|||
if (destination == null)
|
||||
return;
|
||||
|
||||
if (!train.runtime.paused) {
|
||||
boolean frontDriver = train.hasForwardConductor();
|
||||
boolean backDriver = train.hasBackwardConductor();
|
||||
if (destinationBehindTrain && !backDriver) {
|
||||
if (frontDriver)
|
||||
train.status.missingBackwardsConductor();
|
||||
else
|
||||
train.status.missingConductor();
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!destinationBehindTrain && !frontDriver) {
|
||||
train.status.missingConductor();
|
||||
cancelNavigation();
|
||||
return;
|
||||
}
|
||||
|
||||
train.status.foundConductor();
|
||||
}
|
||||
|
||||
destination.reserveFor(train);
|
||||
|
||||
if (distanceToDestination < 1 / 32f) {
|
||||
|
@ -51,21 +74,24 @@ public class Navigation {
|
|||
return;
|
||||
}
|
||||
|
||||
if (distanceToDestination - train.speed < 1 / 32f) {
|
||||
train.speed = distanceToDestination;
|
||||
float speedMod = destinationBehindTrain ? -1 : 1;
|
||||
train.currentlyBackwards = destinationBehindTrain;
|
||||
|
||||
if (distanceToDestination - Math.abs(train.speed) < 1 / 32f) {
|
||||
train.speed = distanceToDestination * speedMod;
|
||||
return;
|
||||
}
|
||||
|
||||
if (distanceToDestination < 10) {
|
||||
double target = Train.topSpeed * ((distanceToDestination) / 10);
|
||||
if (target < train.speed) {
|
||||
train.speed += (target - train.speed) * .5f;
|
||||
if (target < Math.abs(train.speed)) {
|
||||
train.speed += (target - Math.abs(train.speed)) * .5f * speedMod;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
double brakingDistance = (train.speed * train.speed) / (2 * Train.acceleration);
|
||||
train.targetSpeed = distanceToDestination > brakingDistance ? Train.topSpeed : 0;
|
||||
train.targetSpeed = distanceToDestination > brakingDistance ? Train.topSpeed * speedMod : 0;
|
||||
train.approachTargetSpeed(1);
|
||||
}
|
||||
|
||||
|
@ -103,13 +129,17 @@ public class Navigation {
|
|||
|
||||
public double startNavigation(GlobalStation destination, boolean simulate) {
|
||||
Pair<Double, List<TrackEdge>> pathTo = findPathTo(destination);
|
||||
boolean noneFound = pathTo.getFirst() == null;
|
||||
double distance = noneFound ? -1 : Math.abs(pathTo.getFirst());
|
||||
|
||||
if (simulate)
|
||||
return pathTo.getFirst();
|
||||
return distance;
|
||||
|
||||
distanceToDestination = pathTo.getFirst();
|
||||
distanceToDestination = distance;
|
||||
currentPath = pathTo.getSecond();
|
||||
if (distanceToDestination == -1) {
|
||||
destinationBehindTrain = pathTo.getFirst() < 0;
|
||||
|
||||
if (noneFound) {
|
||||
distanceToDestination = 0;
|
||||
if (this.destination != null)
|
||||
cancelNavigation();
|
||||
|
@ -118,6 +148,28 @@ public class Navigation {
|
|||
|
||||
if (this.destination == destination)
|
||||
return 0;
|
||||
|
||||
if (!train.runtime.paused) {
|
||||
boolean frontDriver = train.hasForwardConductor();
|
||||
boolean backDriver = train.hasBackwardConductor();
|
||||
if (destinationBehindTrain && !backDriver) {
|
||||
if (frontDriver)
|
||||
train.status.missingBackwardsConductor();
|
||||
else
|
||||
train.status.missingConductor();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!destinationBehindTrain && !frontDriver) {
|
||||
if (backDriver)
|
||||
train.status.missingBackwardsConductor();
|
||||
else
|
||||
train.status.missingConductor();
|
||||
return -1;
|
||||
}
|
||||
|
||||
train.status.foundConductor();
|
||||
}
|
||||
|
||||
train.leaveStation();
|
||||
this.destination = destination;
|
||||
|
@ -129,49 +181,85 @@ public class Navigation {
|
|||
List<TrackEdge> path = new ArrayList<>();
|
||||
|
||||
if (graph == null)
|
||||
return Pair.of(-1d, path);
|
||||
return Pair.of(null, path);
|
||||
|
||||
Couple<TrackNodeLocation> target = destination.edgeLocation;
|
||||
TravellingPoint leadingPoint = train.carriages.get(0)
|
||||
.getLeadingPoint();
|
||||
TrackEdge initialEdge = leadingPoint.edge;
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> frontResult = new MutableObject<>(Pair.of(null, path));
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> backResult = new MutableObject<>(Pair.of(null, path));
|
||||
|
||||
MutableObject<Pair<Double, List<TrackEdge>>> result = new MutableObject<>(Pair.of(-1d, path));
|
||||
for (boolean forward : Iterate.trueAndFalse) {
|
||||
if (this.destination == destination && destinationBehindTrain == forward)
|
||||
continue;
|
||||
|
||||
search((reachedVia, poll) -> {
|
||||
double distance = poll.getFirst();
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
List<TrackEdge> currentPath = new ArrayList<>();
|
||||
TravellingPoint initialPoint = forward ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
.getTrailingPoint();
|
||||
TrackEdge initialEdge = forward ? initialPoint.edge
|
||||
: graph.getConnectionsFrom(initialPoint.node2)
|
||||
.get(initialPoint.node1);
|
||||
|
||||
TrackNodeLocation loc1 = node1.getLocation();
|
||||
TrackNodeLocation loc2 = node2.getLocation();
|
||||
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
|
||||
return false;
|
||||
search(Double.MAX_VALUE, forward, (reachedVia, poll) -> {
|
||||
|
||||
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
|
||||
TrackEdge toReach = edge;
|
||||
while (backTrack != null && toReach != initialEdge) {
|
||||
if (backTrack.getFirst())
|
||||
path.add(0, toReach);
|
||||
toReach = backTrack.getSecond();
|
||||
backTrack = reachedVia.get(backTrack.getSecond());
|
||||
}
|
||||
double distance = poll.getFirst();
|
||||
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
|
||||
TrackEdge edge = currentEntry.getSecond();
|
||||
TrackNode node1 = currentEntry.getFirst()
|
||||
.getFirst();
|
||||
TrackNode node2 = currentEntry.getFirst()
|
||||
.getSecond();
|
||||
|
||||
double distanceToDestination = distance;
|
||||
double position = edge.getLength(node1, node2) - destination.position;
|
||||
distanceToDestination -= position;
|
||||
result.setValue(Pair.of(distanceToDestination, path));
|
||||
return true;
|
||||
}, Double.MAX_VALUE);
|
||||
TrackNodeLocation loc1 = node1.getLocation();
|
||||
TrackNodeLocation loc2 = node2.getLocation();
|
||||
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
|
||||
return false;
|
||||
|
||||
return result.getValue();
|
||||
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
|
||||
TrackEdge toReach = edge;
|
||||
while (backTrack != null && toReach != initialEdge) {
|
||||
if (backTrack.getFirst())
|
||||
currentPath.add(0, toReach);
|
||||
toReach = backTrack.getSecond();
|
||||
backTrack = reachedVia.get(backTrack.getSecond());
|
||||
}
|
||||
|
||||
double position = edge.getLength(node1, node2) - destination.position;
|
||||
double distanceToDestination = distance - position;
|
||||
|
||||
if (forward)
|
||||
frontResult.setValue(Pair.of(distanceToDestination, currentPath));
|
||||
else
|
||||
backResult.setValue(Pair.of(-distanceToDestination, currentPath));
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!train.doubleEnded)
|
||||
break;
|
||||
}
|
||||
|
||||
Pair<Double, List<TrackEdge>> front = frontResult.getValue();
|
||||
Pair<Double, List<TrackEdge>> back = backResult.getValue();
|
||||
|
||||
boolean frontEmpty = front.getFirst() == null;
|
||||
boolean backEmpty = back.getFirst() == null;
|
||||
if (backEmpty)
|
||||
return front;
|
||||
if (frontEmpty)
|
||||
return back;
|
||||
|
||||
boolean canDriveForward = train.hasForwardConductor() || train.runtime.paused;
|
||||
boolean canDriveBackward = train.hasBackwardConductor() || train.runtime.paused;
|
||||
if (!canDriveBackward)
|
||||
return front;
|
||||
if (!canDriveForward)
|
||||
return back;
|
||||
|
||||
boolean frontBetter = -back.getFirst() > front.getFirst();
|
||||
return frontBetter ? front : back;
|
||||
}
|
||||
|
||||
public GlobalStation findNearestApproachable() {
|
||||
public GlobalStation findNearestApproachable(boolean forward) {
|
||||
TrackGraph graph = train.graph;
|
||||
if (graph == null)
|
||||
return null;
|
||||
|
@ -180,7 +268,7 @@ public class Navigation {
|
|||
double minDistance = .75f * (train.speed * train.speed) / (2 * Train.acceleration);
|
||||
double maxDistance = Math.max(32, 1.5f * (train.speed * train.speed) / (2 * Train.acceleration));
|
||||
|
||||
search((reachedVia, poll) -> {
|
||||
search(maxDistance, forward, (reachedVia, poll) -> {
|
||||
double distance = poll.getFirst();
|
||||
if (distance < minDistance)
|
||||
return false;
|
||||
|
@ -206,29 +294,34 @@ public class Navigation {
|
|||
}
|
||||
|
||||
return false;
|
||||
}, maxDistance);
|
||||
});
|
||||
|
||||
return result.getValue();
|
||||
}
|
||||
|
||||
public void search(
|
||||
BiPredicate<Map<TrackEdge, Pair<Boolean, TrackEdge>>, Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> condition,
|
||||
double maxDistance) {
|
||||
public void search(double maxDistance, boolean forward,
|
||||
BiPredicate<Map<TrackEdge, Pair<Boolean, TrackEdge>>, Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> condition) {
|
||||
TrackGraph graph = train.graph;
|
||||
if (graph == null)
|
||||
return;
|
||||
|
||||
TravellingPoint leadingPoint = train.carriages.get(0)
|
||||
.getLeadingPoint();
|
||||
TravellingPoint startingPoint = forward ? train.carriages.get(0)
|
||||
.getLeadingPoint()
|
||||
: train.carriages.get(train.carriages.size() - 1)
|
||||
.getTrailingPoint();
|
||||
|
||||
Set<TrackEdge> visited = new HashSet<>();
|
||||
Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia = new IdentityHashMap<>();
|
||||
PriorityQueue<Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> frontier =
|
||||
new PriorityQueue<>((p1, p2) -> Double.compare(p1.getFirst(), p2.getFirst()));
|
||||
|
||||
TrackEdge initialEdge = leadingPoint.edge;
|
||||
TrackNode initialNode1 = leadingPoint.node1;
|
||||
TrackNode initialNode2 = leadingPoint.node2;
|
||||
double distanceToNode2 = initialEdge.getLength(initialNode1, initialNode2) - leadingPoint.position;
|
||||
TrackNode initialNode1 = forward ? startingPoint.node1 : startingPoint.node2;
|
||||
TrackNode initialNode2 = forward ? startingPoint.node2 : startingPoint.node1;
|
||||
TrackEdge initialEdge = graph.getConnectionsFrom(initialNode1)
|
||||
.get(initialNode2);
|
||||
double distanceToNode2 = forward ? initialEdge.getLength(initialNode1, initialNode2) - startingPoint.position
|
||||
: startingPoint.position;
|
||||
|
||||
frontier.add(Pair.of(distanceToNode2, Pair.of(Couple.create(initialNode1, initialNode2), initialEdge)));
|
||||
|
||||
while (!frontier.isEmpty()) {
|
||||
|
|
|
@ -61,6 +61,7 @@ public class Train {
|
|||
public boolean manualTick;
|
||||
|
||||
public UUID currentStation;
|
||||
public boolean currentlyBackwards;
|
||||
|
||||
public boolean heldForAssembly;
|
||||
public boolean doubleEnded;
|
||||
|
@ -108,22 +109,13 @@ public class Train {
|
|||
return;
|
||||
}
|
||||
|
||||
updateConductors();
|
||||
runtime.tick(level);
|
||||
navigation.tick(level);
|
||||
|
||||
if (!manualTick && navigation.destination == null && speed != 0) {
|
||||
if (speed > 0)
|
||||
speed = Math.max(speed - acceleration, 0);
|
||||
else
|
||||
speed = Math.min(speed + acceleration, 0);
|
||||
}
|
||||
manualTick = false;
|
||||
|
||||
if (derailed) {
|
||||
speed /= 3f;
|
||||
if (Mth.equal(speed, 0))
|
||||
speed = 0;
|
||||
}
|
||||
tickPassiveSlowdown();
|
||||
if (derailed)
|
||||
tickDerailedSlowdown();
|
||||
|
||||
double distance = speed;
|
||||
Carriage previousCarriage = null;
|
||||
|
@ -144,18 +136,24 @@ public class Train {
|
|||
// negative stress: carriages should move closer
|
||||
|
||||
boolean approachingStation = navigation.distanceToDestination < 5;
|
||||
double leadingModifier = approachingStation ? -0.75d : -0.5d;
|
||||
double leadingModifier = approachingStation ? 0.75d : 0.5d;
|
||||
double trailingModifier = approachingStation ? 0d : 0.125d;
|
||||
|
||||
TravellingPoint previous = null;
|
||||
boolean blocked = false;
|
||||
boolean iterateFromBack = speed < 0;
|
||||
|
||||
for (int index = 0; index < carriages.size(); index++) {
|
||||
int i = iterateFromBack ? carriages.size() - 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);
|
||||
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
double leadingStress = i == 0 ? 0 : stress[i - 1] * leadingModifier;
|
||||
double trailingStress = i == stress.length ? 0 : stress[i] * trailingModifier;
|
||||
Carriage carriage = carriages.get(i);
|
||||
|
||||
TravellingPoint toFollowForward = previous;
|
||||
TravellingPoint toFollowForward = i == 0 ? null
|
||||
: carriages.get(i - 1)
|
||||
.getTrailingPoint();
|
||||
|
||||
TravellingPoint toFollowBackward = i == carriages.size() - 1 ? null
|
||||
: carriages.get(i + 1)
|
||||
.getLeadingPoint();
|
||||
|
@ -165,15 +163,15 @@ public class Train {
|
|||
Function<TravellingPoint, ITrackSelector> backwardControl =
|
||||
toFollowBackward == null ? navigation::control : mp -> mp.follow(toFollowBackward);
|
||||
|
||||
double actualDistance = carriage.travel(level, graph, distance + leadingStress + trailingStress,
|
||||
forwardControl, backwardControl);
|
||||
double totalStress = leadingStress + trailingStress;
|
||||
double actualDistance =
|
||||
carriage.travel(level, graph, distance + totalStress, forwardControl, backwardControl);
|
||||
blocked |= carriage.blocked;
|
||||
|
||||
if (i == 0) {
|
||||
if (index == 0) {
|
||||
distance = actualDistance;
|
||||
collideWithOtherTrains(level, carriage);
|
||||
}
|
||||
previous = carriage.getTrailingPoint();
|
||||
}
|
||||
|
||||
if (blocked) {
|
||||
|
@ -184,24 +182,63 @@ public class Train {
|
|||
} else if (speed != 0)
|
||||
status.trackOK();
|
||||
|
||||
updateNavigationTarget(distance);
|
||||
}
|
||||
|
||||
private void updateNavigationTarget(double distance) {
|
||||
if (navigation.destination != null) {
|
||||
boolean recalculate = navigation.distanceToDestination % 100 > 20;
|
||||
navigation.distanceToDestination -= distance;
|
||||
if (recalculate && navigation.distanceToDestination % 100 <= 20)
|
||||
boolean imminentRecalculate = navigation.distanceToDestination > 5;
|
||||
navigation.distanceToDestination -= Math.abs(distance);
|
||||
if (recalculate && navigation.distanceToDestination % 100 <= 20
|
||||
|| imminentRecalculate && navigation.distanceToDestination <= 5)
|
||||
navigation.startNavigation(navigation.destination, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void tickDerailedSlowdown() {
|
||||
speed /= 3f;
|
||||
if (Mth.equal(speed, 0))
|
||||
speed = 0;
|
||||
}
|
||||
|
||||
private void tickPassiveSlowdown() {
|
||||
if (!manualTick && navigation.destination == null && speed != 0) {
|
||||
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.hasForwardConductor)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasBackwardConductor() {
|
||||
for (Carriage carriage : carriages)
|
||||
if (carriage.hasBackwardConductor)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void collideWithOtherTrains(Level level, Carriage carriage) {
|
||||
if (derailed)
|
||||
return;
|
||||
Collision: for (Train train : Create.RAILWAYS.trains.values()) {
|
||||
if (train == this)
|
||||
continue;
|
||||
Vec3 start = carriage.getLeadingPoint()
|
||||
.getPosition();
|
||||
Vec3 end = carriage.getTrailingPoint()
|
||||
.getPosition();
|
||||
Vec3 start = (speed < 0 ? carriage.getTrailingPoint() : carriage.getLeadingPoint()).getPosition();
|
||||
Vec3 end = (speed < 0 ? carriage.getLeadingPoint() : carriage.getTrailingPoint()).getPosition();
|
||||
Vec3 diff = end.subtract(start);
|
||||
Vec3 lastPoint = null;
|
||||
|
||||
|
@ -249,7 +286,7 @@ public class Train {
|
|||
if (intersect[1] < 0)
|
||||
continue;
|
||||
|
||||
double combinedSpeed = speed + train.speed;
|
||||
double combinedSpeed = Math.abs(speed) + Math.abs(train.speed);
|
||||
if (combinedSpeed > .2f) {
|
||||
Vec3 v = start.add(normedDiff.scale(intersect[0]));
|
||||
level.explode(null, v.x, v.y, v.z, (float) Math.min(3 * combinedSpeed, 5),
|
||||
|
@ -284,21 +321,24 @@ public class Train {
|
|||
}
|
||||
|
||||
int offset = 1;
|
||||
boolean backwards = currentlyBackwards;
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
|
||||
Carriage carriage = carriages.get(i);
|
||||
Carriage carriage = carriages.get(backwards ? carriages.size() - i - 1 : i);
|
||||
CarriageContraptionEntity entity = carriage.entity.get();
|
||||
if (entity == null)
|
||||
return false;
|
||||
|
||||
entity.setPos(Vec3.atLowerCornerOf(pos.relative(assemblyDirection, offset)));
|
||||
entity.setPos(Vec3
|
||||
.atLowerCornerOf(pos.relative(assemblyDirection, backwards ? offset + carriage.bogeySpacing : offset)));
|
||||
entity.disassemble();
|
||||
Create.RAILWAYS.carriageById.remove(carriage.id);
|
||||
CreateClient.RAILWAYS.carriageById.remove(carriage.id);
|
||||
|
||||
offset += carriage.bogeySpacing;
|
||||
|
||||
if (i < carriageSpacing.size())
|
||||
offset += carriageSpacing.get(i);
|
||||
offset += carriageSpacing.get(carriageSpacing.size() - i - 1);
|
||||
}
|
||||
|
||||
GlobalStation currentStation = getCurrentStation();
|
||||
|
@ -385,7 +425,13 @@ public class Train {
|
|||
public int getTotalLength() {
|
||||
int length = 0;
|
||||
for (int i = 0; i < carriages.size(); i++) {
|
||||
length += carriages.get(i).bogeySpacing;
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ public class TrainStatus {
|
|||
|
||||
boolean navigation;
|
||||
boolean track;
|
||||
boolean conductor;
|
||||
|
||||
List<Component> queued = new ArrayList<>();
|
||||
|
||||
|
@ -37,6 +38,27 @@ public class TrainStatus {
|
|||
navigation = false;
|
||||
}
|
||||
|
||||
public void foundConductor() {
|
||||
if (!conductor)
|
||||
return;
|
||||
displayInformation("A new driver has been found", true);
|
||||
conductor = false;
|
||||
}
|
||||
|
||||
public void missingConductor() {
|
||||
if (conductor)
|
||||
return;
|
||||
displayInformation("Driver has gone missing", false);
|
||||
conductor = true;
|
||||
}
|
||||
|
||||
public void missingBackwardsConductor() { // missingCorrectConductor
|
||||
if (conductor)
|
||||
return;
|
||||
displayInformation("Path requires driver on the other controls block", false);
|
||||
conductor = true;
|
||||
}
|
||||
|
||||
public void manualControls() {
|
||||
displayInformation("Schedule paused for manual controls", true);
|
||||
}
|
||||
|
@ -90,4 +112,9 @@ public class TrainStatus {
|
|||
.append(new TextComponent(key).withStyle(st -> st.withColor(itsAGoodThing ? 0xD5ECC2 : 0xFFD3B4))));
|
||||
}
|
||||
|
||||
public void newSchedule() {
|
||||
navigation = false;
|
||||
conductor = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -107,7 +107,6 @@ public class TravellingPoint {
|
|||
public ITrackSelector steer(SteerDirection direction, Vec3 upNormal) {
|
||||
return (graph, pair) -> {
|
||||
List<Entry<TrackNode, TrackEdge>> validTargets = pair.getSecond();
|
||||
boolean forward = pair.getFirst();
|
||||
double closest = Double.MAX_VALUE;
|
||||
Entry<TrackNode, TrackEdge> best = null;
|
||||
|
||||
|
@ -116,7 +115,7 @@ public class TravellingPoint {
|
|||
Vec3 entryTrajectory = entry.getValue()
|
||||
.getDirection(node2, entry.getKey(), true);
|
||||
Vec3 normal = trajectory.cross(upNormal);
|
||||
double dot = normal.dot(entryTrajectory) * (forward ? 1 : -1);
|
||||
double dot = normal.dot(entryTrajectory);
|
||||
double diff = Math.abs(direction.targetDot - dot);
|
||||
if (diff > closest)
|
||||
continue;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
package com.simibubi.create.content.logistics.trains.management;
|
||||
|
||||
import com.simibubi.create.AllContainerTypes;
|
||||
import com.simibubi.create.AllSoundEvents;
|
||||
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageContraption;
|
||||
import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity;
|
||||
import com.simibubi.create.content.logistics.trains.entity.Train;
|
||||
import com.simibubi.create.content.logistics.trains.management.schedule.Schedule;
|
||||
import com.simibubi.create.foundation.utility.Couple;
|
||||
import com.simibubi.create.foundation.utility.Lang;
|
||||
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
|
@ -60,14 +64,9 @@ public class ScheduleItem extends Item implements MenuProvider {
|
|||
InteractionHand pUsedHand) {
|
||||
InteractionResult pass = InteractionResult.PASS;
|
||||
|
||||
if (!pStack.hasTag())
|
||||
Schedule schedule = getSchedule(pStack);
|
||||
if (schedule == null)
|
||||
return pass;
|
||||
if (!pStack.getTag()
|
||||
.contains("Schedule"))
|
||||
return pass;
|
||||
|
||||
Schedule schedule = Schedule.fromTag(pStack.getTagElement("Schedule"));
|
||||
|
||||
if (pInteractionTarget == null)
|
||||
return pass;
|
||||
Entity rootVehicle = pInteractionTarget.getRootVehicle();
|
||||
|
@ -75,21 +74,51 @@ public class ScheduleItem extends Item implements MenuProvider {
|
|||
return pass;
|
||||
if (pPlayer.level.isClientSide)
|
||||
return InteractionResult.SUCCESS;
|
||||
|
||||
CarriageContraptionEntity entity = (CarriageContraptionEntity) rootVehicle;
|
||||
Contraption contraption = entity.getContraption();
|
||||
if (contraption instanceof CarriageContraption cc) {
|
||||
|
||||
Train train = cc.getCarriage().train;
|
||||
if (train == null)
|
||||
return InteractionResult.SUCCESS;
|
||||
if (train.heldForAssembly) {
|
||||
pPlayer.displayClientMessage(Lang.translate("schedule.train_still_assembling"), true);
|
||||
AllSoundEvents.DENY.playOnServer(pPlayer.level, pPlayer.blockPosition(), 1, 1);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
Integer seatIndex = contraption.getSeatMapping()
|
||||
.get(pInteractionTarget.getUUID());
|
||||
if (seatIndex == null)
|
||||
return InteractionResult.SUCCESS;
|
||||
BlockPos seatPos = contraption.getSeats()
|
||||
.get(seatIndex);
|
||||
Couple<Boolean> directions = cc.conductorSeats.get(seatPos);
|
||||
if (directions == null) {
|
||||
pPlayer.displayClientMessage(Lang.translate("schedule.non_controlling_seat"), true);
|
||||
AllSoundEvents.DENY.playOnServer(pPlayer.level, pPlayer.blockPosition(), 1, 1);
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
train.runtime.setSchedule(schedule, false);
|
||||
AllSoundEvents.CONFIRM.playOnServer(pPlayer.level, pPlayer.blockPosition(), 1, 1);
|
||||
pPlayer.displayClientMessage(Lang.translate("schedule.applied_to_train")
|
||||
.withStyle(ChatFormatting.GREEN), true);
|
||||
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
|
||||
public static Schedule getSchedule(ItemStack pStack) {
|
||||
if (!pStack.hasTag())
|
||||
return null;
|
||||
if (!pStack.getTag()
|
||||
.contains("Schedule"))
|
||||
return null;
|
||||
return Schedule.fromTag(pStack.getTagElement("Schedule"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractContainerMenu createMenu(int id, Inventory inv, Player player) {
|
||||
ItemStack heldItem = player.getMainHandItem();
|
||||
|
|
|
@ -152,6 +152,7 @@ public class ScheduleRuntime {
|
|||
currentEntry = 0;
|
||||
paused = false;
|
||||
isAutoSchedule = auto;
|
||||
train.status.newSchedule();
|
||||
}
|
||||
|
||||
public Schedule getSchedule() {
|
||||
|
|
|
@ -218,7 +218,7 @@ public class StationScreen extends AbstractStationScreen {
|
|||
offset += icon.render(TrainIconType.FLIPPED_ENGINE, ms, x + offset, y + 20) + 1;
|
||||
continue;
|
||||
}
|
||||
Carriage carriage = carriages.get(i);
|
||||
Carriage carriage = carriages.get(train.currentlyBackwards ? carriages.size() - i - 1 : i);
|
||||
offset += icon.render(carriage.bogeySpacing, ms, x + offset, y + 20) + 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -605,6 +605,8 @@
|
|||
"create.schedule.loop1": "Schedule starts over",
|
||||
"create.schedule.loop2": "when completed",
|
||||
"create.schedule.train_still_assembling": "Confirm Train Assembly in the Station UI first",
|
||||
"create.schedule.applied_to_train": "Train is now following this Schedule",
|
||||
"create.schedule.non_controlling_seat": "Conductor needs to sit in front of a Controls block",
|
||||
|
||||
"create.track.selection_cleared": "Selection Cleared",
|
||||
"create.track.valid_connection": "Can Connect \u2714",
|
||||
|
|
Loading…
Reference in a new issue