From f64c355816addcca836bbe96ea56aa92347dc3c0 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Mon, 7 Feb 2022 01:54:20 +0100 Subject: [PATCH] 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 --- src/generated/resources/.cache/cache | 30 +-- .../resources/assets/create/lang/en_us.json | 2 + .../assets/create/lang/unfinished/de_de.json | 4 +- .../assets/create/lang/unfinished/es_cl.json | 4 +- .../assets/create/lang/unfinished/es_es.json | 4 +- .../assets/create/lang/unfinished/fr_fr.json | 4 +- .../assets/create/lang/unfinished/it_it.json | 4 +- .../assets/create/lang/unfinished/ja_jp.json | 4 +- .../assets/create/lang/unfinished/ko_kr.json | 4 +- .../assets/create/lang/unfinished/nl_nl.json | 4 +- .../assets/create/lang/unfinished/pl_pl.json | 4 +- .../assets/create/lang/unfinished/pt_br.json | 4 +- .../assets/create/lang/unfinished/pt_pt.json | 4 +- .../assets/create/lang/unfinished/ru_ru.json | 4 +- .../assets/create/lang/unfinished/zh_cn.json | 4 +- .../assets/create/lang/unfinished/zh_tw.json | 4 +- .../java/com/simibubi/create/AllBlocks.java | 2 + .../AbstractContraptionEntity.java | 15 +- .../interaction/controls/ControlsHandler.java | 5 +- .../ControlsInteractionBehaviour.java | 2 +- .../BlazeBurnerInteractionBehaviour.java | 74 +++++++ .../logistics/trains/entity/Carriage.java | 54 +++-- .../trains/entity/CarriageContraption.java | 85 +++++++- .../entity/CarriageContraptionEntity.java | 42 +++- .../logistics/trains/entity/Navigation.java | 197 +++++++++++++----- .../logistics/trains/entity/Train.java | 114 +++++++--- .../logistics/trains/entity/TrainStatus.java | 27 +++ .../trains/entity/TravellingPoint.java | 3 +- .../trains/management/ScheduleItem.java | 43 +++- .../trains/management/ScheduleRuntime.java | 1 + .../trains/management/StationScreen.java | 2 +- .../assets/create/lang/default/interface.json | 2 + 32 files changed, 587 insertions(+), 169 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 281622e95..735678755 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -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 diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 0f055c52b..c3ff63ff0 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index ddf1acf08..f31d47ff9 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_cl.json b/src/generated/resources/assets/create/lang/unfinished/es_cl.json index e21e286b1..c14c576a2 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_cl.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_cl.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json index 237497570..f7be4e2e0 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_es.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index 1ac54776d..39744abb5 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 620986964..d7fedf5e6 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index c04445efd..e71d5392c 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index 03476ab9a..f5ac449df 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index 19710f125..31c7a29f1 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json index 9d6a7e68e..dc179c08f 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json +++ b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index 6871fab36..61271f954 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json index 1f78c6add..645594bee 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 27dcfa339..b783b5f54 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index d54831747..83c89c123 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -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 ✔", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json index 64273f219..f6eeffc23 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json @@ -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 ✔", diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index ca3373fd9..96a41c39c 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -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.customBlockItemModel("blaze_burner", "block_with_blaze")) .build() diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java index 40b75f65e..3301a711d 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/AbstractContraptionEntity.java @@ -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(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java index 3e24329be..c217d15ff 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsHandler.java @@ -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 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(entity); controlsPos = controllerLocalPos; diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java index 019c27a38..b83fb9e6e 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/interaction/controls/ControlsInteractionBehaviour.java @@ -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; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java new file mode 100644 index 000000000..5002c63a4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/burner/BlazeBurnerInteractionBehaviour.java @@ -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; + } + +} diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 9723b19c4..d9df6f26e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -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 entity; Couple 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 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 sides = entity.checkConductors(); + hasForwardConductor = sides.getFirst(); + hasBackwardConductor = sides.getSecond(); + } + public void createEntity(Level level) { contraption.startMoving(level); CarriageContraptionEntity entity = CarriageContraptionEntity.create(level, contraption); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java index d70f5e477..7025131a7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraption.java @@ -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 blazeBurnerConductors; + public Map> 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 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); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java index b03eb9269..4a6d49871 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageContraptionEntity.java @@ -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 checkConductors() { + Couple 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 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; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index 7a77d083a..75230ab63 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -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 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> 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 path = new ArrayList<>(); if (graph == null) - return Pair.of(-1d, path); + return Pair.of(null, path); Couple target = destination.edgeLocation; - TravellingPoint leadingPoint = train.carriages.get(0) - .getLeadingPoint(); - TrackEdge initialEdge = leadingPoint.edge; + MutableObject>> frontResult = new MutableObject<>(Pair.of(null, path)); + MutableObject>> backResult = new MutableObject<>(Pair.of(null, path)); - MutableObject>> 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, TrackEdge> currentEntry = poll.getSecond(); - TrackEdge edge = currentEntry.getSecond(); - TrackNode node1 = currentEntry.getFirst() - .getFirst(); - TrackNode node2 = currentEntry.getFirst() - .getSecond(); + List 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 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, 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 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> front = frontResult.getValue(); + Pair> 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>, Pair, TrackEdge>>> condition, - double maxDistance) { + public void search(double maxDistance, boolean forward, + BiPredicate>, Pair, 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 visited = new HashSet<>(); Map> reachedVia = new IdentityHashMap<>(); PriorityQueue, 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()) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 2abf9d0d0..70e380afb 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -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 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); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java index b0592e50e..00ec20eaf 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainStatus.java @@ -16,6 +16,7 @@ public class TrainStatus { boolean navigation; boolean track; + boolean conductor; List 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; + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 92fd2dcd0..582910e24 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -107,7 +107,6 @@ public class TravellingPoint { public ITrackSelector steer(SteerDirection direction, Vec3 upNormal) { return (graph, pair) -> { List> validTargets = pair.getSecond(); - boolean forward = pair.getFirst(); double closest = Double.MAX_VALUE; Entry 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; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleItem.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleItem.java index 691a2ca8b..27eee5726 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleItem.java @@ -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 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(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleRuntime.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleRuntime.java index 8da5ac817..342482d29 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleRuntime.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/ScheduleRuntime.java @@ -152,6 +152,7 @@ public class ScheduleRuntime { currentEntry = 0; paused = false; isAutoSchedule = auto; + train.status.newSchedule(); } public Schedule getSchedule() { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationScreen.java index a4da7841f..c53f614f1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/StationScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/StationScreen.java @@ -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; } diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index caeaa5141..ce2068773 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -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",