Manual Steering

- Trains can now travel backwards through the graph
- Controls are now a requirement for assembly
- Double-endedness now depends on two opposite controls blocks anywhere on the train
- Players can now manually control trains via a mounted controls block
This commit is contained in:
simibubi 2022-02-05 02:06:31 +01:00
parent 478d891a04
commit 0a931a77ef
44 changed files with 1123 additions and 364 deletions

View file

@ -536,21 +536,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
9ffe5b3f8a39fa3c3a97a3c534bd82402177e82e assets/create/lang/en_ud.json 9ffe5b3f8a39fa3c3a97a3c534bd82402177e82e assets/create/lang/en_ud.json
a95bf9617620bb8b5fb82fe0e56e46bd336b278f assets/create/lang/en_us.json 9dc50a1957cac1967adba6a02f2708f5a82915b6 assets/create/lang/en_us.json
b0115c492677dab858488cef73f2fd8eb6917868 assets/create/lang/unfinished/de_de.json 60e216704dc824ae189af3927ae06e4c70e53478 assets/create/lang/unfinished/de_de.json
5165ae65abf3e3708a2546c4a90d1e73955358e0 assets/create/lang/unfinished/es_cl.json c2faed3f8cdc2616dc03d6c9cf6dafd9084c3e14 assets/create/lang/unfinished/es_cl.json
052b77a7f53c2bff190db58d0c5cdd0fd46b0aa4 assets/create/lang/unfinished/es_es.json f9632799fdf6278d0b0c0a2bff40df099745b076 assets/create/lang/unfinished/es_es.json
33485bc349947338aef69f05cf23df3254c30b02 assets/create/lang/unfinished/fr_fr.json 1d7af6b083679766bb542cf61fc6a835983a055c assets/create/lang/unfinished/fr_fr.json
f5effa80964b2a6afd5e4cc31de0658ab5f3ee4e assets/create/lang/unfinished/it_it.json 4942f180ef3758a1449108331943e0fa75e1a29b assets/create/lang/unfinished/it_it.json
14db37211e03d9e8322d1f692c17325be405b4ff assets/create/lang/unfinished/ja_jp.json 3249596dacdf06bc727676a5cc8acf85742054d0 assets/create/lang/unfinished/ja_jp.json
fc1d89b9f72db1030d4dc11c73a58d8e9f20fc21 assets/create/lang/unfinished/ko_kr.json ef7601ee26fdaf0356fe5400bc4f230ccb87eea8 assets/create/lang/unfinished/ko_kr.json
3acc03de9c0e411d1d935464e8cd66c3745ad2d2 assets/create/lang/unfinished/nl_nl.json 6d3914298d06db106d91299729f39cf5406f6768 assets/create/lang/unfinished/nl_nl.json
23eaf81707d5d67816a3f035b9eee5b48e601624 assets/create/lang/unfinished/pl_pl.json e21bd53612d2e82e9214b94fd6d2d110377089c1 assets/create/lang/unfinished/pl_pl.json
0a626a20150c4246ef5a956d7853424a95254222 assets/create/lang/unfinished/pt_br.json 56b4b8f892bf4442ac2f5140dc97273d1dfe2f27 assets/create/lang/unfinished/pt_br.json
4fd404306e795407325d17d9a68a3e6f5bbaf475 assets/create/lang/unfinished/pt_pt.json 63690bcfce50698d81562fe6cff1d0701a13e23d assets/create/lang/unfinished/pt_pt.json
74a3fec14772a0575debe0ec93f43d45cb556542 assets/create/lang/unfinished/ru_ru.json dfa8dc43216673feac87a2a49d08fd8cc9b1d9f2 assets/create/lang/unfinished/ru_ru.json
f9f56931ea5cae9fecf7bf5f4f323cdbe1101f75 assets/create/lang/unfinished/zh_cn.json dd18a29b4a76752ea033569ebbb07014e9aa3ab0 assets/create/lang/unfinished/zh_cn.json
1c5669a3109edbd448623a38e8b1c653f1a312c5 assets/create/lang/unfinished/zh_tw.json 0b67d5808e2665b5c0414a103b730508e17e01f6 assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -2135,7 +2135,7 @@ d080b1b25e5bc8baf5aee68691b08c7f12ece3b0 assets/create/models/item/windmill_bear
a80fb25a0b655e76be986b5b49fcb0f03461a1ab assets/create/models/item/zinc_nugget.json a80fb25a0b655e76be986b5b49fcb0f03461a1ab assets/create/models/item/zinc_nugget.json
b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json b1689617190c05ef34bd18456b0c7ae09bb3210f assets/create/models/item/zinc_ore.json
5049f72c327a88f175f6f9425909e098fc711100 assets/create/sounds.json 5049f72c327a88f175f6f9425909e098fc711100 assets/create/sounds.json
5d0cc4c0255dc241e61c173b31ddca70c88d08e4 data/create/advancements/aesthetics.json 0f1b4b980afba9bf2caf583b88e261bba8b10313 data/create/advancements/aesthetics.json
613e64b44bed959da899fdd54c1cacb227fb33f2 data/create/advancements/andesite_alloy.json 613e64b44bed959da899fdd54c1cacb227fb33f2 data/create/advancements/andesite_alloy.json
81885c6bfb85792c88aaa7c9b70f58832945d31f data/create/advancements/andesite_casing.json 81885c6bfb85792c88aaa7c9b70f58832945d31f data/create/advancements/andesite_casing.json
83c046bd200623933545c9e4326f782fb02c87fa data/create/advancements/arm_blaze_burner.json 83c046bd200623933545c9e4326f782fb02c87fa data/create/advancements/arm_blaze_burner.json

View file

@ -1398,6 +1398,8 @@
"create.train_assembly.not_connected_in_order": "Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "No structure attached to Bogey %1$s", "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.track_target.set": "Targeted track selected", "create.track_target.set": "Targeted track selected",
"create.track_target.success": "Successfully bound to targeted track", "create.track_target.success": "Successfully bound to targeted track",
@ -1410,10 +1412,14 @@
"create.train.relocate": "Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "Relocation aborted", "create.train.relocate.abort": "Relocation aborted",
"create.train.relocate.success": "Relocation successful", "create.train.relocate.success": "Relocation successful",
"create.train.relocate.valid": "Can be relocated here, Click to Confirm", "create.train.relocate.valid": "Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "Cannot relocate Train to this Track", "create.train.relocate.invalid": "Cannot relocate Train to this Track",
"create.train.relocate.too_far": "Cannot relocate Train this far away", "create.train.relocate.too_far": "Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay2": "This is a sample overlay",
"create.gui.config.overlay3": "Click or drag with your mouse", "create.gui.config.overlay3": "Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1422", "_": "Missing Localizations: 1427",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "Dies ist ein Beispiel Overlay", "create.gui.config.overlay2": "Dies ist ein Beispiel Overlay",
"create.gui.config.overlay3": "Klicke oder ziehe mit deiner Maus", "create.gui.config.overlay3": "Klicke oder ziehe mit deiner Maus",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 433", "_": "Missing Localizations: 438",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hola :)", "create.gui.config.overlay1": "Hola :)",
"create.gui.config.overlay2": "Este es un overlay de ejemplo", "create.gui.config.overlay2": "Este es un overlay de ejemplo",
"create.gui.config.overlay3": "Haz clic o arrastra con el mouse", "create.gui.config.overlay3": "Haz clic o arrastra con el mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 433", "_": "Missing Localizations: 438",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hola :)", "create.gui.config.overlay1": "Hola :)",
"create.gui.config.overlay2": "Esta es una muestra de la superposición", "create.gui.config.overlay2": "Esta es una muestra de la superposición",
"create.gui.config.overlay3": "Haga clic o arrastre con el ratón", "create.gui.config.overlay3": "Haga clic o arrastre con el ratón",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1684", "_": "Missing Localizations: 1689",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",
"create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1373", "_": "Missing Localizations: 1378",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Ciao :)", "create.gui.config.overlay1": "Ciao :)",
"create.gui.config.overlay2": "Questo overlay è di esempio", "create.gui.config.overlay2": "Questo overlay è di esempio",
"create.gui.config.overlay3": "Cliccalo o trascinalo col mouse", "create.gui.config.overlay3": "Cliccalo o trascinalo col mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 103", "_": "Missing Localizations: 108",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "やぁ(・∀・)", "create.gui.config.overlay1": "やぁ(・∀・)",
"create.gui.config.overlay2": "これはオーバーレイのサンプルです", "create.gui.config.overlay2": "これはオーバーレイのサンプルです",
"create.gui.config.overlay3": "マウスでクリックまたはドラッグしてください", "create.gui.config.overlay3": "マウスでクリックまたはドラッグしてください",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 105", "_": "Missing Localizations: 110",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay2": "This is a sample overlay",
"create.gui.config.overlay3": "Click or drag with your mouse", "create.gui.config.overlay3": "Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 2037", "_": "Missing Localizations: 2042",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",
"create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 472", "_": "Missing Localizations: 477",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Cześć :)", "create.gui.config.overlay1": "Cześć :)",
"create.gui.config.overlay2": "To jest przykładowa nakładka", "create.gui.config.overlay2": "To jest przykładowa nakładka",
"create.gui.config.overlay3": "Kliknij lub przeciągnij myszką", "create.gui.config.overlay3": "Kliknij lub przeciągnij myszką",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1656", "_": "Missing Localizations: 1661",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",
"create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 1656", "_": "Missing Localizations: 1661",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "UNLOCALIZED: Hi :)", "create.gui.config.overlay1": "UNLOCALIZED: Hi :)",
"create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay", "create.gui.config.overlay2": "UNLOCALIZED: This is a sample overlay",
"create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse", "create.gui.config.overlay3": "UNLOCALIZED: Click or drag with your mouse",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 477", "_": "Missing Localizations: 482",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Привет :)", "create.gui.config.overlay1": "Привет :)",
"create.gui.config.overlay2": "Это образец оверлея", "create.gui.config.overlay2": "Это образец оверлея",
"create.gui.config.overlay3": "Кликни и тащи с помощью мыши", "create.gui.config.overlay3": "Кликни и тащи с помощью мыши",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 103", "_": "Missing Localizations: 108",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "这是一个实例层", "create.gui.config.overlay2": "这是一个实例层",
"create.gui.config.overlay3": "点击拖拽你的鼠标", "create.gui.config.overlay3": "点击拖拽你的鼠标",

View file

@ -1,5 +1,5 @@
{ {
"_": "Missing Localizations: 491", "_": "Missing Localizations: 496",
"_": "->------------------------] Game Elements [------------------------<-", "_": "->------------------------] Game Elements [------------------------<-",
@ -1399,6 +1399,8 @@
"create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "UNLOCALIZED: Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "UNLOCALIZED: This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "UNLOCALIZED: No structure attached to Bogey %1$s", "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.track_target.set": "UNLOCALIZED: Targeted track selected", "create.track_target.set": "UNLOCALIZED: Targeted track selected",
"create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track", "create.track_target.success": "UNLOCALIZED: Successfully bound to targeted track",
@ -1411,10 +1413,14 @@
"create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort", "create.train.relocate": "UNLOCALIZED: Click a Track to Relocate %1$s to. Sneak-Click to abort",
"create.train.relocate.abort": "UNLOCALIZED: Relocation aborted", "create.train.relocate.abort": "UNLOCALIZED: Relocation aborted",
"create.train.relocate.success": "UNLOCALIZED: Relocation successful", "create.train.relocate.success": "UNLOCALIZED: Relocation successful",
"create.train.relocate.valid": "UNLOCALIZED: Can be relocated here, Click to Confirm", "create.train.relocate.valid": "UNLOCALIZED: Can relocate to here, Click to Confirm",
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track", "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to this Track",
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "嗨 :)", "create.gui.config.overlay1": "嗨 :)",
"create.gui.config.overlay2": "這是一個實例層", "create.gui.config.overlay2": "這是一個實例層",
"create.gui.config.overlay3": "點擊拖拽你的滑鼠", "create.gui.config.overlay3": "點擊拖拽你的滑鼠",

View file

@ -28,8 +28,8 @@
"trigger": "create:bracket_apply", "trigger": "create:bracket_apply",
"conditions": { "conditions": {
"accepted_entries": [ "accepted_entries": [
"create:large_cogwheel", "create:cogwheel",
"create:cogwheel" "create:large_cogwheel"
] ]
} }
}, },

View file

@ -11,6 +11,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Mov
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.DoorMovingInteraction; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.DoorMovingInteraction;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.LeverMovingInteraction; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.LeverMovingInteraction;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.TrapdoorMovingInteraction; import com.simibubi.create.content.contraptions.components.structureMovement.interaction.TrapdoorMovingInteraction;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsInteractionBehaviour;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
@ -49,6 +50,7 @@ public class AllInteractionBehaviours {
static void register() { static void register() {
addInteractionBehaviour(Blocks.LEVER.getRegistryName(), LeverMovingInteraction::new); addInteractionBehaviour(Blocks.LEVER.getRegistryName(), LeverMovingInteraction::new);
addInteractionBehaviour(AllBlocks.DEPLOYER.getId(), DeployerMovingInteraction::new); addInteractionBehaviour(AllBlocks.DEPLOYER.getId(), DeployerMovingInteraction::new);
addInteractionBehaviour(AllBlocks.CONTROLS.getId(), ControlsInteractionBehaviour::new);
// TODO: Scan registry for instanceof (-> modded door support) // TODO: Scan registry for instanceof (-> modded door support)

View file

@ -123,7 +123,7 @@ public class AllShapes {
STATION = shape(0, 0, 0, 16, 5, 16).add(2, 4, 0, 14, 16, 4) STATION = shape(0, 0, 0, 16, 5, 16).add(2, 4, 0, 14, 16, 4)
.forHorizontal(NORTH), .forHorizontal(NORTH),
CONTROLS = shape(0, 0, 4, 16, 8, 16).add(0, 0, 6, 16, 14, 16) CONTROLS = shape(0, 0, 4, 16, 4, 16).add(0, 0, 6, 16, 14, 16)
.forHorizontal(NORTH) .forHorizontal(NORTH)
; ;

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.contraptions.components.structureMovement; package com.simibubi.create.content.contraptions.components.structureMovement;
import java.io.IOException; import java.io.IOException;
import java.util.Collection;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -31,6 +32,7 @@ import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtIo;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.Packet; import net.minecraft.network.protocol.Packet;
import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.EntityDataSerializers;
@ -161,6 +163,20 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
.size(); .size();
} }
public Component getContraptionName() {
return getName();
}
public boolean startControlling(BlockPos controlsLocalPos) {
return false;
}
public boolean control(BlockPos controlsLocalPos, Collection<Integer> heldControls, Player player) {
return true;
}
public void stopControlling(BlockPos controlsLocalPos) {}
public boolean handlePlayerInteraction(Player player, BlockPos localPos, Direction side, public boolean handlePlayerInteraction(Player player, BlockPos localPos, Direction side,
InteractionHand interactionHand) { InteractionHand interactionHand) {
int indexOfSeat = contraption.getSeats() int indexOfSeat = contraption.getSeats()
@ -168,6 +184,8 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
if (indexOfSeat == -1) if (indexOfSeat == -1)
return contraption.interactors.containsKey(localPos) && contraption.interactors.get(localPos) return contraption.interactors.containsKey(localPos) && contraption.interactors.get(localPos)
.handlePlayerInteraction(player, interactionHand, localPos, this); .handlePlayerInteraction(player, interactionHand, localPos, this);
if (player.isPassenger())
return false;
// Eject potential existing passenger // Eject potential existing passenger
Entity toDismount = null; Entity toDismount = null;
@ -223,7 +241,9 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
return; return;
} }
collidingEntities.entrySet().removeIf(e -> e.getValue().incrementAndGet() > 3); collidingEntities.entrySet()
.removeIf(e -> e.getValue()
.incrementAndGet() > 3);
xo = getX(); xo = getX();
yo = getY(); yo = getY();

View file

@ -13,8 +13,8 @@ import com.simibubi.create.content.logistics.trains.entity.TrainRelocator;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.RaycastHelper; import com.simibubi.create.foundation.utility.RaycastHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult; import com.simibubi.create.foundation.utility.RaycastHelper.PredicateTraceResult;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.player.LocalPlayer;
@ -74,8 +74,6 @@ public class ContraptionHandlerClient {
if (player == null) if (player == null)
return; return;
if (player.isPassenger())
return;
if (mc.level == null) if (mc.level == null)
return; return;
if (!event.isUseItem()) if (!event.isUseItem())
@ -84,7 +82,7 @@ public class ContraptionHandlerClient {
Couple<Vec3> rayInputs = getRayInputs(player); Couple<Vec3> rayInputs = getRayInputs(player);
Vec3 origin = rayInputs.getFirst(); Vec3 origin = rayInputs.getFirst();
Vec3 target = rayInputs.getSecond(); Vec3 target = rayInputs.getSecond();
AABB aabb = new AABB(origin, target); AABB aabb = new AABB(origin, target).inflate(4);
List<AbstractContraptionEntity> intersectingContraptions = List<AbstractContraptionEntity> intersectingContraptions =
mc.level.getEntitiesOfClass(AbstractContraptionEntity.class, aabb); mc.level.getEntitiesOfClass(AbstractContraptionEntity.class, aabb);

View file

@ -0,0 +1,135 @@
package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.HashSet;
import java.util.Vector;
import org.lwjgl.glfw.GLFW;
import com.mojang.blaze3d.platform.InputConstants;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.foundation.utility.ControlsUtil;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
public class ControlsHandler {
public static Collection<Integer> currentlyPressed = new HashSet<>();
public static int PACKET_RATE = 5;
static int packetCooldown;
static WeakReference<AbstractContraptionEntity> entityRef = new WeakReference<>(null);
static BlockPos controlsPos;
public static void controllerClicked(AbstractContraptionEntity entity, BlockPos controllerLocalPos) {
AbstractContraptionEntity prevEntity = entityRef.get();
if (prevEntity != null) {
stopControlling();
if (prevEntity == entity)
return;
}
if (!entity.startControlling(controllerLocalPos))
return;
entityRef = new WeakReference<AbstractContraptionEntity>(entity);
controlsPos = controllerLocalPos;
Minecraft.getInstance().player.displayClientMessage(
Lang.translate("contraption.controls.start_controlling", entity.getContraptionName()), true);
}
public static void stopControlling() {
AbstractContraptionEntity abstractContraptionEntity = entityRef.get();
if (abstractContraptionEntity != null)
abstractContraptionEntity.stopControlling(controlsPos);
ControlsUtil.getControls()
.forEach(kb -> kb.setDown(ControlsUtil.isActuallyPressed(kb)));
packetCooldown = 0;
entityRef = new WeakReference<>(null);
controlsPos = null;
// if (!currentlyPressed.isEmpty())
// AllPackets.channel.sendToServer(new LinkedControllerInputPacket(currentlyPressed, false));
currentlyPressed.clear();
Minecraft.getInstance().player.displayClientMessage(Lang.translate("contraption.controls.stop_controlling"),
true);
}
public static void tick() {
AbstractContraptionEntity entity = entityRef.get();
if (entity == null)
return;
if (packetCooldown > 0)
packetCooldown--;
Minecraft mc = Minecraft.getInstance();
LocalPlayer player = mc.player;
if (player.isSpectator()) {
stopControlling();
return;
}
if (InputConstants.isKeyDown(mc.getWindow()
.getWindow(), GLFW.GLFW_KEY_ESCAPE)) {
stopControlling();
return;
}
if (!entity.toGlobalVector(VecHelper.getCenterOf(controlsPos), 1)
.closerThan(player.position(), 10)) {
stopControlling();
return;
}
Vector<KeyMapping> controls = ControlsUtil.getControls();
Collection<Integer> pressedKeys = new HashSet<>();
for (int i = 0; i < controls.size(); i++) {
if (ControlsUtil.isActuallyPressed(controls.get(i)))
pressedKeys.add(i);
}
Collection<Integer> newKeys = new HashSet<>(pressedKeys);
Collection<Integer> releasedKeys = currentlyPressed;
newKeys.removeAll(releasedKeys);
releasedKeys.removeAll(pressedKeys);
// Released Keys
if (!releasedKeys.isEmpty()) {
// AllPackets.channel.sendToServer(new LinkedControllerInputPacket(releasedKeys, false, lecternPos));
// AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .5f, true);
}
// Newly Pressed Keys
if (!newKeys.isEmpty()) {
if (newKeys.contains(Integer.valueOf(5))) {
stopControlling();
return;
}
// AllPackets.channel.sendToServer(new LinkedControllerInputPacket(newKeys, true, lecternPos));
// packetCooldown = PACKET_RATE;
// AllSoundEvents.CONTROLLER_CLICK.playAt(player.level, player.blockPosition(), 1f, .75f, true);
}
// Keepalive Pressed Keys
if (packetCooldown == 0) {
// if (!pressedKeys.isEmpty()) {
// AllPackets.channel.sendToServer(new LinkedControllerInputPacket(pressedKeys, true, lecternPos));
// packetCooldown = PACKET_RATE;
// }
}
// TODO do this server side
if (!entity.control(controlsPos, pressedKeys, player)) {
stopControlling();
return;
}
currentlyPressed = pressedKeys;
controls.forEach(kb -> kb.setDown(false));
}
}

View file

@ -0,0 +1,20 @@
package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
public class ControlsInteractionBehaviour extends MovingInteractionBehaviour {
@Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) {
if (player.level.isClientSide)
ControlsHandler.controllerClicked(contraptionEntity, localPos);
return true;
}
}

View file

@ -1,9 +1,16 @@
package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls;
import java.util.Collection;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour; import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices;
import com.simibubi.create.content.logistics.trains.entity.Carriage;
import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
@ -11,11 +18,38 @@ import net.minecraftforge.api.distmarker.OnlyIn;
public class ControlsMovementBehaviour extends MovementBehaviour { public class ControlsMovementBehaviour extends MovementBehaviour {
// TODO: this is specific to Carriage Contraptions - need to move this behaviour
// there
LerpedFloat steering = LerpedFloat.linear();
LerpedFloat speed = LerpedFloat.linear();
LerpedFloat equipAnimation = LerpedFloat.linear();
@Override
public void tick(MovementContext context) {
steering.tickChaser();
speed.tickChaser();
equipAnimation.tickChaser();
super.tick(context);
}
@Override @Override
@OnlyIn(Dist.CLIENT) @OnlyIn(Dist.CLIENT)
public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld, public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld,
ContraptionMatrices matrices, MultiBufferSource buffer) { ContraptionMatrices matrices, MultiBufferSource buffer) {
ControlsRenderer.render(context, renderWorld, matrices, buffer); if (ControlsHandler.entityRef.get() == context.contraption.entity && ControlsHandler.controlsPos != null
&& ControlsHandler.controlsPos.equals(context.localPos)) {
Collection<Integer> pressed = ControlsHandler.currentlyPressed;
equipAnimation.chase(1, .2f, Chaser.EXP);
steering.chase((pressed.contains(3) ? 1 : 0) + (pressed.contains(2) ? -1 : 0), 0.2f, Chaser.EXP);
if (context.contraption.entity instanceof CarriageContraptionEntity car) {
Carriage carriage = car.getCarriage();
speed.chase(Math.abs(carriage.train.speed), 0.2f, Chaser.EXP);
}
} else
equipAnimation.chase(0, .2f, Chaser.EXP);
float pt = AnimationTickHolder.getPartialTicks(context.world);
ControlsRenderer.render(context, renderWorld, matrices, buffer, equipAnimation.getValue(pt), speed.getValue(pt),
steering.getValue(pt));
} }
} }

View file

@ -1,8 +1,9 @@
package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls; package com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld; import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlockPartials; import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext; import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
@ -16,38 +17,43 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class ControlsRenderer { public class ControlsRenderer {
public static void render(MovementContext context, VirtualRenderWorld renderWorld, ContraptionMatrices matrices, public static void render(MovementContext context, VirtualRenderWorld renderWorld, ContraptionMatrices matrices,
MultiBufferSource buffer) { MultiBufferSource buffer, float equipAnimation, float firstLever, float secondLever) {
BlockState state = context.state; BlockState state = context.state;
Direction facing = state.getValue(ControlsBlock.FACING); Direction facing = state.getValue(ControlsBlock.FACING);
SuperByteBuffer cover = CachedBufferer.partial(AllBlockPartials.TRAIN_CONTROLS_COVER, state); SuperByteBuffer cover = CachedBufferer.partial(AllBlockPartials.TRAIN_CONTROLS_COVER, state);
float hAngle = 180 + AngleHelper.horizontalAngle(facing); float hAngle = 180 + AngleHelper.horizontalAngle(facing);
cover.transform(matrices.getModel()) PoseStack ms = matrices.getModel();
cover.transform(ms)
.centre() .centre()
.rotateY(hAngle) .rotateY(hAngle)
.unCentre() .unCentre()
.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld))
.renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid()));
double yOffset = Mth.lerp(equipAnimation * equipAnimation, -0.15f, 0.05f);
for (boolean first : Iterate.trueAndFalse) { for (boolean first : Iterate.trueAndFalse) {
AbstractContraptionEntity entity = context.contraption.entity; float vAngle = (float) Mth.clamp(first ? firstLever * 70 - 25 : secondLever * 15, -45, 45);
double motion = entity.position()
.distanceTo(new Vec3(entity.xo, entity.yo, entity.zo));
float vAngle = (float) Mth.clamp(first ? motion * 45 : 0, -45, 45);
SuperByteBuffer lever = CachedBufferer.partial(AllBlockPartials.TRAIN_CONTROLS_LEVER, state); SuperByteBuffer lever = CachedBufferer.partial(AllBlockPartials.TRAIN_CONTROLS_LEVER, state);
lever.transform(matrices.getModel()) ms.pushPose();
.centre() new MatrixTransformStack(ms).centre()
.rotateY(hAngle) .rotateY(hAngle)
.rotateX(vAngle) .translate(0, 0, 4 / 16f)
.rotateX(vAngle - 45)
.translate(0, yOffset, 0)
.rotateX(45)
.unCentre() .unCentre()
.translate(first ? 0 : 6 / 16f, 0, 0) .translate(0, -2 / 16f, -3 / 16f)
.translate(first ? 0 : 6 / 16f, 0, 0);
lever.transform(ms)
.light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld)) .light(matrices.getWorld(), ContraptionRenderDispatcher.getContraptionWorldLight(context, renderWorld))
.renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid())); .renderInto(matrices.getViewProjection(), buffer.getBuffer(RenderType.solid()));
ms.popPose();
} }
} }

View file

@ -18,12 +18,12 @@ import com.simibubi.create.foundation.item.TooltipHelper;
import com.simibubi.create.foundation.networking.AllPackets; import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.linked.LinkBehaviour;
import com.simibubi.create.foundation.utility.ControlsUtil;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
import net.minecraft.client.KeyMapping; import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.player.LocalPlayer; import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@ -43,24 +43,8 @@ public class LinkedControllerClientHandler {
public static Collection<Integer> currentlyPressed = new HashSet<>(); public static Collection<Integer> currentlyPressed = new HashSet<>();
private static BlockPos lecternPos; private static BlockPos lecternPos;
private static BlockPos selectedLocation = BlockPos.ZERO; private static BlockPos selectedLocation = BlockPos.ZERO;
private static Vector<KeyMapping> controls;
private static int packetCooldown; private static int packetCooldown;
public static Vector<KeyMapping> getControls() {
if (controls == null) {
Options gameSettings = Minecraft.getInstance().options;
controls = new Vector<>(6);
controls.add(gameSettings.keyUp);
controls.add(gameSettings.keyDown);
controls.add(gameSettings.keyLeft);
controls.add(gameSettings.keyRight);
controls.add(gameSettings.keyJump);
controls.add(gameSettings.keyShift);
}
return controls;
}
public static void toggleBindMode(BlockPos location) { public static void toggleBindMode(BlockPos location) {
if (MODE == Mode.IDLE) { if (MODE == Mode.IDLE) {
MODE = Mode.BIND; MODE = Mode.BIND;
@ -100,7 +84,7 @@ public class LinkedControllerClientHandler {
} }
protected static void onReset() { protected static void onReset() {
getControls().forEach(kb -> kb.setDown(isActuallyPressed(kb))); ControlsUtil.getControls().forEach(kb -> kb.setDown(ControlsUtil.isActuallyPressed(kb)));
packetCooldown = 0; packetCooldown = 0;
selectedLocation = BlockPos.ZERO; selectedLocation = BlockPos.ZERO;
@ -115,14 +99,6 @@ public class LinkedControllerClientHandler {
LinkedControllerItemRenderer.resetButtons(); LinkedControllerItemRenderer.resetButtons();
} }
protected static boolean isActuallyPressed(KeyMapping kb) {
return InputConstants.isKeyDown(Minecraft.getInstance()
.getWindow()
.getWindow(),
kb.getKey()
.getValue());
}
public static void tick() { public static void tick() {
LinkedControllerItemRenderer.tick(); LinkedControllerItemRenderer.tick();
@ -169,10 +145,10 @@ public class LinkedControllerClientHandler {
return; return;
} }
Vector<KeyMapping> controls = getControls(); Vector<KeyMapping> controls = ControlsUtil.getControls();
Collection<Integer> pressedKeys = new HashSet<>(); Collection<Integer> pressedKeys = new HashSet<>();
for (int i = 0; i < controls.size(); i++) { for (int i = 0; i < controls.size(); i++) {
if (isActuallyPressed(controls.get(i))) if (ControlsUtil.isActuallyPressed(controls.get(i)))
pressedKeys.add(i); pressedKeys.add(i);
} }
@ -240,7 +216,7 @@ public class LinkedControllerClientHandler {
tooltipScreen.init(mc, width1, height1); tooltipScreen.init(mc, width1, height1);
Object[] keys = new Object[6]; Object[] keys = new Object[6];
Vector<KeyMapping> controls = getControls(); Vector<KeyMapping> controls = ControlsUtil.getControls();
for (int i = 0; i < controls.size(); i++) { for (int i = 0; i < controls.size(); i++) {
KeyMapping keyBinding = controls.get(i); KeyMapping keyBinding = controls.get(i);
keys[i] = keyBinding.getTranslatedKeyMessage() keys[i] = keyBinding.getTranslatedKeyMessage()

View file

@ -13,6 +13,7 @@ import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen; import com.simibubi.create.foundation.gui.container.AbstractSimiContainerScreen;
import com.simibubi.create.foundation.gui.element.GuiGameElement; import com.simibubi.create.foundation.gui.element.GuiGameElement;
import com.simibubi.create.foundation.gui.widget.IconButton; import com.simibubi.create.foundation.gui.widget.IconButton;
import com.simibubi.create.foundation.utility.ControlsUtil;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting; import net.minecraft.ChatFormatting;
@ -112,7 +113,7 @@ public class LinkedControllerScreen extends AbstractSimiContainerScreen<LinkedCo
return list; return list;
list.add(Lang list.add(Lang
.createTranslationTextComponent("linked_controller.frequency_slot_" + ((slot % 2) + 1), .createTranslationTextComponent("linked_controller.frequency_slot_" + ((slot % 2) + 1),
LinkedControllerClientHandler.getControls() ControlsUtil.getControls()
.get(slot / 2) .get(slot / 2)
.getTranslatedKeyMessage() .getTranslatedKeyMessage()
.getString()) .getString())

View file

@ -59,7 +59,8 @@ public class Carriage {
} }
public double travel(Level level, TrackGraph graph, double distance, public double travel(Level level, TrackGraph graph, double distance,
@Nullable Function<TravellingPoint, ITrackSelector> control) { Function<TravellingPoint, ITrackSelector> forwardControl,
Function<TravellingPoint, ITrackSelector> backwardControl) {
Vec3 leadingAnchor = leadingBogey().anchorPosition; Vec3 leadingAnchor = leadingBogey().anchorPosition;
Vec3 trailingAnchor = trailingBogey().anchorPosition; Vec3 trailingAnchor = trailingBogey().anchorPosition;
boolean onTwoBogeys = isOnTwoBogeys(); boolean onTwoBogeys = isOnTwoBogeys();
@ -86,14 +87,20 @@ public class Carriage {
bogey.points.forEachWithContext((point, first) -> { bogey.points.forEachWithContext((point, first) -> {
TravellingPoint prevPoint = previous.getValue(); TravellingPoint prevPoint = previous.getValue();
ITrackSelector trackSelector = TravellingPoint nextPoint = first ? bogey.points.getSecond()
prevPoint == null ? control == null ? point.random() : control.apply(point) : firstBogey && onTwoBogeys ? bogeys.getSecond().points.getFirst() : null;
: point.follow(prevPoint);
double correction = bogeyStress * (first ? leadingPointModifier : trailingPointModifier); double correction = bogeyStress * (first ? leadingPointModifier : trailingPointModifier);
double toMove = distanceMoved.getValue(); double toMove = distanceMoved.getValue();
double moved = point.travel(graph, toMove, trackSelector);
point.travel(graph, correction + bogeyCorrection, trackSelector); ITrackSelector frontTrackSelector =
prevPoint == null ? forwardControl.apply(point) : point.follow(prevPoint);
ITrackSelector backTrackSelector =
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);
blocked |= point.blocked; blocked |= point.blocked;
distanceMoved.setValue(moved); distanceMoved.setValue(moved);
@ -227,7 +234,7 @@ public class Carriage {
if (carriage.train.derailed) if (carriage.train.derailed)
yRot += derailAngle; yRot += derailAngle;
wheelAngle.setValue((wheelAngle.getValue() - angleDiff) % 360); wheelAngle.setValue((wheelAngle.getValue() - angleDiff * Math.signum(carriage.train.speed)) % 360);
pitch.setValue(xRot); pitch.setValue(xRot);
yaw.setValue(-yRot); yaw.setValue(-yRot);
} }

View file

@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.Con
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionLighter;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType; 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.NonStationaryLighter;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
import com.simibubi.create.content.logistics.trains.IBogeyBlock; import com.simibubi.create.content.logistics.trains.IBogeyBlock;
import com.simibubi.create.foundation.utility.Lang; import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.NBTHelper; import com.simibubi.create.foundation.utility.NBTHelper;
@ -24,7 +25,10 @@ public class CarriageContraption extends Contraption {
private Direction assemblyDirection; private Direction assemblyDirection;
private boolean controls; private boolean forwardControls;
private boolean backwardControls;
private boolean sidewaysControls;
private int bogeys; private int bogeys;
private BlockPos secondBogeyPos; private BlockPos secondBogeyPos;
@ -48,6 +52,8 @@ public class CarriageContraption extends Contraption {
return false; return false;
if (bogeys > 2) if (bogeys > 2)
throw new AssemblyException(Lang.translate("train_assembly.too_many_bogeys", bogeys)); throw new AssemblyException(Lang.translate("train_assembly.too_many_bogeys", bogeys));
if (sidewaysControls)
throw new AssemblyException(Lang.translate("train_assembly.sideways_controls"));
return true; return true;
} }
@ -67,8 +73,15 @@ public class CarriageContraption extends Contraption {
return Pair.of(new StructureBlockInfo(pos, blockState, null), null); return Pair.of(new StructureBlockInfo(pos, blockState, null), null);
} }
if (AllBlocks.CONTROLS.has(blockState)) if (AllBlocks.CONTROLS.has(blockState)) {
controls = true; Direction facing = blockState.getValue(ControlsBlock.FACING);
if (facing.getAxis() != assemblyDirection.getAxis())
sidewaysControls = true;
else if (facing == assemblyDirection)
forwardControls = true;
else
backwardControls = true;
}
return super.capture(world, pos); return super.capture(world, pos);
} }
@ -79,7 +92,8 @@ public class CarriageContraption extends Contraption {
NBTHelper.writeEnum(tag, "AssemblyDirection", getAssemblyDirection()); NBTHelper.writeEnum(tag, "AssemblyDirection", getAssemblyDirection());
if (spawnPacket) if (spawnPacket)
tag.putInt("CarriageId", carriage.id); tag.putInt("CarriageId", carriage.id);
tag.putBoolean("Controls", hasControls()); tag.putBoolean("FrontControls", forwardControls);
tag.putBoolean("BackControls", backwardControls);
return tag; return tag;
} }
@ -88,7 +102,8 @@ public class CarriageContraption extends Contraption {
assemblyDirection = NBTHelper.readEnum(nbt, "AssemblyDirection", Direction.class); assemblyDirection = NBTHelper.readEnum(nbt, "AssemblyDirection", Direction.class);
if (spawnData) if (spawnData)
temporaryCarriageIdHolder = nbt.getInt("CarriageId"); temporaryCarriageIdHolder = nbt.getInt("CarriageId");
controls = nbt.getBoolean("Controls"); forwardControls = nbt.getBoolean("FrontControls");
backwardControls = nbt.getBoolean("BackControls");
super.readNBT(world, nbt, spawnData); super.readNBT(world, nbt, spawnData);
} }
@ -120,8 +135,12 @@ public class CarriageContraption extends Contraption {
return carriage; return carriage;
} }
public boolean hasControls() { public boolean hasForwardControls() {
return controls; return forwardControls;
}
public boolean hasBackwardControls() {
return backwardControls;
} }
public BlockPos getSecondBogeyPos() { public BlockPos getSecondBogeyPos() {

View file

@ -1,14 +1,34 @@
package com.simibubi.create.content.logistics.trains.entity; package com.simibubi.create.content.logistics.trains.entity;
import java.util.Collection;
import com.google.common.base.Strings;
import com.simibubi.create.AllEntityTypes; import com.simibubi.create.AllEntityTypes;
import com.simibubi.create.Create; import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity; import com.simibubi.create.content.contraptions.components.structureMovement.OrientedContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
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.Lang;
import com.simibubi.create.foundation.utility.VecHelper; import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.ChatFormatting;
import net.minecraft.client.Minecraft;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.particles.ParticleTypes; 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.EntityType; import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
public class CarriageContraptionEntity extends OrientedContraptionEntity { public class CarriageContraptionEntity extends OrientedContraptionEntity {
@ -30,16 +50,158 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
return entity; return entity;
} }
@Override
public Component getContraptionName() {
Carriage carriage = getCarriage();
if (carriage != null)
return carriage.train.name;
Component contraptionName = super.getContraptionName();
return contraptionName;
}
@Override
public boolean startControlling(BlockPos controlsLocalPos) {
Carriage carriage = getCarriage();
if (carriage == null)
return false;
if (carriage.train.derailed)
return false;
Train train = carriage.train;
if (train.runtime.getSchedule() != null && !train.runtime.paused)
train.status.manualControls();
train.navigation.cancelNavigation();
train.runtime.paused = true;
return true;
}
double navDistanceTotal = 0;
@Override
public boolean control(BlockPos controlsLocalPos, Collection<Integer> heldControls, Player player) {
Carriage carriage = getCarriage();
if (carriage == null)
return false;
if (carriage.train.derailed)
return false;
StructureBlockInfo info = contraption.getBlocks()
.get(controlsLocalPos);
Direction initialOrientation = getInitialOrientation().getCounterClockWise();
boolean inverted = false;
if (info != null && info.state.hasProperty(ControlsBlock.FACING))
inverted = !info.state.getValue(ControlsBlock.FACING)
.equals(initialOrientation);
int targetSpeed = 0;
if (heldControls.contains(0))
targetSpeed++;
if (heldControls.contains(1))
targetSpeed--;
int targetSteer = 0;
if (heldControls.contains(2))
targetSteer++;
if (heldControls.contains(3))
targetSteer--;
if (inverted) {
targetSpeed *= -1;
// targetSteer *= -1;
}
boolean spaceDown = heldControls.contains(4);
GlobalStation currentStation = carriage.train.getCurrentStation();
if (currentStation != null && spaceDown) {
player.displayClientMessage(new TextComponent("<i> Arrived at ").withStyle(ChatFormatting.GREEN)
.append(new TextComponent(currentStation.name).withStyle(ChatFormatting.WHITE)), true);
return true;
}
if (currentStation != null && targetSpeed != 0) {
stationMessage = false;
player.displayClientMessage(new TextComponent("<i> Departing from ").withStyle(ChatFormatting.YELLOW)
.append(new TextComponent(currentStation.name).withStyle(ChatFormatting.WHITE)), true);
}
if (currentStation == null && targetSpeed >= 0) {
Navigation nav = carriage.train.navigation;
if (nav.destination != null) {
if (!spaceDown)
nav.cancelNavigation();
if (spaceDown) {
double f = (nav.distanceToDestination / navDistanceTotal);
int progress = (int) (Mth.clamp(1 - ((1 - f) * (1 - f)), 0, 1) * 30);
boolean arrived = progress == 0;
TextComponent whiteComponent =
new TextComponent(Strings.repeat("|", progress) + (arrived ? " ->" : " <-"));
TextComponent greenComponent =
new TextComponent((arrived ? "<- " : "-> ") + Strings.repeat("|", 30 - progress));
int mixedColor = Color.mixColors(0xff_91EA44, 0xff_FFC244, progress / 30f);
int targetColor = arrived ? 0xff_91EA44 : 0xff_ffffff;
player.displayClientMessage(greenComponent.withStyle(st -> st.withColor(mixedColor))
.append(whiteComponent.withStyle(st -> st.withColor(targetColor))), true);
return true;
}
}
GlobalStation lookAhead = nav.findNearestApproachable();
if (lookAhead != null) {
if (spaceDown) {
nav.startNavigation(lookAhead, false);
navDistanceTotal = nav.distanceToDestination;
return true;
}
if (level.isClientSide)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> () -> displayApproachStationMessage(lookAhead));
} else {
if (level.isClientSide)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> this::cleanUpApproachStationMessage);
}
}
carriage.train.manualSteer =
targetSteer < 0 ? SteerDirection.RIGHT : targetSteer > 0 ? SteerDirection.LEFT : SteerDirection.NONE;
carriage.train.targetSpeed = Train.topSpeed * targetSpeed;
if (inverted ^ targetSpeed < 0)
carriage.train.targetSpeed /= 8;
boolean counteringAcceleration = Math.abs(Math.signum(targetSpeed) - Math.signum(carriage.train.speed)) > 1.5f;
carriage.train.manualTick = true;
carriage.train.approachTargetSpeed(counteringAcceleration ? 2 : 1);
return true;
}
boolean stationMessage = false;
@OnlyIn(Dist.CLIENT)
private void displayApproachStationMessage(GlobalStation station) {
Minecraft instance = Minecraft.getInstance();
instance.player.displayClientMessage(Lang.translate("contraption.controls.approach_station",
instance.options.keyJump.getTranslatedKeyMessage(), station.name), true);
stationMessage = true;
}
@OnlyIn(Dist.CLIENT)
private void cleanUpApproachStationMessage() {
if (!stationMessage)
return;
Minecraft instance = Minecraft.getInstance();
instance.player.displayClientMessage(new TextComponent(""), true);
stationMessage = false;
}
@Override @Override
protected void tickContraption() { protected void tickContraption() {
if (!(contraption instanceof CarriageContraption)) if (!(contraption instanceof CarriageContraption))
return; return;
int id = ((CarriageContraption) contraption).temporaryCarriageIdHolder; Carriage carriage = getCarriage();
Carriage carriage = Create.RAILWAYS.carriageById.get(id); // TODO: thread breach
if (carriage == null) { if (carriage == null) {
discard(); discard();
return; return;
} }
tickActors();
if (!level.isClientSide) if (!level.isClientSide)
return; return;
@ -61,6 +223,12 @@ public class CarriageContraptionEntity extends OrientedContraptionEntity {
} }
public Carriage getCarriage() {
int id = ((CarriageContraption) contraption).temporaryCarriageIdHolder;
Carriage carriage = Create.RAILWAYS.carriageById.get(id); // TODO: thread breach
return carriage;
}
Vec3 derailParticleOffset = VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, 1.5f) Vec3 derailParticleOffset = VecHelper.offsetRandomly(Vec3.ZERO, Create.RANDOM, 1.5f)
.multiply(1, .25f, 1); .multiply(1, .25f, 1);

View file

@ -2,7 +2,6 @@ package com.simibubi.create.content.logistics.trains.entity;
import com.jozufozu.flywheel.util.transform.MatrixTransformStack; import com.jozufozu.flywheel.util.transform.MatrixTransformStack;
import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntityRenderer; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntityRenderer;
import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.MultiBufferSource;
@ -29,8 +28,7 @@ public class CarriageContraptionEntityRenderer extends ContraptionEntityRenderer
MultiBufferSource buffers, int overlay) { MultiBufferSource buffers, int overlay) {
super.render(entity, yaw, partialTicks, ms, buffers, overlay); super.render(entity, yaw, partialTicks, ms, buffers, overlay);
int id = ((CarriageContraption) entity.getContraption()).temporaryCarriageIdHolder; Carriage carriage = entity.getCarriage();
Carriage carriage = Create.RAILWAYS.carriageById.get(id);
if (carriage == null) if (carriage == null)
return; return;

View file

@ -8,6 +8,9 @@ import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.PriorityQueue; import java.util.PriorityQueue;
import java.util.Set; import java.util.Set;
import java.util.function.BiPredicate;
import org.apache.commons.lang3.mutable.MutableObject;
import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackEdge;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
@ -18,7 +21,6 @@ import com.simibubi.create.content.logistics.trains.management.GlobalStation;
import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Pair; import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.util.Mth;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -64,15 +66,7 @@ public class Navigation {
double brakingDistance = (train.speed * train.speed) / (2 * Train.acceleration); double brakingDistance = (train.speed * train.speed) / (2 * Train.acceleration);
train.targetSpeed = distanceToDestination > brakingDistance ? Train.topSpeed : 0; train.targetSpeed = distanceToDestination > brakingDistance ? Train.topSpeed : 0;
train.approachTargetSpeed(1);
if (Mth.equal(train.targetSpeed, train.speed))
return;
if (train.speed < train.targetSpeed)
train.speed = Math.min(train.speed + Train.acceleration, train.targetSpeed);
else if (train.speed > train.targetSpeed)
train.speed = Math.max(train.speed - Train.acceleration, train.targetSpeed);
} }
public boolean isActive() { public boolean isActive() {
@ -80,17 +74,20 @@ public class Navigation {
} }
public ITrackSelector control(TravellingPoint mp) { public ITrackSelector control(TravellingPoint mp) {
return (graph, list) -> { if (destination == null)
return mp.steer(train.manualSteer, new Vec3(0, 1, 0));
return (graph, pair) -> {
if (!currentPath.isEmpty()) { if (!currentPath.isEmpty()) {
TrackEdge target = currentPath.get(0); TrackEdge target = currentPath.get(0);
for (Entry<TrackNode, TrackEdge> entry : list) { for (Entry<TrackNode, TrackEdge> entry : pair.getSecond()) {
if (entry.getValue() == target) { if (entry.getValue() == target) {
currentPath.remove(0); currentPath.remove(0);
return entry; return entry;
} }
} }
} }
return list.get(0); return pair.getSecond()
.get(0);
}; };
} }
@ -122,7 +119,7 @@ public class Navigation {
if (this.destination == destination) if (this.destination == destination)
return 0; return 0;
train.leave(); train.leaveStation();
this.destination = destination; this.destination = destination;
return distanceToDestination; return distanceToDestination;
} }
@ -130,19 +127,103 @@ public class Navigation {
private Pair<Double, List<TrackEdge>> findPathTo(GlobalStation destination) { private Pair<Double, List<TrackEdge>> findPathTo(GlobalStation destination) {
TrackGraph graph = train.graph; TrackGraph graph = train.graph;
List<TrackEdge> path = new ArrayList<>(); List<TrackEdge> path = new ArrayList<>();
double distanceToDestination = 0;
if (graph == null) if (graph == null)
return Pair.of(-1d, path); return Pair.of(-1d, path);
Couple<TrackNodeLocation> target = destination.edgeLocation; Couple<TrackNodeLocation> target = destination.edgeLocation;
PriorityQueue<Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> frontier = TravellingPoint leadingPoint = train.carriages.get(0)
new PriorityQueue<>((p1, p2) -> Double.compare(p1.getFirst(), p2.getFirst())); .getLeadingPoint();
TrackEdge initialEdge = leadingPoint.edge;
MutableObject<Pair<Double, List<TrackEdge>>> result = new MutableObject<>(Pair.of(-1d, path));
search((reachedVia, poll) -> {
double distance = poll.getFirst();
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
TrackEdge edge = currentEntry.getSecond();
TrackNode node1 = currentEntry.getFirst()
.getFirst();
TrackNode node2 = currentEntry.getFirst()
.getSecond();
TrackNodeLocation loc1 = node1.getLocation();
TrackNodeLocation loc2 = node2.getLocation();
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
return false;
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
TrackEdge toReach = edge;
while (backTrack != null && toReach != initialEdge) {
if (backTrack.getFirst())
path.add(0, toReach);
toReach = backTrack.getSecond();
backTrack = reachedVia.get(backTrack.getSecond());
}
double distanceToDestination = distance;
double position = edge.getLength(node1, node2) - destination.position;
distanceToDestination -= position;
result.setValue(Pair.of(distanceToDestination, path));
return true;
}, Double.MAX_VALUE);
return result.getValue();
}
public GlobalStation findNearestApproachable() {
TrackGraph graph = train.graph;
if (graph == null)
return null;
MutableObject<GlobalStation> result = new MutableObject<>(null);
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) -> {
double distance = poll.getFirst();
if (distance < minDistance)
return false;
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
TrackEdge edge = currentEntry.getSecond();
TrackNode node1 = currentEntry.getFirst()
.getFirst();
TrackNode node2 = currentEntry.getFirst()
.getSecond();
for (GlobalStation globalStation : graph.getStations()) {
Couple<TrackNodeLocation> target = globalStation.edgeLocation;
TrackNodeLocation loc1 = node1.getLocation();
TrackNodeLocation loc2 = node2.getLocation();
if (!loc1.equals(target.getFirst()) || !loc2.equals(target.getSecond()))
continue;
double position = edge.getLength(node1, node2) - globalStation.position;
if (distance - position < minDistance)
continue;
result.setValue(globalStation);
return true;
}
return false;
}, maxDistance);
return result.getValue();
}
public void search(
BiPredicate<Map<TrackEdge, Pair<Boolean, TrackEdge>>, Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> condition,
double maxDistance) {
TrackGraph graph = train.graph;
if (graph == null)
return;
TravellingPoint leadingPoint = train.carriages.get(0) TravellingPoint leadingPoint = train.carriages.get(0)
.getLeadingPoint(); .getLeadingPoint();
Set<TrackEdge> visited = new HashSet<>(); Set<TrackEdge> visited = new HashSet<>();
Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia = new IdentityHashMap<>(); Map<TrackEdge, Pair<Boolean, TrackEdge>> reachedVia = new IdentityHashMap<>();
PriorityQueue<Pair<Double, Pair<Couple<TrackNode>, TrackEdge>>> frontier =
new PriorityQueue<>((p1, p2) -> Double.compare(p1.getFirst(), p2.getFirst()));
TrackEdge initialEdge = leadingPoint.edge; TrackEdge initialEdge = leadingPoint.edge;
TrackNode initialNode1 = leadingPoint.node1; TrackNode initialNode1 = leadingPoint.node1;
@ -153,39 +234,19 @@ public class Navigation {
while (!frontier.isEmpty()) { while (!frontier.isEmpty()) {
Pair<Double, Pair<Couple<TrackNode>, TrackEdge>> poll = frontier.poll(); Pair<Double, Pair<Couple<TrackNode>, TrackEdge>> poll = frontier.poll();
double distance = poll.getFirst(); double distance = poll.getFirst();
if (distance > maxDistance)
continue;
Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond(); Pair<Couple<TrackNode>, TrackEdge> currentEntry = poll.getSecond();
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
TrackEdge edge = currentEntry.getSecond(); TrackEdge edge = currentEntry.getSecond();
TrackNode node1 = currentEntry.getFirst() TrackNode node1 = currentEntry.getFirst()
.getFirst(); .getFirst();
TrackNode node2 = currentEntry.getFirst() TrackNode node2 = currentEntry.getFirst()
.getSecond(); .getSecond();
if (condition.test(reachedVia, poll))
return;
TrackNodeLocation loc1 = node1.getLocation(); List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
TrackNodeLocation loc2 = node2.getLocation();
boolean enteringBackward = loc2.equals(target.getFirst()) && loc1.equals(target.getSecond());
boolean enteringForward = loc1.equals(target.getFirst()) && loc2.equals(target.getSecond());
if (enteringForward || train.doubleEnded && enteringBackward) {
Pair<Boolean, TrackEdge> backTrack = reachedVia.get(edge);
TrackEdge toReach = edge;
while (backTrack != null && toReach != initialEdge) {
if (backTrack.getFirst())
path.add(0, toReach);
toReach = backTrack.getSecond();
backTrack = reachedVia.get(backTrack.getSecond());
}
distanceToDestination = distance;
double position = destination.position;
if (enteringForward)
position = edge.getLength(node1, node2) - position;
else
distanceToDestination += train.getTotalLength() + 2;
distanceToDestination -= position;
return Pair.of(distanceToDestination, path);
}
for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node2) for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node2)
.entrySet()) { .entrySet()) {
TrackNode newNode = entry.getKey(); TrackNode newNode = entry.getKey();
@ -210,8 +271,6 @@ public class Navigation {
Pair.of(Couple.create(node2, newNode), newEdge))); Pair.of(Couple.create(node2, newNode), newEdge)));
} }
} }
return Pair.of(-1d, path);
} }
} }

View file

@ -21,6 +21,7 @@ import com.simibubi.create.CreateClient;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNode;
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
import com.simibubi.create.content.logistics.trains.management.GlobalStation; import com.simibubi.create.content.logistics.trains.management.GlobalStation;
import com.simibubi.create.content.logistics.trains.management.GraphLocation; import com.simibubi.create.content.logistics.trains.management.GraphLocation;
import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime; import com.simibubi.create.content.logistics.trains.management.ScheduleRuntime;
@ -56,6 +57,9 @@ public class Train {
public Component name; public Component name;
public TrainStatus status; public TrainStatus status;
public SteerDirection manualSteer;
public boolean manualTick;
public UUID currentStation; public UUID currentStation;
public boolean heldForAssembly; public boolean heldForAssembly;
@ -85,12 +89,14 @@ public class Train {
Create.RAILWAYS.carriageById.put(c.id, c); Create.RAILWAYS.carriageById.put(c.id, c);
}); });
doubleEnded = carriages.size() > 1 && carriages.get(carriages.size() - 1).contraption.hasControls(); doubleEnded = carriages.stream()
.anyMatch(c -> c.contraption.hasBackwardControls());
navigation = new Navigation(this, graph); navigation = new Navigation(this, graph);
runtime = new ScheduleRuntime(this); runtime = new ScheduleRuntime(this);
heldForAssembly = true; heldForAssembly = true;
migratingPoints = new ArrayList<>(); migratingPoints = new ArrayList<>();
currentStation = null; currentStation = null;
manualSteer = SteerDirection.NONE;
} }
public void tick(Level level) { public void tick(Level level) {
@ -105,11 +111,13 @@ public class Train {
runtime.tick(level); runtime.tick(level);
navigation.tick(level); navigation.tick(level);
if (navigation.destination == null && speed > 0) { if (!manualTick && navigation.destination == null && speed != 0) {
speed -= acceleration; if (speed > 0)
if (speed <= 0) speed = Math.max(speed - acceleration, 0);
speed = 0; else
speed = Math.min(speed + acceleration, 0);
} }
manualTick = false;
if (derailed) { if (derailed) {
speed /= 3f; speed /= 3f;
@ -145,12 +153,20 @@ public class Train {
for (int i = 0; i < carriages.size(); i++) { for (int i = 0; i < carriages.size(); i++) {
double leadingStress = i == 0 ? 0 : stress[i - 1] * leadingModifier; double leadingStress = i == 0 ? 0 : stress[i - 1] * leadingModifier;
double trailingStress = i == stress.length ? 0 : stress[i] * trailingModifier; double trailingStress = i == stress.length ? 0 : stress[i] * trailingModifier;
Carriage carriage = carriages.get(i); Carriage carriage = carriages.get(i);
TravellingPoint toFollow = previous;
Function<TravellingPoint, ITrackSelector> control = TravellingPoint toFollowForward = previous;
previous == null ? navigation::control : mp -> mp.follow(toFollow); TravellingPoint toFollowBackward = i == carriages.size() - 1 ? null
double actualDistance = carriage.travel(level, graph, distance + leadingStress + trailingStress, control); : carriages.get(i + 1)
.getLeadingPoint();
Function<TravellingPoint, ITrackSelector> forwardControl =
toFollowForward == null ? navigation::control : mp -> mp.follow(toFollowForward);
Function<TravellingPoint, ITrackSelector> backwardControl =
toFollowBackward == null ? navigation::control : mp -> mp.follow(toFollowBackward);
double actualDistance = carriage.travel(level, graph, distance + leadingStress + trailingStress,
forwardControl, backwardControl);
blocked |= carriage.blocked; blocked |= carriage.blocked;
if (i == 0) { if (i == 0) {
@ -165,7 +181,7 @@ public class Train {
navigation.cancelNavigation(); navigation.cancelNavigation();
runtime.tick(level); runtime.tick(level);
status.endOfTrack(); status.endOfTrack();
} else if (speed > 0) } else if (speed != 0)
status.trackOK(); status.trackOK();
if (navigation.destination != null) { if (navigation.destination != null) {
@ -376,7 +392,7 @@ public class Train {
return length; return length;
} }
public void leave() { public void leaveStation() {
GlobalStation currentStation = getCurrentStation(); GlobalStation currentStation = getCurrentStation();
if (currentStation == null) if (currentStation == null)
return; return;
@ -411,4 +427,15 @@ public class Train {
} }
} }
public void approachTargetSpeed(float accelerationMod) {
if (Mth.equal(targetSpeed, speed))
return;
if (manualTick)
leaveStation();
if (speed < targetSpeed)
speed = Math.min(speed + Train.acceleration * accelerationMod, targetSpeed);
else if (speed > targetSpeed)
speed = Math.max(speed - Train.acceleration * accelerationMod, targetSpeed);
}
} }

View file

@ -188,7 +188,7 @@ public class TrainRelocator {
}); });
train.status.successfulMigration(); train.status.successfulMigration();
train.leave(); train.leaveStation();
return true; return true;
} }
@ -293,8 +293,7 @@ public class TrainRelocator {
private static Train getTrainFromEntity(CarriageContraptionEntity carriageContraptionEntity) { private static Train getTrainFromEntity(CarriageContraptionEntity carriageContraptionEntity) {
if (carriageContraptionEntity == null) if (carriageContraptionEntity == null)
return null; return null;
int id = ((CarriageContraption) carriageContraptionEntity.getContraption()).temporaryCarriageIdHolder; Carriage carriage = carriageContraptionEntity.getCarriage();
Carriage carriage = Create.RAILWAYS.carriageById.get(id); // TODO: thread breach
if (carriage == null) if (carriage == null)
return null; return null;
return carriage.train; return carriage.train;

View file

@ -37,6 +37,10 @@ public class TrainStatus {
navigation = false; navigation = false;
} }
public void manualControls() {
displayInformation("Schedule paused for manual controls", true);
}
public void failedMigration() { public void failedMigration() {
if (track) if (track)
return; return;

View file

@ -13,6 +13,7 @@ import com.simibubi.create.content.logistics.trains.TrackEdge;
import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraph;
import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNode;
import com.simibubi.create.content.logistics.trains.management.GraphLocation; import com.simibubi.create.content.logistics.trains.management.GraphLocation;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
@ -34,7 +35,7 @@ public class TravellingPoint {
} }
public static interface ITrackSelector public static interface ITrackSelector
extends BiFunction<TrackGraph, List<Entry<TrackNode, TrackEdge>>, Entry<TrackNode, TrackEdge>> { extends BiFunction<TrackGraph, Pair<Boolean, List<Entry<TrackNode, TrackEdge>>>, Entry<TrackNode, TrackEdge>> {
}; };
public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) { public TravellingPoint(TrackNode node1, TrackNode node2, TrackEdge edge, double position) {
@ -45,15 +46,20 @@ public class TravellingPoint {
} }
public ITrackSelector random() { public ITrackSelector random() {
return (graph, validTargets) -> validTargets.get(Create.RANDOM.nextInt(validTargets.size())); return (graph, pair) -> pair.getSecond()
.get(Create.RANDOM.nextInt(pair.getSecond()
.size()));
} }
public ITrackSelector follow(TravellingPoint other) { public ITrackSelector follow(TravellingPoint other) {
return (graph, validTargets) -> { return (graph, pair) -> {
TrackNode target = other.node1; List<Entry<TrackNode, TrackEdge>> validTargets = pair.getSecond();
boolean forward = pair.getFirst();
TrackNode target = forward ? other.node1 : other.node2;
TrackNode secondary = forward ? other.node2 : other.node1;
for (Entry<TrackNode, TrackEdge> entry : validTargets) for (Entry<TrackNode, TrackEdge> entry : validTargets)
if (entry.getKey() == target || entry.getKey() == other.node2) if (entry.getKey() == target || entry.getKey() == secondary)
return entry; return entry;
Vector<List<Entry<TrackNode, TrackEdge>>> frontiers = new Vector<>(validTargets.size()); Vector<List<Entry<TrackNode, TrackEdge>>> frontiers = new Vector<>(validTargets.size());
@ -99,7 +105,9 @@ public class TravellingPoint {
} }
public ITrackSelector steer(SteerDirection direction, Vec3 upNormal) { public ITrackSelector steer(SteerDirection direction, Vec3 upNormal) {
return (graph, validTargets) -> { return (graph, pair) -> {
List<Entry<TrackNode, TrackEdge>> validTargets = pair.getSecond();
boolean forward = pair.getFirst();
double closest = Double.MAX_VALUE; double closest = Double.MAX_VALUE;
Entry<TrackNode, TrackEdge> best = null; Entry<TrackNode, TrackEdge> best = null;
@ -108,7 +116,7 @@ public class TravellingPoint {
Vec3 entryTrajectory = entry.getValue() Vec3 entryTrajectory = entry.getValue()
.getDirection(node2, entry.getKey(), true); .getDirection(node2, entry.getKey(), true);
Vec3 normal = trajectory.cross(upNormal); Vec3 normal = trajectory.cross(upNormal);
double dot = normal.dot(entryTrajectory); double dot = normal.dot(entryTrajectory) * (forward ? 1 : -1);
double diff = Math.abs(direction.targetDot - dot); double diff = Math.abs(direction.targetDot - dot);
if (diff > closest) if (diff > closest)
continue; continue;
@ -136,41 +144,84 @@ public class TravellingPoint {
double currentT = position / edgeLength; double currentT = position / edgeLength;
double incrementT = edge.incrementT(node1, node2, currentT, distance); double incrementT = edge.incrementT(node1, node2, currentT, distance);
position = incrementT * edgeLength; position = incrementT * edgeLength;
List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>(); List<Entry<TrackNode, TrackEdge>> validTargets = new ArrayList<>();
while (position > edgeLength) {
validTargets.clear();
for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node2) if (distance > 0) {
.entrySet()) { // Moving forward
TrackNode newNode = entry.getKey(); while (position > edgeLength) {
if (newNode == node1) validTargets.clear();
continue;
TrackEdge newEdge = entry.getValue(); for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node2)
Vec3 currentDirection = edge.getDirection(node1, node2, false); .entrySet()) {
Vec3 newDirection = newEdge.getDirection(node2, newNode, true); TrackNode newNode = entry.getKey();
if (currentDirection.dot(newDirection) < 0) if (newNode == node1)
continue; continue;
validTargets.add(entry); TrackEdge newEdge = entry.getValue();
Vec3 currentDirection = edge.getDirection(node1, node2, false);
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
if (currentDirection.dot(newDirection) < 0)
continue;
validTargets.add(entry);
}
if (validTargets.isEmpty()) {
traveled -= position - edgeLength;
position = edgeLength;
blocked = true;
break;
}
Entry<TrackNode, TrackEdge> entry = validTargets.size() == 1 ? validTargets.get(0)
: trackSelector.apply(graph, Pair.of(true, validTargets));
node1 = node2;
node2 = entry.getKey();
edge = entry.getValue();
position -= edgeLength;
edgeLength = edge.getLength(node1, node2);
} }
if (validTargets.isEmpty()) { } else {
traveled -= position - edgeLength; // Moving backwards
position = edgeLength; while (position < 0) {
blocked = true; validTargets.clear();
break;
for (Entry<TrackNode, TrackEdge> entry : graph.getConnectionsFrom(node1)
.entrySet()) {
TrackNode newNode = entry.getKey();
if (newNode == node2)
continue;
TrackEdge newEdge = graph.getConnectionsFrom(newNode)
.get(node1);
Vec3 currentDirection = edge.getDirection(node1, node2, true);
Vec3 newDirection = newEdge.getDirection(newNode, node1, false);
if (currentDirection.dot(newDirection) < 0)
continue;
validTargets.add(entry);
}
if (validTargets.isEmpty()) {
traveled -= position;
position = 0;
blocked = true;
break;
}
Entry<TrackNode, TrackEdge> entry = validTargets.size() == 1 ? validTargets.get(0)
: trackSelector.apply(graph, Pair.of(false, validTargets));
node2 = node1;
node1 = entry.getKey();
edge = graph.getConnectionsFrom(node1)
.get(node2);
edgeLength = edge.getLength(node1, node2);
position += edgeLength;
} }
Entry<TrackNode, TrackEdge> entry =
validTargets.size() == 1 ? validTargets.get(0) : trackSelector.apply(graph, validTargets);
node1 = node2;
node2 = entry.getKey();
edge = entry.getValue();
position -= edgeLength;
edgeLength = edge.getLength(node1, node2);
} }
return traveled; return traveled;

View file

@ -414,6 +414,7 @@ public class StationTileEntity extends SmartTileEntity {
List<CarriageContraption> contraptions = new ArrayList<>(); List<CarriageContraption> contraptions = new ArrayList<>();
List<Carriage> carriages = new ArrayList<>(); List<Carriage> carriages = new ArrayList<>();
List<Integer> spacing = new ArrayList<>(); List<Integer> spacing = new ArrayList<>();
boolean atLeastOneForwardControls = false;
for (int bogeyIndex = 0; bogeyIndex < bogeyCount; bogeyIndex++) { for (int bogeyIndex = 0; bogeyIndex < bogeyCount; bogeyIndex++) {
int pointIndex = bogeyIndex * 2; int pointIndex = bogeyIndex * 2;
@ -425,6 +426,7 @@ public class StationTileEntity extends SmartTileEntity {
try { try {
boolean success = contraption.assemble(level, boolean success = contraption.assemble(level,
bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex] + 1)); bogeyPosOffset.relative(assemblyDirection, bogeyLocations[bogeyIndex] + 1));
atLeastOneForwardControls |= contraption.hasForwardControls();
if (!success) { if (!success) {
exception(new AssemblyException(Lang.translate("train_assembly.nothing_attached", bogeyIndex + 1)), exception(new AssemblyException(Lang.translate("train_assembly.nothing_attached", bogeyIndex + 1)),
-1); -1);
@ -467,6 +469,11 @@ public class StationTileEntity extends SmartTileEntity {
carriages.add(carriage); carriages.add(carriage);
} }
if (!atLeastOneForwardControls) {
exception(new AssemblyException(Lang.translate("train_assembly.no_controls")), -1);
return;
}
for (CarriageContraption contraption : contraptions) { for (CarriageContraption contraption : contraptions) {
contraption.removeBlocksFromWorld(level, BlockPos.ZERO); contraption.removeBlocksFromWorld(level, BlockPos.ZERO);
contraption.expandBoundsAroundAxis(Axis.Y); contraption.expandBoundsAroundAxis(Axis.Y);

View file

@ -15,6 +15,7 @@ import com.simibubi.create.content.contraptions.components.fan.AirCurrent;
import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineBlock; import com.simibubi.create.content.contraptions.components.flywheel.engine.EngineBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler; import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay; import com.simibubi.create.content.contraptions.components.structureMovement.chassis.ChassisRangeDisplay;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsHandler;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher; import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionRenderDispatcher;
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingHandlerClient;
import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics; import com.simibubi.create.content.contraptions.components.structureMovement.train.CouplingPhysics;
@ -105,6 +106,7 @@ public class ClientEvents {
Level world = Minecraft.getInstance().level; Level world = Minecraft.getInstance().level;
if (event.phase == Phase.START) { if (event.phase == Phase.START) {
LinkedControllerClientHandler.tick(); LinkedControllerClientHandler.tick();
ControlsHandler.tick();
AirCurrent.tickClientPlayerSounds(); AirCurrent.tickClientPlayerSounds();
return; return;
} }

View file

@ -0,0 +1,37 @@
package com.simibubi.create.foundation.utility;
import java.util.Vector;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.Options;
public class ControlsUtil {
private static Vector<KeyMapping> standardControls;
public static Vector<KeyMapping> getControls() {
if (standardControls == null) {
Options gameSettings = Minecraft.getInstance().options;
standardControls = new Vector<>(6);
standardControls.add(gameSettings.keyUp);
standardControls.add(gameSettings.keyDown);
standardControls.add(gameSettings.keyLeft);
standardControls.add(gameSettings.keyRight);
standardControls.add(gameSettings.keyJump);
standardControls.add(gameSettings.keyShift);
}
return standardControls;
}
public static boolean isActuallyPressed(KeyMapping kb) {
return InputConstants.isKeyDown(Minecraft.getInstance()
.getWindow()
.getWindow(),
kb.getKey()
.getValue());
}
}

View file

@ -627,6 +627,8 @@
"create.train_assembly.not_connected_in_order": "Bogeys are not connected in order", "create.train_assembly.not_connected_in_order": "Bogeys are not connected in order",
"create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own", "create.train_assembly.single_bogey_carriage": "This Bogey type cannot support a carriage on its own",
"create.train_assembly.nothing_attached": "No structure attached to Bogey %1$s", "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.track_target.set": "Targeted track selected", "create.track_target.set": "Targeted track selected",
"create.track_target.success": "Successfully bound to targeted track", "create.track_target.success": "Successfully bound to targeted track",
@ -643,6 +645,10 @@
"create.train.relocate.invalid": "Cannot relocate Train to this Track", "create.train.relocate.invalid": "Cannot relocate Train to this Track",
"create.train.relocate.too_far": "Cannot relocate Train this far away", "create.train.relocate.too_far": "Cannot relocate Train this far away",
"create.contraption.controls.start_controlling": "Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
"create.gui.config.overlay1": "Hi :)", "create.gui.config.overlay1": "Hi :)",
"create.gui.config.overlay2": "This is a sample overlay", "create.gui.config.overlay2": "This is a sample overlay",
"create.gui.config.overlay3": "Click or drag with your mouse", "create.gui.config.overlay3": "Click or drag with your mouse",

View file

@ -3,32 +3,53 @@
"texture_size": [32, 32], "texture_size": [32, 32],
"textures": { "textures": {
"0": "create:block/brass_casing_belt", "0": "create:block/brass_casing_belt",
"1": "create:block/brass_block",
"3": "create:block/brass_funnel_plating", "3": "create:block/brass_funnel_plating",
"4": "create:block/blaze_burner_side",
"5": "create:block/blaze_heater_brazier",
"particle": "create:block/brass_casing" "particle": "create:block/brass_casing"
}, },
"elements": [ "elements": [
{ {
"from": [0, 0, 4], "from": [0, 0, 4],
"to": [16, 8, 16], "to": [16, 4, 8],
"faces": { "faces": {
"north": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"}, "north": {"uv": [12, 0, 16, 16], "rotation": 90, "texture": "#4"},
"east": {"uv": [8, 8.5, 14, 12.5], "texture": "#0"}, "east": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#4"},
"south": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"}, "west": {"uv": [12, 12, 16, 16], "rotation": 90, "texture": "#4"},
"west": {"uv": [10, 8.5, 16, 12.5], "texture": "#0"}, "up": {"uv": [8, 0, 16, 2], "texture": "#5"},
"up": {"uv": [9, 1, 15, 9], "rotation": 90, "texture": "#3"}, "down": {"uv": [6, 8, 8, 16], "rotation": 90, "texture": "#5"}
"down": {"uv": [0, 2, 16, 14], "texture": "#1"}
} }
}, },
{ {
"from": [0, 8, 6], "from": [0, 0, 8],
"to": [8, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#5"},
"south": {"uv": [2, 5, 6, 8], "texture": "#5"},
"west": {"uv": [2, 5, 6, 8], "texture": "#5"},
"down": {"uv": [0, 8, 4, 11], "texture": "#5"}
}
},
{
"from": [8, 0, 8],
"to": [16, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#5"},
"east": {"uv": [2, 5, 6, 8], "texture": "#5"},
"south": {"uv": [2, 5, 6, 8], "texture": "#5"},
"down": {"uv": [4, 8, 8, 11], "texture": "#5"}
}
},
{
"from": [0, 6, 6],
"to": [16, 14, 16], "to": [16, 14, 16],
"faces": { "faces": {
"north": {"uv": [11, 1, 14, 9], "rotation": 90, "texture": "#3"}, "north": {"uv": [10, 1, 14, 9], "rotation": 270, "texture": "#3"},
"east": {"uv": [7, 0, 16, 6], "texture": "#1"}, "east": {"uv": [3, 0, 8, 4], "texture": "#0"},
"south": {"uv": [2, 0, 14, 6], "texture": "#1"}, "south": {"uv": [8, 0, 16, 4], "texture": "#0"},
"west": {"uv": [0, 0, 10, 6], "texture": "#1"}, "west": {"uv": [0, 0, 5, 4], "texture": "#0"},
"up": {"uv": [9, 1, 14, 9], "rotation": 270, "texture": "#3"} "up": {"uv": [9, 1, 14, 9], "rotation": 270, "texture": "#3"},
"down": {"uv": [10, 1, 15, 9], "rotation": 270, "texture": "#3"}
} }
} }
], ],
@ -37,7 +58,7 @@
"name": "closed", "name": "closed",
"origin": [0, 0, 0], "origin": [0, 0, 0],
"color": 0, "color": 0,
"children": [0, 1] "children": [0, 1, 2, 3]
} }
] ]
} }

View file

@ -6,59 +6,88 @@
"1": "create:block/brass_block", "1": "create:block/brass_block",
"2": "create:block/brass_funnel_back", "2": "create:block/brass_funnel_back",
"3": "create:block/brass_funnel_plating", "3": "create:block/brass_funnel_plating",
"5": "create:block/blaze_burner_side",
"6": "create:block/blaze_heater_brazier",
"particle": "create:block/brass_casing" "particle": "create:block/brass_casing"
}, },
"elements": [ "elements": [
{ {
"from": [0, 0, 4], "from": [14, 6, 6],
"to": [16, 8, 16],
"faces": {
"north": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"},
"east": {"uv": [8, 8.5, 14, 12.5], "texture": "#0"},
"south": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"},
"west": {"uv": [10, 8.5, 16, 12.5], "texture": "#0"},
"up": {"uv": [9, 1, 15, 9], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 2, 16, 14], "texture": "#1"}
}
},
{
"from": [14, 8, 6],
"to": [16, 14, 16], "to": [16, 14, 16],
"faces": { "faces": {
"north": {"uv": [11, 8, 14, 9], "rotation": 90, "texture": "#3"}, "north": {"uv": [10, 8, 14, 9], "rotation": 90, "texture": "#3"},
"east": {"uv": [7, 0, 16, 6], "texture": "#1"}, "east": {"uv": [7, 0, 16, 8], "texture": "#particle"},
"south": {"uv": [11, 0, 13, 6], "texture": "#1"}, "south": {"uv": [15, 0, 16, 4], "texture": "#0"},
"west": {"uv": [0, 0, 10, 6], "texture": "#1"}, "west": {"uv": [0, 0, 10, 6], "texture": "#1"},
"up": {"uv": [9, 8, 14, 9], "rotation": 270, "texture": "#3"} "up": {"uv": [9, 8, 14, 9], "rotation": 270, "texture": "#3"},
"down": {"uv": [10, 8, 15, 9], "rotation": 270, "texture": "#3"}
} }
}, },
{ {
"from": [2, 8, 14], "from": [2, 6, 14],
"to": [14, 14, 16], "to": [14, 14, 16],
"faces": { "faces": {
"north": {"uv": [2, 0, 14, 6], "texture": "#1"}, "north": {"uv": [2, 0, 14, 6], "texture": "#1"},
"south": {"uv": [3, 0, 12, 6], "texture": "#1"}, "south": {"uv": [9, 0, 15, 4], "texture": "#0"},
"up": {"uv": [10, 1, 14, 2], "rotation": 180, "texture": "#3"} "up": {"uv": [10, 1, 14, 2], "rotation": 180, "texture": "#3"}
} }
}, },
{ {
"from": [0, 8, 6], "from": [0, 6, 6],
"to": [2, 14, 16], "to": [2, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]}, "rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]},
"faces": { "faces": {
"north": {"uv": [11, 9, 14, 8], "rotation": 90, "texture": "#3"}, "north": {"uv": [10, 9, 14, 8], "rotation": 90, "texture": "#3"},
"east": {"uv": [10, 0, 0, 6], "texture": "#1"}, "east": {"uv": [10, 0, 0, 6], "texture": "#1"},
"south": {"uv": [4, 0, 2, 6], "texture": "#1"}, "south": {"uv": [9, 0, 8, 4], "texture": "#0"},
"west": {"uv": [16, 0, 7, 6], "texture": "#1"}, "west": {"uv": [16, 0, 7, 8], "texture": "#particle"},
"up": {"uv": [9, 9, 14, 8], "rotation": 270, "texture": "#3"} "up": {"uv": [9, 9, 14, 8], "rotation": 270, "texture": "#3"},
"down": {"uv": [10, 9, 15, 8], "rotation": 270, "texture": "#3"}
} }
}, },
{ {
"from": [2, 8, 7], "from": [2, 6, 7],
"to": [14, 13, 14], "to": [14, 13, 14],
"faces": { "faces": {
"north": {"uv": [0, 8, 2.5, 14], "rotation": 270, "texture": "#2"}, "north": {"uv": [0, 8, 3.5, 14], "rotation": 270, "texture": "#2"},
"up": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"} "up": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"},
"down": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"}
}
},
{
"from": [0, 0, 8],
"to": [8, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#6"},
"east": {"uv": [0, 0, 0, 0], "texture": "#6"},
"south": {"uv": [2, 5, 6, 8], "texture": "#6"},
"west": {"uv": [2, 5, 6, 8], "texture": "#6"},
"up": {"uv": [0, 0, 0, 0], "texture": "#6"},
"down": {"uv": [0, 8, 4, 11], "texture": "#6"}
}
},
{
"from": [8, 0, 8],
"to": [16, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#6"},
"east": {"uv": [2, 5, 6, 8], "texture": "#6"},
"south": {"uv": [2, 5, 6, 8], "texture": "#6"},
"west": {"uv": [0, 0, 0, 0], "texture": "#6"},
"up": {"uv": [0, 0, 0, 0], "texture": "#6"},
"down": {"uv": [4, 8, 8, 11], "texture": "#6"}
}
},
{
"from": [0, 0, 4],
"to": [16, 4, 8],
"faces": {
"north": {"uv": [12, 0, 16, 16], "rotation": 90, "texture": "#5"},
"east": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#5"},
"south": {"uv": [0, 0, 0, 0], "rotation": 90, "texture": "#6"},
"west": {"uv": [12, 12, 16, 16], "rotation": 90, "texture": "#5"},
"up": {"uv": [8, 0, 16, 2], "texture": "#6"},
"down": {"uv": [6, 8, 8, 16], "rotation": 90, "texture": "#6"}
} }
} }
], ],
@ -67,7 +96,10 @@
"name": "open", "name": "open",
"origin": [0, 0, 0], "origin": [0, 0, 0],
"color": 0, "color": 0,
"children": [0, 1, 2, 3, 4] "children": [0, 1, 2, 3]
} },
4,
5,
6
] ]
} }

View file

@ -7,85 +7,12 @@
"2": "create:block/brass_funnel_back", "2": "create:block/brass_funnel_back",
"3": "create:block/brass_funnel_plating", "3": "create:block/brass_funnel_plating",
"5": "block/lever", "5": "block/lever",
"7": "create:block/chute" "6": "create:block/blaze_heater_brazier",
"7": "create:block/chute",
"1_5": "create:block/blaze_burner_side",
"particle": "create:block/brass_casing"
}, },
"elements": [ "elements": [
{
"from": [0, 0, 4],
"to": [16, 8, 16],
"faces": {
"north": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"},
"east": {"uv": [8, 8.5, 14, 12.5], "texture": "#0"},
"south": {"uv": [8, 8.5, 16, 12.5], "texture": "#0"},
"west": {"uv": [10, 8.5, 16, 12.5], "texture": "#0"},
"up": {"uv": [9, 1, 15, 9], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 2, 16, 14], "texture": "#1"}
}
},
{
"from": [14, 8, 6],
"to": [16, 14, 16],
"faces": {
"north": {"uv": [11, 8, 14, 9], "rotation": 90, "texture": "#3"},
"east": {"uv": [7, 0, 16, 6], "texture": "#1"},
"south": {"uv": [11, 0, 13, 6], "texture": "#1"},
"west": {"uv": [0, 0, 10, 6], "texture": "#1"},
"up": {"uv": [9, 8, 14, 9], "rotation": 270, "texture": "#3"}
}
},
{
"from": [2, 8, 14],
"to": [14, 14, 16],
"faces": {
"north": {"uv": [2, 0, 14, 6], "texture": "#1"},
"south": {"uv": [3, 0, 12, 6], "texture": "#1"},
"up": {"uv": [10, 1, 14, 2], "rotation": 180, "texture": "#3"}
}
},
{
"from": [0, 8, 6],
"to": [2, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]},
"faces": {
"north": {"uv": [11, 9, 14, 8], "rotation": 90, "texture": "#3"},
"east": {"uv": [10, 0, 0, 6], "texture": "#1"},
"south": {"uv": [4, 0, 2, 6], "texture": "#1"},
"west": {"uv": [16, 0, 7, 6], "texture": "#1"},
"up": {"uv": [9, 9, 14, 8], "rotation": 270, "texture": "#3"}
}
},
{
"from": [2, 8, 7],
"to": [14, 13, 14],
"faces": {
"north": {"uv": [0, 8, 2.5, 14], "rotation": 270, "texture": "#2"},
"up": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"}
}
},
{
"from": [6, 7.25, 6.75],
"to": [10, 13.25, 14.75],
"faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"}
}
},
{
"from": [0, 7.25, 6.75],
"to": [4, 13.25, 14.75],
"faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"}
}
},
{
"from": [12, 7.25, 6.75],
"to": [16, 13.25, 14.75],
"faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"}
}
},
{ {
"from": [4, 9, -1], "from": [4, 9, -1],
"to": [6, 11, 9], "to": [6, 11, 9],
@ -109,6 +36,109 @@
"up": {"uv": [7, 6, 9, 16], "texture": "#5"}, "up": {"uv": [7, 6, 9, 16], "texture": "#5"},
"down": {"uv": [7, 6, 9, 16], "rotation": 180, "texture": "#5"} "down": {"uv": [7, 6, 9, 16], "rotation": 180, "texture": "#5"}
} }
},
{
"from": [14, 6, 6],
"to": [16, 14, 16],
"faces": {
"north": {"uv": [10, 8, 14, 9], "rotation": 90, "texture": "#3"},
"east": {"uv": [7, 0, 16, 8], "texture": "#particle"},
"south": {"uv": [15, 0, 16, 4], "texture": "#0"},
"west": {"uv": [0, 0, 10, 6], "texture": "#1"},
"up": {"uv": [9, 8, 14, 9], "rotation": 270, "texture": "#3"},
"down": {"uv": [10, 8, 15, 9], "rotation": 270, "texture": "#3"}
}
},
{
"from": [2, 6, 14],
"to": [14, 14, 16],
"faces": {
"north": {"uv": [2, 0, 14, 6], "texture": "#1"},
"south": {"uv": [9, 0, 15, 4], "texture": "#0"},
"up": {"uv": [10, 1, 14, 2], "rotation": 180, "texture": "#3"}
}
},
{
"from": [0, 6, 6],
"to": [2, 14, 16],
"rotation": {"angle": 0, "axis": "y", "origin": [16, 0, 0]},
"faces": {
"north": {"uv": [10, 9, 14, 8], "rotation": 90, "texture": "#3"},
"east": {"uv": [10, 0, 0, 6], "texture": "#1"},
"south": {"uv": [9, 0, 8, 4], "texture": "#0"},
"west": {"uv": [16, 0, 7, 8], "texture": "#particle"},
"up": {"uv": [9, 9, 14, 8], "rotation": 270, "texture": "#3"},
"down": {"uv": [10, 9, 15, 8], "rotation": 270, "texture": "#3"}
}
},
{
"from": [2, 6, 7],
"to": [14, 13, 14],
"faces": {
"north": {"uv": [0, 8, 3.5, 14], "rotation": 270, "texture": "#2"},
"up": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"},
"down": {"uv": [2.5, 8, 6, 14], "rotation": 90, "texture": "#2"}
}
},
{
"from": [0, 0, 8],
"to": [8, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#6"},
"east": {"uv": [0, 0, 0, 0], "texture": "#6"},
"south": {"uv": [2, 5, 6, 8], "texture": "#6"},
"west": {"uv": [2, 5, 6, 8], "texture": "#6"},
"up": {"uv": [0, 0, 0, 0], "texture": "#6"},
"down": {"uv": [0, 8, 4, 11], "texture": "#6"}
}
},
{
"from": [8, 0, 8],
"to": [16, 6, 16],
"faces": {
"north": {"uv": [2, 5, 6, 8], "texture": "#6"},
"east": {"uv": [2, 5, 6, 8], "texture": "#6"},
"south": {"uv": [2, 5, 6, 8], "texture": "#6"},
"west": {"uv": [0, 0, 0, 0], "texture": "#6"},
"up": {"uv": [0, 0, 0, 0], "texture": "#6"},
"down": {"uv": [4, 8, 8, 11], "texture": "#6"}
}
},
{
"from": [0, 0, 4],
"to": [16, 4, 8],
"faces": {
"north": {"uv": [12, 0, 16, 16], "rotation": 90, "texture": "#1_5"},
"east": {"uv": [12, 0, 16, 4], "rotation": 90, "texture": "#1_5"},
"south": {"uv": [0, 0, 0, 0], "rotation": 90, "texture": "#6"},
"west": {"uv": [12, 12, 16, 16], "rotation": 90, "texture": "#1_5"},
"up": {"uv": [8, 0, 16, 2], "texture": "#6"},
"down": {"uv": [6, 8, 8, 16], "rotation": 90, "texture": "#6"}
}
},
{
"from": [6, 6.25, 6.75],
"to": [10, 13.25, 14.75],
"faces": {
"north": {"uv": [8.5, 1, 12, 3], "rotation": 270, "texture": "#7"},
"up": {"uv": [8.5, 1, 12.5, 3], "rotation": 270, "texture": "#7"}
}
},
{
"from": [0, 6.25, 6.75],
"to": [4, 13.25, 14.75],
"faces": {
"north": {"uv": [12, 1, 15.5, 3], "rotation": 90, "texture": "#7"},
"up": {"uv": [11.5, 1, 15.5, 3], "rotation": 90, "texture": "#7"}
}
},
{
"from": [12, 6.25, 6.75],
"to": [16, 13.25, 14.75],
"faces": {
"north": {"uv": [12, 1, 15.5, 3], "rotation": 90, "texture": "#7"},
"up": {"uv": [11.5, 1, 15.5, 3], "rotation": 90, "texture": "#7"}
}
} }
], ],
"display": { "display": {
@ -148,28 +178,38 @@
}, },
"groups": [ "groups": [
{ {
"name": "open", "name": "lever",
"origin": [0, 0, 0], "origin": [8, 8, 8],
"color": 0, "color": 0,
"children": [0, 1, 2, 3, 4] "children": [0]
},
{
"name": "lever",
"origin": [8, 8, 8],
"color": 0,
"children": [1]
},
{
"name": "block_open",
"origin": [8, 8, 8],
"color": 0,
"children": [
{
"name": "open",
"origin": [0, 0, 0],
"color": 0,
"children": [2, 3, 4, 5]
},
6,
7,
8
]
}, },
{ {
"name": "cover", "name": "cover",
"origin": [8, 8, 8], "origin": [8, 8, 8],
"color": 0, "color": 0,
"children": [5, 6, 7] "children": [9, 10, 11]
},
{
"name": "lever",
"origin": [8, 8, 8],
"color": 0,
"children": [8]
},
{
"name": "lever",
"origin": [8, 8, 8],
"color": 0,
"children": [9]
} }
] ]
} }

View file

@ -6,27 +6,27 @@
}, },
"elements": [ "elements": [
{ {
"from": [6, 7.25, 6.75], "from": [6, 6.25, 6.75],
"to": [10, 13.25, 14.75], "to": [10, 13.25, 14.75],
"faces": { "faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"}, "north": {"uv": [8.5, 1, 12, 3], "rotation": 270, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"} "up": {"uv": [8.5, 1, 12.5, 3], "rotation": 270, "texture": "#7"}
} }
}, },
{ {
"from": [0, 7.25, 6.75], "from": [0, 6.25, 6.75],
"to": [4, 13.25, 14.75], "to": [4, 13.25, 14.75],
"faces": { "faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"}, "north": {"uv": [12, 1, 15.5, 3], "rotation": 90, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"} "up": {"uv": [11.5, 1, 15.5, 3], "rotation": 90, "texture": "#7"}
} }
}, },
{ {
"from": [12, 7.25, 6.75], "from": [12, 6.25, 6.75],
"to": [16, 13.25, 14.75], "to": [16, 13.25, 14.75],
"faces": { "faces": {
"north": {"uv": [10.5, 6, 13.5, 8], "rotation": 270, "texture": "#7"}, "north": {"uv": [12, 1, 15.5, 3], "rotation": 90, "texture": "#7"},
"up": {"uv": [10, 6, 14, 8], "rotation": 90, "texture": "#7"} "up": {"uv": [11.5, 1, 15.5, 3], "rotation": 90, "texture": "#7"}
} }
} }
] ]