From 0f2b28a2ad137d53795b6d8fcf2aeacf51f93c8d Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Wed, 4 May 2022 01:05:03 +0200 Subject: [PATCH] The edge case files - Fixed train relocation not working - Train relocation now works on selected beziers - Fixed trains with driverless backward controls not navigating forward - Fixed trains not properly stopped by dead ends - Fixed tracks not separating edges meeting at 45 degrees - Assembly screen now shows whether any drives are present on the train - Track placement and pavement now checks and consumes inventory items in survival mode --- src/generated/resources/.cache/cache | 33 ++- .../resources/assets/create/lang/en_us.json | 3 + .../assets/create/lang/unfinished/de_de.json | 5 +- .../assets/create/lang/unfinished/es_cl.json | 5 +- .../assets/create/lang/unfinished/es_es.json | 5 +- .../assets/create/lang/unfinished/fr_fr.json | 5 +- .../assets/create/lang/unfinished/it_it.json | 5 +- .../assets/create/lang/unfinished/ja_jp.json | 5 +- .../assets/create/lang/unfinished/ko_kr.json | 5 +- .../assets/create/lang/unfinished/nl_nl.json | 5 +- .../assets/create/lang/unfinished/pl_pl.json | 5 +- .../assets/create/lang/unfinished/pt_br.json | 5 +- .../assets/create/lang/unfinished/pt_pt.json | 5 +- .../assets/create/lang/unfinished/ro_ro.json | 5 +- .../assets/create/lang/unfinished/ru_ru.json | 5 +- .../assets/create/lang/unfinished/zh_cn.json | 5 +- .../assets/create/lang/unfinished/zh_tw.json | 5 +- .../tags/blocks/active_boiler_heaters.json | 8 - .../steam/SteamEngineTileEntity.java | 6 +- .../tools/BlueprintOverlayRenderer.java | 38 +++- .../trains/GlobalRailwayManager.java | 2 +- .../content/logistics/trains/ITrackBlock.java | 13 +- .../logistics/trains/RailwaySavedData.java | 6 +- .../logistics/trains/TrackNodeLocation.java | 17 +- .../logistics/trains/TrackPropagator.java | 9 +- .../logistics/trains/entity/Carriage.java | 1 + .../trains/entity/CarriageSyncData.java | 2 +- .../logistics/trains/entity/Navigation.java | 4 +- .../trains/entity/TrainRelocationPacket.java | 19 +- .../trains/entity/TrainRelocator.java | 35 +++- .../trains/entity/TravellingPoint.java | 9 +- .../edgePoint/signal/SignalEdgeGroup.java | 9 + .../edgePoint/station/AssemblyScreen.java | 50 +++-- .../edgePoint/station/StationTileEntity.java | 33 ++- .../trains/track/StandardBogeyBlock.java | 2 +- .../logistics/trains/track/TrackBlock.java | 53 ++--- .../trains/track/TrackBlockItem.java | 52 ++--- .../logistics/trains/track/TrackPaver.java | 75 ++++--- .../trains/track/TrackPlacement.java | 192 ++++++++++++++++-- .../simibubi/create/events/InputEvents.java | 1 - .../create/foundation/utility/NBTHelper.java | 7 +- .../assets/create/lang/default/interface.json | 3 + 42 files changed, 554 insertions(+), 203 deletions(-) delete mode 100644 src/generated/resources/data/create/tags/blocks/active_boiler_heaters.json diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index 4438cf566..86b31cce9 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -543,22 +543,22 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json 7fbb25c577025ff61388c54c43401d8bb80723dd assets/create/lang/en_ud.json -21bf73628fbf1f4e3a496f3ae1b0511193f42ddc assets/create/lang/en_us.json -b8e107ed495ab72b5ee2e5d150d10bb6f9738ef2 assets/create/lang/unfinished/de_de.json -130c39194325888e3b7d8b0fe8186cc1064558b8 assets/create/lang/unfinished/es_cl.json -fcba07a025fb54f1de46953eaa182bd422ce8b07 assets/create/lang/unfinished/es_es.json -ff2a7df3eb9555df959761654bec0df7adc14a06 assets/create/lang/unfinished/fr_fr.json -1bbaf5201cbe698bdcb946168992f1a6c59a5b5c assets/create/lang/unfinished/it_it.json -62f5f1eb810e76911ddf26af4bd14ac9ff22205e assets/create/lang/unfinished/ja_jp.json -f9788d8bdd53e4b1ddaff505eeb5ff783ac6037d assets/create/lang/unfinished/ko_kr.json -afa72a4a1bc4d3aac3ee1960713c1ee7006d0d4d assets/create/lang/unfinished/nl_nl.json -d8c932f13fde024184ab121def7d4c14195e87a0 assets/create/lang/unfinished/pl_pl.json -e65c509495f72c872a3517b40f1cba3e81b2eb4a assets/create/lang/unfinished/pt_br.json -e3757ef8da2b88d3c83e6974c2d9ef36d1548121 assets/create/lang/unfinished/pt_pt.json -1313ea94854c11e4b55fe2a2cf143c5a548ec58d assets/create/lang/unfinished/ro_ro.json -7bc26d8d8b2162615513fba5dd4f48cf787f3f45 assets/create/lang/unfinished/ru_ru.json -2e704ec8d4cfb767cf22b7c154677e374f7377c9 assets/create/lang/unfinished/zh_cn.json -c6dba4495d3a03c2ea196c59c085f90ff9452b51 assets/create/lang/unfinished/zh_tw.json +024a27fd48ffcc6a79c9743ece2e8c92e10190ab assets/create/lang/en_us.json +28f293c0e56f4b0928ed5784c6fa542cd958b08d assets/create/lang/unfinished/de_de.json +6caa5da7f0537dab9968522151a2022cbb9f017f assets/create/lang/unfinished/es_cl.json +a182e06d08d8e1b382a1c3233b5d92553ce126bd assets/create/lang/unfinished/es_es.json +0e308ef282040673debe46ec12e6e55ac9ce985e assets/create/lang/unfinished/fr_fr.json +35d0439648d6ec63cdf47aabb631afc098c32666 assets/create/lang/unfinished/it_it.json +089dd0341bd90a9ac319064a9007c25d5e5de271 assets/create/lang/unfinished/ja_jp.json +63b018284849f4afc247d42e64fe64c06e7f96b0 assets/create/lang/unfinished/ko_kr.json +e861c584c4870fa6a2449207affc91b246372862 assets/create/lang/unfinished/nl_nl.json +7ea957da93493b49328f862bab2df59afdc3fe79 assets/create/lang/unfinished/pl_pl.json +4885dd6c1e1102e24c11ad17088d7a66981c73c5 assets/create/lang/unfinished/pt_br.json +54da09cde93617abe7cdc6ccb136e94221abb612 assets/create/lang/unfinished/pt_pt.json +77c2b474774c623314f66f8c975be1075b0d3dec assets/create/lang/unfinished/ro_ro.json +573a751dba49ecb96c22d5d5374de475a4875ffa assets/create/lang/unfinished/ru_ru.json +9a14db7b7a4629a2f9030f0e9c74fd919bb108e8 assets/create/lang/unfinished/zh_cn.json +597ebfa894f0e6fe1c7c33de8504370b7a81939a 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 @@ -5216,7 +5216,6 @@ d79c82bc6cf59b073b2f51f5fea9c98e81d14b68 data/create/recipes/weathered_copper_ti 452d480dd50b97fce72e0c89429cf68db534c6b2 data/create/recipes/weathered_copper_tile_slab_from_weathered_copper_tiles_stonecutting.json ac265a674626e0e832330086fd18fe0be37fc327 data/create/recipes/weathered_copper_tile_stairs.json 5942a571f79c40524bbf408775cf91de4715f2b6 data/create/recipes/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json -0003d197585d40fda7dac6c08eac0985e4a23f5c data/create/tags/blocks/active_boiler_heaters.json 6558ef43f28c92cc558fbfc572f38496f1ed479e data/create/tags/blocks/brittle.json 330bfb3850ba3964b10b1bccbc3cbb9b012cae54 data/create/tags/blocks/fan_heaters.json 57b942386a15c874d1ca9cd6a8032c11a5599fc2 data/create/tags/blocks/fan_transparent.json diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index 3a6969647..c5173ef08 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1414,6 +1414,8 @@ "create.track.turn_90": "Can only turn up to 90 Degrees", "create.track.junction_start": "Cannot start connection from a Junction", "create.track.turn_start": "Cannot start connection from a Turn", + "create.track.not_enough_tracks": "Not holding enough tracks", + "create.track.not_enough_pavement": "Not holding enough pavement blocks", "create.station.create_train": "Create new Train", "create.station.disassemble_train": "Disassemble Train", @@ -1434,6 +1436,7 @@ "create.train_assembly.nothing_attached": "No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "Bogey created. Click again to cycle type", "create.track_target.set": "Targeted track selected", "create.track_target.success": "Successfully bound to targeted track", 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 b194b7637..2448acf31 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: 1536", + "_": "Missing Localizations: 1539", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 ebc522724..b6229b0d4 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: 547", + "_": "Missing Localizations: 550", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 04aacb5f4..1fa624836 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: 218", + "_": "Missing Localizations: 221", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 47b5ead3c..d68799846 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: 1798", + "_": "Missing Localizations: 1801", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 7e4da414d..5ae430b8e 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: 1487", + "_": "Missing Localizations: 1490", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 b22346151..3fab3abf8 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: 213", + "_": "Missing Localizations: 216", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 bb1750335..49f70a930 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: 213", + "_": "Missing Localizations: 216", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 0c1e7c14d..330f92cb0 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: 2151", + "_": "Missing Localizations: 2154", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 b7bedd453..64ff1480a 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: 586", + "_": "Missing Localizations: 589", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 934c96364..8ebe4cb1a 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: 1398", + "_": "Missing Localizations: 1401", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 8db619305..f69fd254c 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: 1770", + "_": "Missing Localizations: 1773", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", diff --git a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json b/src/generated/resources/assets/create/lang/unfinished/ro_ro.json index 1709a0df7..135552914 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json +++ b/src/generated/resources/assets/create/lang/unfinished/ro_ro.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 214", + "_": "Missing Localizations: 217", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 a31e16450..afa8345ed 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: 591", + "_": "Missing Localizations: 594", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 7390464e0..620230e2c 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: 213", + "_": "Missing Localizations: 216", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", 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 f09af56c8..15a22aaff 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: 605", + "_": "Missing Localizations: 608", "_": "->------------------------] Game Elements [------------------------<-", @@ -1415,6 +1415,8 @@ "create.track.turn_90": "UNLOCALIZED: Can only turn up to 90 Degrees", "create.track.junction_start": "UNLOCALIZED: Cannot start connection from a Junction", "create.track.turn_start": "UNLOCALIZED: Cannot start connection from a Turn", + "create.track.not_enough_tracks": "UNLOCALIZED: Not holding enough tracks", + "create.track.not_enough_pavement": "UNLOCALIZED: Not holding enough pavement blocks", "create.station.create_train": "UNLOCALIZED: Create new Train", "create.station.disassemble_train": "UNLOCALIZED: Disassemble Train", @@ -1435,6 +1437,7 @@ "create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "UNLOCALIZED: At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "UNLOCALIZED: A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "UNLOCALIZED: Bogey created. Click again to cycle type", "create.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", diff --git a/src/generated/resources/data/create/tags/blocks/active_boiler_heaters.json b/src/generated/resources/data/create/tags/blocks/active_boiler_heaters.json deleted file mode 100644 index e9e85ee8d..000000000 --- a/src/generated/resources/data/create/tags/blocks/active_boiler_heaters.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "replace": false, - "values": [ - "minecraft:furnace", - "minecraft:blast_furnace", - "minecraft:smoker" - ] -} \ No newline at end of file diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java index e4fddbbb0..0610f799a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/steam/SteamEngineTileEntity.java @@ -91,10 +91,10 @@ public class SteamEngineTileEntity extends SmartTileEntity implements IHaveGoggl @Override @OnlyIn(Dist.CLIENT) - public AABB getRenderBoundingBox() { - return super.getRenderBoundingBox().inflate(2); + protected AABB createRenderBoundingBox() { + return super.createRenderBoundingBox().inflate(2); } - + public PoweredShaftTileEntity getShaft() { PoweredShaftTileEntity shaft = target.get(); if (shaft == null || shaft.isRemoved() || !shaft.canBePoweredBy(worldPosition)) { diff --git a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java index 2b4333a9a..f3c74c14e 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java +++ b/src/main/java/com/simibubi/create/content/curiosities/tools/BlueprintOverlayRenderer.java @@ -9,12 +9,14 @@ import java.util.Optional; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +import com.simibubi.create.AllBlocks; import com.simibubi.create.AllItems; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintCraftingInventory; import com.simibubi.create.content.curiosities.tools.BlueprintEntity.BlueprintSection; import com.simibubi.create.content.logistics.item.filter.AttributeFilterContainer.WhitelistMode; import com.simibubi.create.content.logistics.item.filter.FilterItem; import com.simibubi.create.content.logistics.item.filter.ItemAttribute; +import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.gui.AllGuiTextures; import com.simibubi.create.foundation.gui.element.GuiGameElement; import com.simibubi.create.foundation.utility.AnimationTickHolder; @@ -47,6 +49,7 @@ public class BlueprintOverlayRenderer { static boolean active; static boolean empty; + static boolean noOutput; static boolean lastSneakState; static BlueprintSection lastTargetedSection; @@ -62,6 +65,8 @@ public class BlueprintOverlayRenderer { boolean sneak = mc.player.isShiftKeyDown(); lastTargetedSection = null; active = false; + noOutput = false; + if (mouseOver == null) return; if (mouseOver.getType() != Type.ENTITY) @@ -85,6 +90,29 @@ public class BlueprintOverlayRenderer { lastSneakState = sneak; } + public static void displayTrackRequirements(PlacementInfo info, ItemStack pavementItem) { + if (active) + return; + + active = true; + empty = false; + noOutput = true; + ingredients.clear(); + + int tracks = info.requiredTracks; + while (tracks > 0) { + ingredients.add(Pair.of(AllBlocks.TRACK.asStack(Math.min(64, tracks)), info.hasRequiredTracks)); + tracks -= 64; + } + + int pavement = info.requiredPavement; + while (pavement > 0) { + ingredients.add(Pair.of(ItemHandlerHelper.copyStackWithSize(pavementItem, Math.min(64, pavement)), + info.hasRequiredPavement)); + pavement -= 64; + } + } + public static void rebuild(BlueprintSection sectionAt, boolean sneak) { cachedRenderedFilters.clear(); ItemStackHandler items = sectionAt.getItems(); @@ -212,10 +240,13 @@ public class BlueprintOverlayRenderer { return; Minecraft mc = Minecraft.getInstance(); - int w = 30 + 21 * ingredients.size() + 21; + int w = 21 * ingredients.size(); + + if (!noOutput) + w += 51; int x = (width - w) / 2; - int y = (int) (height / 3f * 2); + int y = (int) (height - 100); for (Pair pair : ingredients) { RenderSystem.enableBlend(); @@ -226,6 +257,9 @@ public class BlueprintOverlayRenderer { x += 21; } + if (noOutput) + return; + x += 5; RenderSystem.enableBlend(); AllGuiTextures.HOTSLOT_ARROW.render(poseStack, x, y + 4); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java index cabfe2418..a087cba9d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/GlobalRailwayManager.java @@ -125,7 +125,7 @@ public class GlobalRailwayManager { public void putGraphWithDefaultGroup(TrackGraph graph) { SignalEdgeGroup group = new SignalEdgeGroup(graph.id); - signalEdgeGroups.put(graph.id, group); + signalEdgeGroups.put(graph.id, group.asFallback()); sync.edgeGroupCreated(graph.id, group.color); putGraph(graph); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java index eeb570bf8..920a4a212 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/ITrackBlock.java @@ -66,7 +66,7 @@ public interface ITrackBlock { TrackShape shape = state.getValue(TrackBlock.SHAPE); getTrackAxes(world, pos, state).forEach(axis -> { addToListIfConnected(connectedTo, list, (d, b) -> axis.scale(b ? d : -d) - .add(center), b -> shape.getNormal(), null); + .add(center), b -> shape.getNormal(), axis, null); }); return list; @@ -74,12 +74,14 @@ public interface ITrackBlock { public static void addToListIfConnected(@Nullable TrackNodeLocation fromEnd, Collection list, BiFunction offsetFactory, Function normalFactory, - BezierConnection viaTurn) { + Vec3 axis, BezierConnection viaTurn) { DiscoveredLocation firstLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, true)).viaTurn(viaTurn) - .withNormal(normalFactory.apply(true)); + .withNormal(normalFactory.apply(true)) + .withDirection(axis); DiscoveredLocation secondLocation = new DiscoveredLocation(offsetFactory.apply(0.5d, false)).viaTurn(viaTurn) - .withNormal(normalFactory.apply(false)); + .withNormal(normalFactory.apply(false)) + .withDirection(axis); boolean skipFirst = false; boolean skipSecond = false; @@ -106,7 +108,8 @@ public interface ITrackBlock { @OnlyIn(Dist.CLIENT) public PartialModel prepareTrackOverlay(BlockGetter world, BlockPos pos, BlockState state, - BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack transform, RenderedTrackOverlayType type); + BezierTrackPointLocation bezierPoint, AxisDirection direction, PoseStack transform, + RenderedTrackOverlayType type); @OnlyIn(Dist.CLIENT) public PartialModel prepareAssemblyOverlay(BlockGetter world, BlockPos pos, BlockState state, Direction direction, diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java b/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java index ca275e246..00622e92d 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/RailwaySavedData.java @@ -28,7 +28,11 @@ public class RailwaySavedData extends SavedData { Create.LOGGER.info("Saving Railway Information..."); nbt.put("RailGraphs", NBTHelper.writeCompoundList(railways.trackNetworks.values(), TrackGraph::write)); nbt.put("SignalBlocks", - NBTHelper.writeCompoundList(railways.signalEdgeGroups.values(), SignalEdgeGroup::write)); + NBTHelper.writeCompoundList(railways.signalEdgeGroups.values(), seg -> { + if (seg.fallbackGroup && !railways.trackNetworks.containsKey(seg.id)) + return null; + return seg.write(); + })); nbt.put("Trains", NBTHelper.writeCompoundList(railways.trains.values(), Train::write)); return nbt; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java index 2ccd1d573..e34cd76c4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackNodeLocation.java @@ -57,6 +57,7 @@ public class TrackNodeLocation extends Vec3i { BezierConnection turn = null; boolean forceNode = false; + Vec3 direction; Vec3 normal; public DiscoveredLocation(double p_121865_, double p_121866_, double p_121867_) { @@ -73,17 +74,22 @@ public class TrackNodeLocation extends Vec3i { forceNode(); return this; } - + public DiscoveredLocation forceNode() { forceNode = true; return this; } - + public DiscoveredLocation withNormal(Vec3 normal) { this.normal = normal; return this; } + public DiscoveredLocation withDirection(Vec3 direction) { + this.direction = direction == null ? null : direction.normalize(); + return this; + } + public boolean connectedViaTurn() { return turn != null; } @@ -91,11 +97,16 @@ public class TrackNodeLocation extends Vec3i { public BezierConnection getTurn() { return turn; } - + public boolean shouldForceNode() { return forceNode; } + public boolean notInLineWith(Vec3 direction) { + return this.direction != null + && Math.max(direction.dot(this.direction), direction.dot(this.direction.scale(-1))) < 7 / 8f; + } + } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java index 0b0d608b9..2ec855cb7 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackPropagator.java @@ -32,7 +32,7 @@ public class TrackPropagator { } public static void onRailRemoved(LevelAccessor reader, BlockPos pos, BlockState state) { - if (!(state.getBlock() instanceof ITrackBlock track)) + if (!(state.getBlock()instanceof ITrackBlock track)) return; Collection ends = track.getConnected(reader, pos, state, false, null); @@ -79,7 +79,7 @@ public class TrackPropagator { } public static TrackGraph onRailAdded(LevelAccessor reader, BlockPos pos, BlockState state) { - if (!(state.getBlock() instanceof ITrackBlock track)) + if (!(state.getBlock()instanceof ITrackBlock track)) return null; // 1. Remove all immediately reachable node locations @@ -238,6 +238,11 @@ public class TrackPropagator { .anyMatch(DiscoveredLocation::connectedViaTurn)) return true; + Vec3 direction = location.direction; + if (direction != null && next.stream() + .anyMatch(dl -> dl.notInLineWith(direction))) + return true; + Vec3 vec = location.getLocation(); boolean centeredX = !Mth.equal(vec.x, Math.round(vec.x)); boolean centeredZ = !Mth.equal(vec.z, Math.round(vec.z)); 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 128041bb5..e47ecdd3e 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 @@ -60,6 +60,7 @@ public class Carriage { this.serialisedEntity = new CompoundTag(); this.pointsInitialised = false; this.rotationAnchors = Couple.create(null, null); + this.presentConductors = Couple.create(false, false); updateContraptionAnchors(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java index be3b609a1..dc25ceb1e 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java @@ -309,7 +309,7 @@ public class CarriageSyncData { TrackEdge newEdge = entry.getValue(); Vec3 currentDirection = edge.getDirection(false); Vec3 newDirection = newEdge.getDirection(true); - if (currentDirection.dot(newDirection) < 3 / 4f) + if (currentDirection.dot(newDirection) < 7 / 8f) continue; if (!visited.add(entry.getValue())) continue; 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 2ada1a287..886d1bd31 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 @@ -455,7 +455,7 @@ public class Navigation { return true; }); - if (!train.doubleEnded) + if (!train.doubleEnded || !train.hasBackwardConductor()) break; } @@ -620,7 +620,7 @@ public class Navigation { TrackEdge newEdge = connection.getValue(); Vec3 currentDirection = edge.getDirection(false); Vec3 newDirection = newEdge.getDirection(true); - if (currentDirection.dot(newDirection) < 3 / 4f) + if (currentDirection.dot(newDirection) < 7 / 8f) continue; validTargets.add(connection); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java index 939efdf1d..340aa830b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocationPacket.java @@ -4,6 +4,7 @@ import java.util.UUID; import java.util.function.Supplier; import com.simibubi.create.Create; +import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; import com.simibubi.create.foundation.networking.SimplePacketBase; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.VecHelper; @@ -22,17 +23,25 @@ public class TrainRelocationPacket extends SimplePacketBase { BlockPos pos; Vec3 lookAngle; int entityId; + private boolean direction; + private BezierTrackPointLocation hoveredBezier; public TrainRelocationPacket(FriendlyByteBuf buffer) { trainId = buffer.readUUID(); pos = buffer.readBlockPos(); lookAngle = VecHelper.read(buffer); entityId = buffer.readInt(); + direction = buffer.readBoolean(); + if (buffer.readBoolean()) + hoveredBezier = new BezierTrackPointLocation(buffer.readBlockPos(), buffer.readInt()); } - public TrainRelocationPacket(UUID trainId, BlockPos pos, Vec3 lookAngle, int entityId) { + public TrainRelocationPacket(UUID trainId, BlockPos pos, BezierTrackPointLocation hoveredBezier, boolean direction, + Vec3 lookAngle, int entityId) { this.trainId = trainId; this.pos = pos; + this.hoveredBezier = hoveredBezier; + this.direction = direction; this.lookAngle = lookAngle; this.entityId = entityId; } @@ -43,6 +52,12 @@ public class TrainRelocationPacket extends SimplePacketBase { buffer.writeBlockPos(pos); VecHelper.write(lookAngle, buffer); buffer.writeInt(entityId); + buffer.writeBoolean(direction); + buffer.writeBoolean(hoveredBezier != null); + if (hoveredBezier != null) { + buffer.writeBlockPos(hoveredBezier.curveTarget()); + buffer.writeInt(hoveredBezier.segment()); + } } @Override @@ -77,7 +92,7 @@ public class TrainRelocationPacket extends SimplePacketBase { return; } - if (TrainRelocator.relocate(train, sender.level, pos, lookAngle, false)) { + if (TrainRelocator.relocate(train, sender.level, pos, hoveredBezier, direction, lookAngle, false)) { sender.displayClientMessage(Lang.translate("train.relocate.success") .withStyle(ChatFormatting.GREEN), true); train.syncTrackGraphChanges(); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java index a65a369f6..6601b6eba 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.trains.entity; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.UUID; import java.util.function.Consumer; @@ -26,6 +27,9 @@ import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdge import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; +import com.simibubi.create.content.logistics.trains.track.BezierTrackPointLocation; +import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline; +import com.simibubi.create.content.logistics.trains.track.TrackBlockOutline.BezierPointSelection; import com.simibubi.create.foundation.item.TooltipHelper; import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.utility.Couple; @@ -58,6 +62,7 @@ public class TrainRelocator { static int relocatingEntityId; static BlockPos lastHoveredPos; + static BezierTrackPointLocation lastHoveredBezierSegment; static Boolean lastHoveredResult; static List toVisualise; @@ -104,7 +109,9 @@ public class TrainRelocator { HitResult hitResult = mc.hitResult; if (!(hitResult instanceof BlockHitResult blockhit)) return null; + BlockPos blockPos = blockhit.getBlockPos(); + BezierTrackPointLocation hoveredBezier = null; if (simulate && toVisualise != null && lastHoveredResult != null) { for (int i = 0; i < toVisualise.size() - 1; i++) { @@ -117,10 +124,19 @@ public class TrainRelocator { } } + BezierPointSelection bezierSelection = TrackBlockOutline.result; + if (bezierSelection != null) { + blockPos = bezierSelection.te() + .getBlockPos(); + hoveredBezier = bezierSelection.loc(); + } + if (simulate) { - if (lastHoveredPos != null && lastHoveredPos.equals(blockPos)) + if (lastHoveredPos != null && lastHoveredPos.equals(blockPos) + && Objects.equals(lastHoveredBezierSegment, hoveredBezier)) return lastHoveredResult; lastHoveredPos = blockPos; + lastHoveredBezierSegment = hoveredBezier; toVisualise = null; } @@ -129,22 +145,27 @@ public class TrainRelocator { return lastHoveredResult = null; Vec3 lookAngle = mc.player.getLookAngle(); - boolean result = relocate(relocating, mc.level, blockPos, lookAngle, true); + boolean direction = bezierSelection != null && lookAngle.dot(bezierSelection.direction()) < 0; + boolean result = relocate(relocating, mc.level, blockPos, hoveredBezier, direction, lookAngle, true); if (!simulate && result) - AllPackets.channel - .sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, lookAngle, relocatingEntityId)); + AllPackets.channel.sendToServer(new TrainRelocationPacket(relocatingTrain, blockPos, hoveredBezier, + direction, lookAngle, relocatingEntityId)); return lastHoveredResult = result; } - public static boolean relocate(Train train, Level level, BlockPos pos, Vec3 lookAngle, boolean simulate) { + public static boolean relocate(Train train, Level level, BlockPos pos, BezierTrackPointLocation bezier, + boolean bezierDirection, Vec3 lookAngle, boolean simulate) { BlockState blockState = level.getBlockState(pos); if (!(blockState.getBlock()instanceof ITrackBlock track)) return false; Pair nearestTrackAxis = track.getNearestTrackAxis(level, pos, blockState, lookAngle); - GraphLocation graphLocation = - TrackGraphHelper.getGraphLocationAt(level, pos, nearestTrackAxis.getSecond(), nearestTrackAxis.getFirst()); + GraphLocation graphLocation = bezier != null + ? TrackGraphHelper.getBezierGraphLocationAt(level, pos, + bezierDirection ? AxisDirection.POSITIVE : AxisDirection.NEGATIVE, bezier) + : TrackGraphHelper.getGraphLocationAt(level, pos, nearestTrackAxis.getSecond(), + nearestTrackAxis.getFirst()); if (graphLocation == null) return 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 5760f8119..ace20dd28 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 @@ -29,6 +29,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; +import net.minecraft.util.Mth; import net.minecraft.world.phys.Vec3; public class TravellingPoint { @@ -179,7 +180,7 @@ public class TravellingPoint { IEdgePointListener signalListener, ITurnListener turnListener) { blocked = false; double edgeLength = edge.getLength(); - if (distance == 0) + if (Mth.equal(distance, 0)) return 0; double prevPos = position; @@ -223,7 +224,7 @@ public class TravellingPoint { TrackEdge newEdge = entry.getValue(); Vec3 currentDirection = edge.getDirection(false); Vec3 newDirection = newEdge.getDirection(true); - if (currentDirection.dot(newDirection) < 3 / 4f) + if (currentDirection.dot(newDirection) < 7 / 8f) continue; validTargets.add(entry); @@ -276,14 +277,14 @@ public class TravellingPoint { .get(node1); Vec3 currentDirection = edge.getDirection(true); Vec3 newDirection = newEdge.getDirection(false); - if (currentDirection.dot(newDirection) < 3 / 4f) + if (currentDirection.dot(newDirection) < 7 / 8f) continue; validTargets.add(entry); } if (validTargets.isEmpty()) { - traveled += position; + traveled -= position; position = 0; blocked = true; break; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java index edbde3214..3f84a6f47 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalEdgeGroup.java @@ -29,6 +29,8 @@ public class SignalEdgeGroup { public Map intersecting; public Set intersectingResolved; public Set adjacent; + + public boolean fallbackGroup; public SignalEdgeGroup(UUID id) { this.id = id; @@ -38,6 +40,11 @@ public class SignalEdgeGroup { intersectingResolved = new HashSet<>(); color = EdgeGroupColor.getDefault(); } + + public SignalEdgeGroup asFallback() { + fallbackGroup = true; + return this; + } public boolean isOccupiedUnless(Train train) { if (intersectingResolved.isEmpty()) @@ -129,6 +136,7 @@ public class SignalEdgeGroup { group.color = NBTHelper.readEnum(tag, "Color", EdgeGroupColor.class); NBTHelper.iterateCompoundList(tag.getList("Connected", Tag.TAG_COMPOUND), nbt -> group.intersecting.put(nbt.getUUID("Key"), nbt.getUUID("Value"))); + group.fallbackGroup = tag.getBoolean("Fallback"); return group; } @@ -142,6 +150,7 @@ public class SignalEdgeGroup { nbt.putUUID("Value", e.getValue()); return nbt; })); + tag.putBoolean("Fallback", fallbackGroup); return tag; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java index 3860421e9..bdc5ccdaa 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/AssemblyScreen.java @@ -18,7 +18,6 @@ import com.simibubi.create.foundation.gui.widget.ScrollInput; import com.simibubi.create.foundation.networking.AllPackets; import net.minecraft.client.gui.components.Widget; -import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TextComponent; import net.minecraft.resources.ResourceLocation; @@ -103,6 +102,10 @@ public class AssemblyScreen extends AbstractStationScreen { tickTrainDisplay(); Train train = displayedTrain.get(); toggleAssemblyButton.active = te.bogeyCount > 0 || train != null; + + if (train != null) + for (Carriage carriage : train.carriages) + carriage.updateConductors(); } private void tickTrainDisplay() { @@ -151,15 +154,21 @@ public class AssemblyScreen extends AbstractStationScreen { TrainIconType icon = train.icon; int offset = 0; int position = background.width / 2 - getTrainIconWidth(train) / 2; + boolean frontConductor = false; + boolean backConductor = false; List carriages = train.carriages; - for (int i = carriages.size() - 1; i > 0; i--) { - if (i == carriages.size() - 1 && train.doubleEnded) { - offset += icon.render(TrainIconType.FLIPPED_ENGINE, ms, x + offset + position, y + 20) + 1; - continue; - } + for (int i = carriages.size() - 1; i >= 0; i--) { Carriage carriage = carriages.get(i); - offset += icon.render(carriage.bogeySpacing, ms, x + offset + position, y + 20) + 1; + frontConductor |= carriage.presentConductors.getFirst(); + backConductor |= carriage.presentConductors.getSecond(); + + if (i == 0) + continue; + if (i == carriages.size() - 1 && train.doubleEnded) + offset += icon.render(TrainIconType.FLIPPED_ENGINE, ms, x + offset + position, y + 20) + 1; + else + offset += icon.render(carriage.bogeySpacing, ms, x + offset + position, y + 20) + 1; } offset += icon.render(TrainIconType.ENGINE, ms, x + offset + position, y + 20); @@ -171,15 +180,18 @@ public class AssemblyScreen extends AbstractStationScreen { TextComponent text = new TextComponent("Assembly Successful"); font.drawShadow(ms, text, x + 97 - font.width(text) / 2, y + 47, 0xC6C6C6); font.drawShadow(ms, - new TextComponent("-> " + train.carriages.size() + " Carriages, " + train.getTotalLength() + "m"), + new TextComponent("-> " + train.carriages.size() + " Carriage(s), " + train.getTotalLength() + "m"), x + 30, y + 67, 0xC6C6C6); - font.drawShadow(ms, new TextComponent("-> Fuel Type: NYI"), x + 30, y + 77, 0xC6C6C6); - font.drawShadow(ms, new TextComponent("-> " + (train.doubleEnded ? "Dual Powered" : "Single Powered")), - x + 30, y + 92, 0xC6C6C6); font.drawShadow(ms, - new TextComponent((train.doubleEnded ? "(Navigates both ways)" : "(Navigates forward only)")), x + 30, - y + 102, 0xACC4BC); + new TextComponent("-> " + (frontConductor || backConductor ? "Drivers present" : "No drivers found")), + x + 30, y + 82, 0xC6C6C6); + + font.drawShadow(ms, new TextComponent("-> " + (train.doubleEnded ? "Dual Controls" : "Single Controls")), + x + 30, y + 97, 0xC6C6C6); + font.drawShadow(ms, + new TextComponent((train.doubleEnded ? "(Navigates both ways)" : "(Navigates forward only)")), x + 35, + y + 107, 0xACC4BC); return; } @@ -205,10 +217,12 @@ public class AssemblyScreen extends AbstractStationScreen { new TextComponent(bogeyCount == 0 ? "No Bogeys" : bogeyCount + (bogeyCount == 1 ? " Bogey" : " Bogeys")); font.draw(ms, text, x + 97 - font.width(text) / 2, y + 47, 0x7A7A7A); - Component component = - new TextComponent("Right-click on highlighted Tracks to create bogeys. Use Wrench to cycle type." - + "\n\nAttach structures to one or between two bogeys to form carriages."); - font.drawWordWrap(component, x + 30, y + 67, 134, 0x7A7A7A); + font.drawWordWrap(new TextComponent("Right-click on highlighted Tracks to create bogeys."), x + 28, y + 67, 134, + 0x7A7A7A); + font.drawWordWrap(new TextComponent("Remove bogeys by breaking the block on top."), x + 28, y + 90, 134, + 0x7A7A7A); + font.drawWordWrap(new TextComponent("Build carriages attached to one or two bogeys each."), x + 28, y + 113, + 138, 0x7A7A7A); } @Override @@ -221,7 +235,7 @@ public class AssemblyScreen extends AbstractStationScreen { AllPackets.channel.sendToServer(new TrainEditPacket(train.id, "", !assemblyCompleted, iconId)); } } - + @Override protected PartialModel getFlag(float partialTicks) { return AllBlockPartials.STATION_ASSEMBLE; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java index 6bf62cceb..1d9c434b3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java @@ -50,9 +50,11 @@ import net.minecraft.core.Direction.AxisDirection; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; @@ -235,20 +237,39 @@ public class StationTileEntity extends SmartTileEntity { } } - public void trackClicked(Player player, ITrackBlock track, BlockState state, BlockPos pos) { + public boolean trackClicked(Player player, ITrackBlock track, BlockState state, BlockPos pos) { refreshAssemblyInfo(); BoundingBox bb = assemblyAreas.get(level) .get(worldPosition); if (bb == null || !bb.isInside(pos)) - return; + return false; + BlockPos up = new BlockPos(track.getUpNormal(level, pos, state)); int bogeyOffset = pos.distManhattan(edgePoint.getGlobalPosition()) - 1; - if (!isValidBogeyOffset(bogeyOffset)) - return; + if (!isValidBogeyOffset(bogeyOffset)) { + + for (int i = -1; i <= 1; i++) { + BlockPos bogeyPos = pos.relative(assemblyDirection, i) + .offset(up); + BlockState blockState = level.getBlockState(bogeyPos); + if (blockState.getBlock()instanceof IBogeyBlock bogey) { + level.setBlock(bogeyPos, bogey.getRotatedBlockState(blockState, Direction.DOWN), 3); + bogey.playRotateSound(level, bogeyPos); + return true; + } + } + + return false; + } - Vec3 upNormal = track.getUpNormal(level, pos, state); BlockState bogeyAnchor = track.getBogeyAnchor(level, pos, state); - level.setBlock(pos.offset(new BlockPos(upNormal)), bogeyAnchor, 3); + level.setBlock(pos.offset(up), bogeyAnchor, 3); + player.displayClientMessage(Lang.translate("train_assembly.bogey_created"), true); + SoundType soundtype = bogeyAnchor.getBlock() + .getSoundType(state, level, pos, player); + level.playSound(null, pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, + soundtype.getPitch() * 0.8F); + return true; } public boolean isAssembling() { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java index e579cbf35..5540d0a2c 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/StandardBogeyBlock.java @@ -62,7 +62,7 @@ public class StandardBogeyBlock extends Block implements IBogeyBlock, ITE axis.scale(b ? 0 : fromCenter ? -d : d) .add(center), - b -> shape.getNormal(), null); + b -> shape.getNormal(), axis, null); } else list = ITrackBlock.super.getConnected(world, pos, state, linear, connectedTo); @@ -202,7 +198,8 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac Map connections = trackTE.getConnections(); connections.forEach((connectedPos, bc) -> ITrackBlock.addToListIfConnected(connectedTo, list, - (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, bc)); + (d, b) -> d == 1 ? Vec3.atLowerCornerOf(bc.tePositions.get(b)) : bc.starts.get(b), bc.normals::get, null, + bc)); return list; } @@ -227,29 +224,17 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac @Override public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) { - ItemStack itemInHand = player.getItemInHand(hand); - // debug remove all graphs - if (Blocks.SPONGE.asItem() == itemInHand.getItem()) { - Create.RAILWAYS.trackNetworks.clear(); - CreateClient.RAILWAYS.trackNetworks.clear(); - Create.RAILWAYS.signalEdgeGroups.clear(); - CreateClient.RAILWAYS.signalEdgeGroups.clear(); - return InteractionResult.SUCCESS; - } - - if (itemInHand.isEmpty()) { - if (world.isClientSide) - return InteractionResult.SUCCESS; - for (Entry entry : StationTileEntity.assemblyAreas.get(world) - .entrySet()) { - if (!entry.getValue() - .isInside(pos)) - continue; - if (world.getBlockEntity(entry.getKey()) instanceof StationTileEntity station) - station.trackClicked(player, this, state, pos); - } + if (world.isClientSide) return InteractionResult.SUCCESS; + for (Entry entry : StationTileEntity.assemblyAreas.get(world) + .entrySet()) { + if (!entry.getValue() + .isInside(pos)) + continue; + if (world.getBlockEntity(entry.getKey())instanceof StationTileEntity station) + if (station.trackClicked(player, this, state, pos)) + return InteractionResult.SUCCESS; } return InteractionResult.PASS; @@ -263,7 +248,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac BlockPos girderPos = pPos.below() .offset(vec3.z * side, 0, vec3.x * side); BlockState girderState = pLevel.getBlockState(girderPos); - if (girderState.getBlock() instanceof GirderBlock girderBlock + if (girderState.getBlock()instanceof GirderBlock girderBlock && !blockTicks.hasScheduledTick(girderPos, girderBlock)) pLevel.scheduleTick(girderPos, girderBlock, 1); } @@ -362,16 +347,16 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac @Override public InteractionResult onWrenched(BlockState state, UseOnContext context) { - if (context.getLevel().isClientSide) - TrackRemoval.wrenched(context.getClickedPos()); +// if (context.getLevel().isClientSide) +// TrackRemoval.wrenched(context.getClickedPos()); return InteractionResult.SUCCESS; } @Override public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) { - if (context.getLevel().isClientSide) - TrackRemoval.sneakWrenched(context.getClickedPos()); - return InteractionResult.SUCCESS; +// if (context.getLevel().isClientSide) +// TrackRemoval.sneakWrenched(context.getClickedPos()); + return IWrenchable.super.onSneakWrenched(state, context); } @Override @@ -443,7 +428,7 @@ public class TrackBlock extends Block implements EntityBlock, IWrenchable, ITrac Vec3 normal = null; Vec3 offset = null; - if (bezierPoint != null && world.getBlockEntity(pos) instanceof TrackTileEntity trackTE) { + if (bezierPoint != null && world.getBlockEntity(pos)instanceof TrackTileEntity trackTE) { BezierConnection bc = trackTE.connections.get(bezierPoint.curveTarget()); if (bc != null) { double length = Mth.floor(bc.getLength() * 2); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java index 0a65a7fdb..6d55c789f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackBlockItem.java @@ -1,10 +1,10 @@ package com.simibubi.create.content.logistics.trains.track; import com.simibubi.create.AllBlocks; +import com.simibubi.create.AllSoundEvents; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.content.logistics.trains.track.TrackPlacement.PlacementInfo; import com.simibubi.create.foundation.networking.AllPackets; -import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.VecHelper; @@ -15,6 +15,8 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction.AxisDirection; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; @@ -25,7 +27,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; @@ -51,11 +53,13 @@ public class TrackBlockItem extends BlockItem { if (player == null) return super.useOn(pContext); + if (pContext.getHand() == InteractionHand.OFF_HAND) + return super.useOn(pContext); Vec3 lookAngle = player.getLookAngle(); if (!isFoil(stack)) { - if (state.getBlock() instanceof TrackBlock track && track.getTrackAxes(level, pos, state) + if (state.getBlock()instanceof TrackBlock track && track.getTrackAxes(level, pos, state) .size() > 1) { if (!level.isClientSide) player.displayClientMessage(Lang.translate("track.junction_start") @@ -63,15 +67,18 @@ public class TrackBlockItem extends BlockItem { return InteractionResult.SUCCESS; } - if (select(level, pos, lookAngle, stack)) + if (select(level, pos, lookAngle, stack)) { + level.playSound(null, pos, SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, 0.75f, 1); return InteractionResult.SUCCESS; + } return super.useOn(pContext); } else if (player.isSteppingCarefully()) { if (!level.isClientSide) { player.displayClientMessage(Lang.translate("track.selection_cleared"), true); stack.setTag(null); - } + } else + level.playSound(player, pos, SoundEvents.ITEM_FRAME_REMOVE_ITEM, SoundSource.BLOCKS, 0.75f, 1); return InteractionResult.SUCCESS; } @@ -91,36 +98,29 @@ public class TrackBlockItem extends BlockItem { ItemStack offhandItem = player.getOffhandItem(); boolean hasGirder = AllBlocks.METAL_GIRDER.isIn(offhandItem); - PlacementInfo info = TrackPlacement.tryConnect(level, pos, state, lookAngle, stack, hasGirder, extend); + PlacementInfo info = TrackPlacement.tryConnect(level, player, pos, state, stack, hasGirder, extend); if (info.message != null && !level.isClientSide) player.displayClientMessage(Lang.translate(info.message), true); - if (!info.valid) + if (!info.valid) { + AllSoundEvents.DENY.playFrom(player, 1, 1); return InteractionResult.FAIL; + } - stack.setTag(null); - - if (level.isClientSide) + if (level.isClientSide) return InteractionResult.SUCCESS; - if (offhandItem.getItem() instanceof BlockItem blockItem) { - Block block = blockItem.getBlock(); - if (block == null) - return InteractionResult.SUCCESS; - if (block instanceof EntityBlock) - return InteractionResult.SUCCESS; - - for (boolean first : Iterate.trueAndFalse) { - int extent = (first ? info.end1Extent : info.end2Extent) + (info.curve != null ? 1 : 0); - Vec3 axis = first ? info.axis1 : info.axis2; - BlockPos pavePos = first ? info.pos1 : info.pos2; - TrackPaver.paveStraight(level, pavePos.below(), axis, extent, block); - } - - if (info.curve != null) - TrackPaver.paveCurve(level, info.curve, block); + stack = player.getMainHandItem(); + if (AllBlocks.TRACK.isIn(stack)) { + stack.setTag(null); + player.setItemInHand(pContext.getHand(), stack); } + SoundType soundtype = state.getSoundType(); + if (soundtype != null) + level.playSound(null, pos, soundtype.getPlaceSound(), SoundSource.BLOCKS, + (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F); + return InteractionResult.SUCCESS; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java index ae4cdfe0b..299e6bad1 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPaver.java @@ -27,12 +27,17 @@ import net.minecraft.world.phys.Vec3; public class TrackPaver { - public static void paveStraight(Level level, BlockPos startPos, Vec3 direction, int extent, Block block) { + public static int paveStraight(Level level, BlockPos startPos, Vec3 direction, int extent, Block block, + boolean simulate, Set visited) { + int itemsNeeded = 0; + BlockState defaultBlockState = block.defaultBlockState(); - if (defaultBlockState.hasProperty(SlabBlock.TYPE)) - defaultBlockState = defaultBlockState.setValue(SlabBlock.TYPE, SlabType.DOUBLE); + boolean slabLike = defaultBlockState.hasProperty(SlabBlock.TYPE); boolean wallLike = isWallLike(defaultBlockState); + if (slabLike) + defaultBlockState = defaultBlockState.setValue(SlabBlock.TYPE, SlabType.DOUBLE); + if (defaultBlockState.getBlock() instanceof GirderBlock) for (Direction d : Iterate.horizontalDirections) if (Vec3.atLowerCornerOf(d.getNormal()) @@ -66,28 +71,27 @@ public class TrackPaver { } final BlockState state = defaultBlockState; - toPlaceOn.forEach(p -> placeBlockIfFree(level, p, state)); - } - - private static boolean isWallLike(BlockState defaultBlockState) { - return defaultBlockState.getBlock() instanceof WallBlock || AllBlocks.METAL_GIRDER.has(defaultBlockState); - } - - private static void placeBlockIfFree(Level level, BlockPos pos, BlockState state) { - BlockState stateAtPos = level.getBlockState(pos); - if (stateAtPos.getBlock() != state.getBlock() && stateAtPos.getMaterial() - .isReplaceable()) { - level.setBlock(pos, state, 3); + for (BlockPos p : toPlaceOn) { + if (!visited.add(p)) + continue; + if (placeBlockIfFree(level, p, state, simulate)) + itemsNeeded += slabLike ? 2 : 1; } + visited.addAll(toPlaceOn); + + return itemsNeeded; } - public static void paveCurve(Level level, BezierConnection bc, Block block) { + public static int paveCurve(Level level, BezierConnection bc, Block block, boolean simulate, + Set visited) { + int itemsNeeded = 0; + BlockState defaultBlockState = block.defaultBlockState(); - boolean slab = defaultBlockState.hasProperty(SlabBlock.TYPE); - if (slab) + boolean slabLike = defaultBlockState.hasProperty(SlabBlock.TYPE); + if (slabLike) defaultBlockState = defaultBlockState.setValue(SlabBlock.TYPE, SlabType.DOUBLE); if (isWallLike(defaultBlockState)) - return; + return 0; Map, Double> yLevels = new HashMap<>(); BlockPos tePosition = bc.tePositions.getFirst(); @@ -141,7 +145,7 @@ public class TrackPaver { for (Entry, Double> entry : yLevels.entrySet()) { double yValue = entry.getValue(); int floor = Mth.floor(yValue); - boolean placeSlab = slab && yValue - floor >= .5; + boolean placeSlab = slabLike && yValue - floor >= .5; BlockPos targetPos = new BlockPos(entry.getKey() .getFirst(), floor, entry.getKey() @@ -150,10 +154,35 @@ public class TrackPaver { .above(placeSlab ? 1 : 0); BlockState stateToPlace = placeSlab ? defaultBlockState.setValue(SlabBlock.TYPE, SlabType.BOTTOM) : defaultBlockState; - placeBlockIfFree(level, targetPos, stateToPlace); - if (placeSlab) - placeBlockIfFree(level, targetPos.below(), stateToPlace.setValue(SlabBlock.TYPE, SlabType.TOP)); + if (!visited.add(targetPos)) + continue; + if (placeBlockIfFree(level, targetPos, stateToPlace, simulate)) + itemsNeeded += !placeSlab ? 2 : 1; + if (placeSlab) { + if (!visited.add(targetPos.below())) + continue; + BlockState topSlab = stateToPlace.setValue(SlabBlock.TYPE, SlabType.TOP); + if (placeBlockIfFree(level, targetPos.below(), topSlab, simulate)) + itemsNeeded++; + } } + + return itemsNeeded; + } + + private static boolean isWallLike(BlockState defaultBlockState) { + return defaultBlockState.getBlock() instanceof WallBlock || AllBlocks.METAL_GIRDER.has(defaultBlockState); + } + + private static boolean placeBlockIfFree(Level level, BlockPos pos, BlockState state, boolean simulate) { + BlockState stateAtPos = level.getBlockState(pos); + if (stateAtPos.getBlock() != state.getBlock() && stateAtPos.getMaterial() + .isReplaceable()) { + if (!simulate) + level.setBlock(pos, state, 3); + return true; + } + return false; } } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java index 3b4795669..4d3f1cf60 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/track/TrackPlacement.java @@ -2,12 +2,15 @@ package com.simibubi.create.content.logistics.trains.track; import java.util.ArrayList; import java.util.Collection; +import java.util.HashSet; import java.util.List; +import java.util.Set; import com.jozufozu.flywheel.util.Color; import com.simibubi.create.AllBlocks; import com.simibubi.create.AllSpecialTextures; import com.simibubi.create.CreateClient; +import com.simibubi.create.content.curiosities.tools.BlueprintOverlayRenderer; import com.simibubi.create.content.logistics.trains.BezierConnection; import com.simibubi.create.content.logistics.trains.ITrackBlock; import com.simibubi.create.foundation.utility.AngleHelper; @@ -31,9 +34,14 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.util.Mth; import net.minecraft.world.InteractionHand; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; @@ -42,16 +50,23 @@ import net.minecraft.world.phys.HitResult.Type; import net.minecraft.world.phys.Vec3; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.items.ItemHandlerHelper; public class TrackPlacement { - static class PlacementInfo { + public static class PlacementInfo { BezierConnection curve = null; boolean valid = false; int end1Extent = 0; int end2Extent = 0; String message = null; + public int requiredTracks = 0; + public boolean hasRequiredTracks = false; + + public int requiredPavement = 0; + public boolean hasRequiredPavement = false; + // for visualisation Vec3 end1; Vec3 end2; @@ -73,14 +88,16 @@ public class TrackPlacement { } } - static PlacementInfo cached; + public static PlacementInfo cached; + static BlockPos hoveringPos; static boolean hoveringMaxed; static int hoveringAngle; static ItemStack lastItem; - public static PlacementInfo tryConnect(Level level, BlockPos pos2, BlockState state2, Vec3 lookVec, ItemStack stack, - boolean girder, boolean maximiseTurn) { + public static PlacementInfo tryConnect(Level level, Player player, BlockPos pos2, BlockState state2, + ItemStack stack, boolean girder, boolean maximiseTurn) { + Vec3 lookVec = player.getLookAngle(); int lookAngle = (int) (22.5 + AngleHelper.deg(Mth.atan2(lookVec.z, lookVec.x)) % 360) / 8; if (level.isClientSide && cached != null && pos2.equals(hoveringPos) && stack.equals(lastItem) @@ -329,18 +346,131 @@ public class TrackPlacement { info.valid = true; + info.pos1 = pos1; + info.pos2 = pos2; + info.axis1 = axis1; + info.axis2 = axis2; + + placeTracks(level, info, state1, state2, targetPos1, targetPos2, true); + + ItemStack offhandItem = player.getOffhandItem() + .copy(); + boolean shouldPave = offhandItem.getItem() instanceof BlockItem; + if (shouldPave) { + BlockItem paveItem = (BlockItem) offhandItem.getItem(); + paveTracks(level, info, paveItem, true); + info.hasRequiredPavement = true; + } + + info.hasRequiredTracks = true; + + if (!player.isCreative()) { + for (boolean simulate : Iterate.trueAndFalse) { + if (level.isClientSide && !simulate) + break; + + int tracks = info.requiredTracks; + int pavement = info.requiredPavement; + int foundTracks = 0; + int foundPavement = 0; + + Inventory inv = player.getInventory(); + int size = inv.items.size(); + for (int j = 0; j <= size + 1; j++) { + int i = j; + boolean offhand = j == size + 1; + if (j == size) + i = inv.selected; + else if (offhand) + i = 0; + else if (j == inv.selected) + continue; + + ItemStack stackInSlot = (offhand ? inv.offhand : inv.items).get(i); + boolean isTrack = AllBlocks.TRACK.isIn(stackInSlot); + if (!isTrack && (!shouldPave || offhandItem.getItem() != stackInSlot.getItem())) + continue; + if (isTrack ? foundTracks >= tracks : foundPavement >= pavement) + continue; + + int count = stackInSlot.getCount(); + + if (!simulate) { + int remainingItems = + count - Math.min(isTrack ? tracks - foundTracks : pavement - foundPavement, count); + if (i == inv.selected) + stackInSlot.setTag(null); + ItemStack newItem = ItemHandlerHelper.copyStackWithSize(stackInSlot, remainingItems); + if (offhand) + player.setItemInHand(InteractionHand.OFF_HAND, newItem); + else + inv.setItem(i, newItem); + } + + if (isTrack) + foundTracks += count; + else + foundPavement += count; + } + + if (simulate && foundTracks < tracks) { + info.valid = false; + info.tooJumbly(); + info.hasRequiredTracks = false; + return info.withMessage("not_enough_tracks"); + } + + if (simulate && foundPavement < pavement) { + info.valid = false; + info.tooJumbly(); + info.hasRequiredPavement = false; + return info.withMessage("not_enough_pavement"); + } + } + } + if (level.isClientSide()) return info; + if (shouldPave) { + BlockItem paveItem = (BlockItem) offhandItem.getItem(); + paveTracks(level, info, paveItem, false); + } + return placeTracks(level, info, state1, state2, targetPos1, targetPos2, false); + } + + private static void paveTracks(Level level, PlacementInfo info, BlockItem blockItem, boolean simulate) { + Block block = blockItem.getBlock(); + info.requiredPavement = 0; + if (block == null || block instanceof EntityBlock) + return; + + Set visited = new HashSet<>(); + + for (boolean first : Iterate.trueAndFalse) { + int extent = (first ? info.end1Extent : info.end2Extent) + (info.curve != null ? 1 : 0); + Vec3 axis = first ? info.axis1 : info.axis2; + BlockPos pavePos = first ? info.pos1 : info.pos2; + info.requiredPavement += + TrackPaver.paveStraight(level, pavePos.below(), axis, extent, block, simulate, visited); + } + + if (info.curve != null) + info.requiredPavement += TrackPaver.paveCurve(level, info.curve, block, simulate, visited); + } + + private static PlacementInfo placeTracks(Level level, PlacementInfo info, BlockState state1, BlockState state2, + BlockPos targetPos1, BlockPos targetPos2, boolean simulate) { + info.requiredTracks = 0; for (boolean first : Iterate.trueAndFalse) { int extent = first ? info.end1Extent : info.end2Extent; - Vec3 axis = first ? axis1 : axis2; - BlockPos pos = first ? pos1 : pos2; + Vec3 axis = first ? info.axis1 : info.axis2; + BlockPos pos = first ? info.pos1 : info.pos2; BlockState state = first ? state1 : state2; - if (state.hasProperty(TrackBlock.HAS_TURN)) + if (state.hasProperty(TrackBlock.HAS_TURN) && !simulate) state = state.setValue(TrackBlock.HAS_TURN, false); - for (int i = 0; i < extent; i++) { + for (int i = 0; i < (info.curve != null ? extent + 1 : extent); i++) { Vec3 offset = axis.scale(i); BlockPos offsetPos = pos.offset(offset.x, offset.y, offset.z); BlockState stateAtPos = level.getBlockState(offsetPos); @@ -348,7 +478,12 @@ public class TrackPlacement { boolean canPlace = stateAtPos.getMaterial() .isReplaceable(); - if (stateAtPos.getBlock() instanceof ITrackBlock trackAtPos) { + if (canPlace) + info.requiredTracks++; + if (simulate) + continue; + + if (stateAtPos.getBlock()instanceof ITrackBlock trackAtPos) { toPlace = trackAtPos.overlay(level, offsetPos, stateAtPos, toPlace); canPlace = true; } @@ -358,24 +493,40 @@ public class TrackPlacement { } } - info.pos1 = pos1; - info.pos2 = pos2; - info.axis1 = axis1; - info.axis2 = axis2; - if (info.curve == null) return info; - level.setBlock(targetPos1, state1.setValue(TrackBlock.HAS_TURN, true), 3); - level.setBlock(targetPos2, state2.setValue(TrackBlock.HAS_TURN, true), 3); + if (!simulate) { + BlockState stateAtPos = level.getBlockState(targetPos1); + level.setBlock(targetPos1, + (stateAtPos.getBlock() == state1.getBlock() ? stateAtPos : state1).setValue(TrackBlock.HAS_TURN, true), + 3); + + stateAtPos = level.getBlockState(targetPos2); + level.setBlock(targetPos2, + (stateAtPos.getBlock() == state2.getBlock() ? stateAtPos : state2).setValue(TrackBlock.HAS_TURN, true), + 3); + } + BlockEntity te1 = level.getBlockEntity(targetPos1); BlockEntity te2 = level.getBlockEntity(targetPos2); + int requiredTracksForTurn = (info.curve.getSegmentCount() + 1) / 2; - if (!(te1 instanceof TrackTileEntity) || !(te2 instanceof TrackTileEntity)) + if (!(te1 instanceof TrackTileEntity) || !(te2 instanceof TrackTileEntity)) { + info.requiredTracks += requiredTracksForTurn; return info; + } TrackTileEntity tte1 = (TrackTileEntity) te1; TrackTileEntity tte2 = (TrackTileEntity) te2; + + if (!tte1.getConnections() + .containsKey(tte2.getBlockPos())) + info.requiredTracks += requiredTracksForTurn; + + if (simulate) + return info; + tte1.addConnection(info.curve); tte2.addConnection(info.curve.secondary()); return info; @@ -427,7 +578,9 @@ public class TrackPlacement { return; boolean maxTurns = Minecraft.getInstance().options.keySprint.isDown(); - PlacementInfo info = tryConnect(level, pos, hitState, player.getLookAngle(), stack, false, maxTurns); + PlacementInfo info = tryConnect(level, player, pos, hitState, stack, false, maxTurns); + if (!player.isCreative() && (info.valid || !info.hasRequiredTracks || !info.hasRequiredPavement)) + BlueprintOverlayRenderer.displayTrackRequirements(info, player.getOffhandItem()); if (info.valid) player.displayClientMessage(Lang.translate("track.valid_connection") @@ -445,8 +598,7 @@ public class TrackPlacement { for (int xOffset = -2; xOffset <= 2; xOffset++) { for (int zOffset = -2; zOffset <= 2; zOffset++) { BlockPos offset = pos.offset(xOffset, 0, zOffset); - PlacementInfo adjInfo = - tryConnect(level, offset, hitState, player.getLookAngle(), stack, false, maxTurns); + PlacementInfo adjInfo = tryConnect(level, player, offset, hitState, stack, false, maxTurns); hints.get(adjInfo.valid) .add(offset.below()); } diff --git a/src/main/java/com/simibubi/create/events/InputEvents.java b/src/main/java/com/simibubi/create/events/InputEvents.java index f17ef8bec..fa30d1fdf 100644 --- a/src/main/java/com/simibubi/create/events/InputEvents.java +++ b/src/main/java/com/simibubi/create/events/InputEvents.java @@ -71,7 +71,6 @@ public class InputEvents { if (event.getKeyMapping() == mc.options.keyUse) { if (CreateClient.GLUE_HANDLER.onMouseInput()) event.setCanceled(true); - return; } if (event.getKeyMapping() == mc.options.keyPickItem) { diff --git a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java index 3951317c2..267a343eb 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/NBTHelper.java @@ -43,7 +43,12 @@ public class NBTHelper { public static ListTag writeCompoundList(Iterable list, Function serializer) { ListTag listNBT = new ListTag(); - list.forEach(t -> listNBT.add(serializer.apply(t))); + list.forEach(t -> { + CompoundTag apply = serializer.apply(t); + if (apply == null) + return; + listNBT.add(apply); + }); return listNBT; } diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 0d03e2e21..492e0767f 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -638,6 +638,8 @@ "create.track.turn_90": "Can only turn up to 90 Degrees", "create.track.junction_start": "Cannot start connection from a Junction", "create.track.turn_start": "Cannot start connection from a Turn", + "create.track.not_enough_tracks": "Not holding enough tracks", + "create.track.not_enough_pavement": "Not holding enough pavement blocks", "create.station.create_train": "Create new Train", "create.station.disassemble_train": "Disassemble Train", @@ -658,6 +660,7 @@ "create.train_assembly.nothing_attached": "No structure attached to Bogey %1$s", "create.train_assembly.no_controls": "At least one forward-facing controls block needs to be mounted on the train", "create.train_assembly.sideways_controls": "A mounted controls block is facing sideways", + "create.train_assembly.bogey_created": "Bogey created. Click again to cycle type", "create.track_target.set": "Targeted track selected", "create.track_target.success": "Successfully bound to targeted track",