diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index a96d2faa3..d6df6948a 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -484,7 +484,7 @@ e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/stressometer. 8b0c2c7ac72529565b3339aa8df7565858100afa assets/create/blockstates/tiled_glass.json a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_pane.json 85b57776edf426c2f8df6698b2482ea925914a5c assets/create/blockstates/track.json -5a61450b6f6aac63f75580f8dcbc3d3fabfd54d8 assets/create/blockstates/track_signal.json +408ae1009ee8bb2f2b83753d5909c53744f7865f assets/create/blockstates/track_signal.json aa08785f906d41933e0dd1086ea7b08f5b93aa24 assets/create/blockstates/track_station.json 29af21c8d82891139d48d69f0393f612f2b6f8f1 assets/create/blockstates/tuff_pillar.json a8094531617e27a545c4815ab2062bf0ffca3633 assets/create/blockstates/turntable.json @@ -541,21 +541,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json 255e47ab7894ba35851a2f34c82be3dc9c9e8784 assets/create/lang/en_ud.json -b908dd7c47b286d05a57b8a58c60051363ffff86 assets/create/lang/en_us.json -29ad91d27ee183b9d4de8d152d0fb8ed2a388a0c assets/create/lang/unfinished/de_de.json -8d33ba82d3cca307c5ae0dda41a49ec16f1c7b74 assets/create/lang/unfinished/es_cl.json -ae674553b564a9e09a7d10c9c2d8c1be1307f40a assets/create/lang/unfinished/es_es.json -318149855f383fb90439f2f0818e8e83fee3924e assets/create/lang/unfinished/fr_fr.json -e7321dbe8f98c96e778b5c46823c98500b3001bc assets/create/lang/unfinished/it_it.json -5a2da425fd0dd276c3d7cf66f6bb43f229574306 assets/create/lang/unfinished/ja_jp.json -98fc1956e8b25aec27e889ada3a160800b958dfd assets/create/lang/unfinished/ko_kr.json -67cefb6690f5cccce93d776a760ebdadc7f2631e assets/create/lang/unfinished/nl_nl.json -9a7f4d369d2a54aaf5c422fae740244025a13af4 assets/create/lang/unfinished/pl_pl.json -3656897ffc5c89bf16a32ad11efe33cd5b4bfb23 assets/create/lang/unfinished/pt_br.json -c84995ec524b6469fc42f39574be21b9dbee24e3 assets/create/lang/unfinished/pt_pt.json -bcf41d9fd8454296dc56326b6e26ee41e2ad52e5 assets/create/lang/unfinished/ru_ru.json -d3dfdab017748fa82f9e952a35bd6e82fe063771 assets/create/lang/unfinished/zh_cn.json -dda3aee2ece5503edd53dbd4aa9db7363e4beafc assets/create/lang/unfinished/zh_tw.json +e6698e4672c04cf7b8251e2267b1fe3d6c60e50c assets/create/lang/en_us.json +dfd5234276f508edfb10160fa2b7859363acc313 assets/create/lang/unfinished/de_de.json +c23ca905e7aa9983057c970d9e799b4ba91a9acd assets/create/lang/unfinished/es_cl.json +1781ed3854e04116319528699b4edee9cff4a435 assets/create/lang/unfinished/es_es.json +24d421795a67a19efd3a092b693c2397b3b84d9b assets/create/lang/unfinished/fr_fr.json +50107fc09f422527f20b0a2ddee7e961540e4f6c assets/create/lang/unfinished/it_it.json +570cc561fcb7f1839212e7ba3e1a68886874c846 assets/create/lang/unfinished/ja_jp.json +f5ddd8b98314636c4c763cdd8aee7acd462b00a9 assets/create/lang/unfinished/ko_kr.json +f3696cf3bfcdff92eb11882be9be9fa2759c51c6 assets/create/lang/unfinished/nl_nl.json +3df68a7b3fb44dd666de541d7437c300d596aa7b assets/create/lang/unfinished/pl_pl.json +6a7fb1146f15117abca1a0ea970ab4054a1ee6a7 assets/create/lang/unfinished/pt_br.json +6e993c9e6f5faa55448a8b24456082096cb10935 assets/create/lang/unfinished/pt_pt.json +d8fc231286d4a53e249037905c92513857432c4c assets/create/lang/unfinished/ru_ru.json +3aedca5bf7cf2f08cb53d6e8b5949009cddc1843 assets/create/lang/unfinished/zh_cn.json +30f01dd054c4706d37f6d5ece0fc09ad241a6214 assets/create/lang/unfinished/zh_tw.json 487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json 3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json diff --git a/src/generated/resources/assets/create/blockstates/track_signal.json b/src/generated/resources/assets/create/blockstates/track_signal.json index 691723f6a..22f491f71 100644 --- a/src/generated/resources/assets/create/blockstates/track_signal.json +++ b/src/generated/resources/assets/create/blockstates/track_signal.json @@ -1,7 +1,10 @@ { "variants": { - "": { - "model": "create:block/track_signal/block" + "type=entry_signal": { + "model": "create:block/track_signal/block_entry_signal" + }, + "type=cross_signal": { + "model": "create:block/track_signal/block_cross_signal" } } } \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index bec91fbc7..9151b387a 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -1424,6 +1424,10 @@ "create.train.relocate.invalid": "Cannot relocate Train to here", "create.train.relocate.too_far": "Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "-> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "-> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index 267cc1628..54d88c438 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1435", + "_": "Missing Localizations: 1438", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_cl.json b/src/generated/resources/assets/create/lang/unfinished/es_cl.json index a2cbb0a0b..5634d7f01 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_cl.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_cl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 446", + "_": "Missing Localizations: 449", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json index f1a3c04fb..1c9aa0439 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_es.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 446", + "_": "Missing Localizations: 449", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index fe6040df8..696c9d297 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1697", + "_": "Missing Localizations: 1700", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 4b4e8ee5a..4efcc7573 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1386", + "_": "Missing Localizations: 1389", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index 0d4062584..25cafa447 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 116", + "_": "Missing Localizations: 119", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index a98bd1e5a..cc17db55a 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 118", + "_": "Missing Localizations: 121", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index fd6b4c140..bea5c6765 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 2050", + "_": "Missing Localizations: 2053", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json index 3dd84b415..1617f65ce 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json +++ b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 485", + "_": "Missing Localizations: 488", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index 17086c8c8..2de547a82 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1669", + "_": "Missing Localizations: 1672", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json index 19a116dbc..ec7026dd5 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1669", + "_": "Missing Localizations: 1672", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 5f282f4ca..376533c56 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 490", + "_": "Missing Localizations: 493", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index e7a92edf4..0243ca27c 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 116", + "_": "Missing Localizations: 119", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json index d93ec320d..b26e8bb86 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 504", + "_": "Missing Localizations: 507", "_": "->------------------------] Game Elements [------------------------<-", @@ -1425,6 +1425,10 @@ "create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here", "create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "UNLOCALIZED: Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "UNLOCALIZED: -> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "UNLOCALIZED: -> Allow passage if section fully traversable", + "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", diff --git a/src/main/java/com/simibubi/create/AllBlockPartials.java b/src/main/java/com/simibubi/create/AllBlockPartials.java index 11aa86b3b..f5412541b 100644 --- a/src/main/java/com/simibubi/create/AllBlockPartials.java +++ b/src/main/java/com/simibubi/create/AllBlockPartials.java @@ -151,6 +151,9 @@ public class AllBlockPartials { SIGNAL_RED_CUBE = block("track_signal/red_cube"), SIGNAL_RED_GLOW = block("track_signal/red_glow"), SIGNAL_RED = block("track_signal/red_tube"), + SIGNAL_YELLOW_CUBE = block("track_signal/yellow_cube"), + SIGNAL_YELLOW_GLOW = block("track_signal/yellow_glow"), + SIGNAL_YELLOW = block("track_signal/yellow_tube"), CRAFTING_BLUEPRINT_1x1 = entity("crafting_blueprint_small"), CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"), diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index fcc73d726..20131c78e 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -1336,7 +1336,11 @@ public class AllBlocks { .initialProperties(SharedProperties::softMetal) .properties(p -> p.sound(SoundType.NETHERITE_BLOCK)) .transform(pickaxeOnly()) - .blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.partialBaseModel(c, p))) + .blockstate((c, p) -> p.getVariantBuilder(c.get()) + .forAllStates(state -> ConfiguredModel.builder() + .modelFile(AssetLookup.partialBaseModel(c, p, state.getValue(SignalBlock.TYPE) + .getSerializedName())) + .build())) .lang("Train Signal") .item(TrackTargetingBlockItem::new) .transform(customItemModel()) diff --git a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java index d101e8a3b..efc153b6a 100644 --- a/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java +++ b/src/main/java/com/simibubi/create/content/logistics/block/redstone/NixieTubeRenderer.java @@ -177,10 +177,11 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer trains; public TrackGraphSync sync; + private List movingTrains; + private List waitingTrains; + private RailwaySavedData savedData; public GlobalRailwayManager() { @@ -75,6 +80,8 @@ public class GlobalRailwayManager { trains = savedData.getTrains(); trackNetworks = savedData.getTrackNetworks(); signalEdgeGroups = savedData.getSignalBlocks(); + trains.values() + .forEach(movingTrains::add); } public void cleanUp() { @@ -82,6 +89,8 @@ public class GlobalRailwayManager { signalEdgeGroups = new HashMap<>(); trains = new HashMap<>(); sync = new TrackGraphSync(); + movingTrains = new LinkedList<>(); + waitingTrains = new LinkedList<>(); } public void markTracksDirty() { @@ -89,6 +98,19 @@ public class GlobalRailwayManager { savedData.setDirty(); } + public void addTrain(Train train) { + trains.put(train.id, train); + movingTrains.add(train); + } + + public void removeTrain(UUID id) { + Train removed = trains.remove(id); + if (removed == null) + return; + movingTrains.remove(removed); + waitingTrains.remove(removed); + } + // public TrackGraph getOrCreateGraph(UUID graphID) { @@ -145,22 +167,51 @@ public class GlobalRailwayManager { group.trains.clear(); group.reserved = null; } - + for (TrackGraph graph : trackNetworks.values()) - graph.tickPoints(); - for (Train train : trains.values()) - train.earlyTick(level); - for (Train train : trains.values()) - train.tick(level); + graph.tickPoints(true); -// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && AllKeys.altDown()) + tickTrains(level); + + for (TrackGraph graph : trackNetworks.values()) + graph.tickPoints(false); + +// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_K)) // trackNetworks.values() -// .forEach(TrackGraph::debugViewSignalData); +// .forEach(TrackGraph::debugViewReserved); // if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown()) // trackNetworks.values() // .forEach(TrackGraph::debugViewNodes); } + private void tickTrains(Level level) { + // keeping two lists ensures a tick order starting at longest waiting + for (Train train : waitingTrains) + train.earlyTick(level); + for (Train train : movingTrains) + train.earlyTick(level); + for (Train train : waitingTrains) + train.tick(level); + for (Train train : movingTrains) + train.tick(level); + + for (Iterator iterator = waitingTrains.iterator(); iterator.hasNext();) { + Train train = iterator.next(); + if (train.navigation.waitingForSignal != null) + continue; + movingTrains.add(train); + iterator.remove(); + } + + for (Iterator iterator = movingTrains.iterator(); iterator.hasNext();) { + Train train = iterator.next(); + if (train.navigation.waitingForSignal == null) + continue; + waitingTrains.add(train); + iterator.remove(); + } + } + public void clientTick() { if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown()) trackNetworks.values() diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java index 25f04eb2d..60a8fd816 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/TrackGraph.java @@ -98,8 +98,8 @@ public class TrackGraph { return removed; } - public void tickPoints() { - edgePoints.tick(this); + public void tickPoints(boolean preTrains) { + edgePoints.tick(this, preTrains); } // @@ -425,6 +425,129 @@ public class TrackGraph { return graph; } + public void debugViewReserved() { + Entity cameraEntity = Minecraft.getInstance().cameraEntity; + if (cameraEntity == null) + return; + + Set reserved = new HashSet<>(); + Set occupied = new HashSet<>(); + + for (Train train : Create.RAILWAYS.trains.values()) { + reserved.addAll(train.reservedSignalBlocks); + occupied.addAll(train.occupiedSignalBlocks.keySet()); + } + + reserved.removeAll(occupied); + + Vec3 camera = cameraEntity.getEyePosition(); + for (Entry nodeEntry : nodes.entrySet()) { + TrackNodeLocation nodeLocation = nodeEntry.getKey(); + TrackNode node = nodeEntry.getValue(); + if (nodeLocation == null) + continue; + + Vec3 location = nodeLocation.getLocation(); + if (location.distanceTo(camera) > 100) + continue; + + Map map = connectionsByNode.get(node); + if (map == null) + continue; + + int hashCode = node.hashCode(); + for (Entry entry : map.entrySet()) { + TrackNode other = entry.getKey(); + + if (other.hashCode() > hashCode && !AllKeys.isKeyDown(GLFW.GLFW_KEY_LEFT_CONTROL)) + continue; + Vec3 yOffset = new Vec3(0, (other.hashCode() > hashCode ? 6 : 4) / 16f, 0); + + TrackEdge edge = entry.getValue(); + EdgeData signalData = edge.getEdgeData(); + UUID singleGroup = signalData.singleSignalGroup; + SignalEdgeGroup signalEdgeGroup = + singleGroup == null ? null : Create.RAILWAYS.sided(null).signalEdgeGroups.get(singleGroup); + + if (!edge.isTurn()) { + Vec3 p1 = edge.getPosition(node, other, 0); + Vec3 p2 = edge.getPosition(node, other, 1); + + if (signalData.hasPoints()) { + double prev = 0; + double length = edge.getLength(node, other); + SignalBoundary prevBoundary = null; + SignalEdgeGroup group = null; + + for (TrackEdgePoint trackEdgePoint : signalData.getPoints()) { + if (!(trackEdgePoint instanceof SignalBoundary boundary)) + continue; + + prevBoundary = boundary; + UUID groupId = boundary.getGroup(node); + group = Create.RAILWAYS.sided(null).signalEdgeGroups.get(groupId); + double start = prev + (prev == 0 ? 0 : 1 / 16f / length); + prev = (boundary.getLocationOn(node, other, edge) / length) - 1 / 16f / length; + + if (group != null + && (group.reserved != null || occupied.contains(groupId) || reserved.contains(groupId))) + CreateClient.OUTLINER + .showLine(Pair.of(boundary, edge), edge.getPosition(node, other, start) + .add(yOffset), + edge.getPosition(node, other, prev) + .add(yOffset)) + .colored(occupied.contains(groupId) ? 0xF68989 + : group.reserved != null ? 0xC5D8A4 : 0xF6E7D8) + .lineWidth(1 / 16f); + + } + + if (prevBoundary != null) { + UUID groupId = prevBoundary.getGroup(other); + SignalEdgeGroup lastGroup = Create.RAILWAYS.sided(null).signalEdgeGroups.get(groupId); + if (lastGroup != null && ((lastGroup.reserved != null || occupied.contains(groupId) + || reserved.contains(groupId)))) + CreateClient.OUTLINER + .showLine(edge, edge.getPosition(node, other, prev + 1 / 16f / length) + .add(yOffset), p2.add(yOffset)) + .colored(occupied.contains(groupId) ? 0xF68989 + : lastGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8) + .lineWidth(1 / 16f); + continue; + } + } + + if (signalEdgeGroup == null || !(signalEdgeGroup.reserved != null || occupied.contains(singleGroup) + || reserved.contains(singleGroup))) + continue; + CreateClient.OUTLINER.showLine(edge, p1.add(yOffset), p2.add(yOffset)) + .colored(occupied.contains(singleGroup) ? 0xF68989 + : signalEdgeGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8) + .lineWidth(1 / 16f); + continue; + } + + if (signalEdgeGroup == null || !(signalEdgeGroup.reserved != null || occupied.contains(singleGroup) + || reserved.contains(singleGroup))) + continue; + + int color = + occupied.contains(singleGroup) ? 0xF68989 : signalEdgeGroup.reserved != null ? 0xC5D8A4 : 0xF6E7D8; + Vec3 previous = null; + BezierConnection turn = edge.getTurn(); + for (int i = 0; i <= turn.getSegmentCount(); i++) { + Vec3 current = edge.getPosition(node, other, i * 1f / turn.getSegmentCount()); + if (previous != null) + CreateClient.OUTLINER + .showLine(Pair.of(edge, previous), previous.add(yOffset), current.add(yOffset)) + .colored(color) + .lineWidth(1 / 16f); + previous = current; + } + } + } + } + public void debugViewSignalData() { Entity cameraEntity = Minecraft.getInstance().cameraEntity; if (cameraEntity == null) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java index 509633476..d8d1b37c2 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Carriage.java @@ -11,7 +11,7 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.mutable.MutableDouble; import com.simibubi.create.content.logistics.trains.TrackGraph; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ISignalBoundaryListener; +import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; @@ -131,9 +131,9 @@ public class Carriage { boolean atBack = (type == LAST || type == BOTH) && !actuallyFirstWheel && (!actuallyFirstBogey || !onTwoBogeys); - ISignalBoundaryListener frontListener = train.frontSignalListener(); - ISignalBoundaryListener backListener = train.backSignalListener(); - ISignalBoundaryListener passiveListener = point.ignoreSignals(); + IEdgePointListener frontListener = train.frontSignalListener(); + IEdgePointListener backListener = train.backSignalListener(); + IEdgePointListener passiveListener = point.ignoreEdgePoints(); toMove += correction + bogeyCorrection; double moved = diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java index ad9824632..4d15a4f04 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/CarriageSyncData.java @@ -239,7 +239,7 @@ public class CarriageSyncData { TravellingPoint toApproach = pointsToApproach[index]; point.travel(graph, partial * f, - point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)), point.ignoreSignals(), + point.follow(toApproach, b -> success.setValue(success.booleanValue() && b)), point.ignoreEdgePoints(), point.ignoreTurns()); // could not pathfind to server location diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java index 7af3adb53..180ce6a04 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Navigation.java @@ -24,6 +24,7 @@ import com.simibubi.create.content.logistics.trains.TrackNodeLocation; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; +import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; @@ -52,6 +53,7 @@ public class Navigation { private TravellingPoint signalScout; public Pair waitingForSignal; + private Set waitingForChainedGroups; public double distanceToSignal; public int ticksWaitingForSignal; @@ -59,6 +61,7 @@ public class Navigation { this.train = train; currentPath = new ArrayList<>(); signalScout = new TravellingPoint(); + waitingForChainedGroups = new HashSet<>(); } public void tick(Level level) { @@ -97,8 +100,13 @@ public class Navigation { // Signals if (train.graph != null) { - if (waitingForSignal != null && checkBlockingSignal()) + if (waitingForSignal != null && currentSignalResolved()) { + SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst()); + if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) + train.reservedSignalBlocks.addAll(waitingForChainedGroups); waitingForSignal = null; + waitingForChainedGroups.clear(); + } TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0) .getLeadingPoint() @@ -120,49 +128,103 @@ public class Navigation { double brakingDistanceNoFlicker = Math.max(preDepartureLookAhead, brakingDistance + 3 - (brakingDistance % 3)); - double scanDistance = Math.min(distanceToDestination - .5f, brakingDistanceNoFlicker); + double scanDistance = Math.min(distanceToDestination, brakingDistanceNoFlicker); - signalScout.travel(train.graph, scanDistance * speedMod, controlSignalScout(), (distance, couple) -> { - UUID entering = couple.getSecond() - .getSecond(); - SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(entering); - if (signalEdgeGroup == null) - return; - SignalBoundary boundary = couple.getFirst(); - if (signalEdgeGroup.isOccupiedUnless(train)) { - distanceToSignal = Math.min(distance, distanceToSignal); - waitingForSignal = Pair.of(boundary.id, entering.equals(boundary.groups.getFirst())); - return; + MutableDouble crossSignalDistanceTracker = new MutableDouble(-1); + MutableObject> trackingCrossSignal = new MutableObject<>(null); + waitingForChainedGroups.clear(); +// train.reservedSignalBlocks.clear(); + + signalScout.travel(train.graph, distanceToDestination * speedMod, controlSignalScout(), + (distance, couple) -> { + // > scanDistance and not following down a cross signal + boolean crossSignalTracked = trackingCrossSignal.getValue() != null; + if (!crossSignalTracked && distance > scanDistance) + return true; + + Couple nodes = couple.getSecond(); + TrackEdgePoint boundary = couple.getFirst(); + if (boundary == destination && ((GlobalStation) boundary).canApproachFrom(nodes.getSecond())) + return true; + if (!(boundary instanceof SignalBoundary signal)) + return false; + + UUID entering = signal.getGroup(nodes.getSecond()); + SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(entering); + if (signalEdgeGroup == null) + return false; + + boolean primary = entering.equals(signal.groups.getFirst()); + boolean crossSignal = signal.types.get(primary) == SignalType.CROSS_SIGNAL; + boolean occupied = signalEdgeGroup.isOccupiedUnless(train); + + if (!occupied && distance < distanceToSignal + .25) + signalEdgeGroup.reserved = signal; // Reserve group for traversal, unless waiting at an + // earlier cross signal + + if (!crossSignalTracked) { + if (crossSignal) { // Now entering cross signal path + trackingCrossSignal.setValue(Pair.of(boundary.id, primary)); + crossSignalDistanceTracker.setValue(distance); + waitingForChainedGroups.add(entering); + } + if (occupied) { // Section is occupied + waitingForSignal = Pair.of(boundary.id, primary); + distanceToSignal = distance; + if (!crossSignal) + return true; // Standard entry signal, do not collect any further segments + } + } else { + waitingForChainedGroups.add(entering); // Add group to chain + if (occupied) { // Section is occupied, but wait at the cross signal that started the chain + waitingForSignal = trackingCrossSignal.getValue(); + distanceToSignal = crossSignalDistanceTracker.doubleValue(); + if (!crossSignal) + return true; // Entry signals end a chain + } + if (!crossSignal) { + if (distance < distanceToSignal + .25) { + // Collect and reset the signal chain because none were blocked + trackingCrossSignal.setValue(null); + train.reservedSignalBlocks.addAll(waitingForChainedGroups); + waitingForChainedGroups.clear(); + return false; + } else + return true; // End of a blocked signal chain + } + } + + return false; + + }, (distance, edge) -> { + float current = curveDistanceTracker.floatValue(); + if (current == -1 || distance < current) + curveDistanceTracker.setValue(distance); + }); + + if (trackingCrossSignal.getValue() != null) { + if (waitingForSignal == null) { + train.reservedSignalBlocks.addAll(waitingForChainedGroups); + waitingForChainedGroups.clear(); } - signalEdgeGroup.reserved = boundary; - }, (distance, edge) -> { - float current = curveDistanceTracker.floatValue(); - if (current == -1 || distance < current) - curveDistanceTracker.setValue(distance); - }); + } distanceToNextCurve = curveDistanceTracker.floatValue(); + } else { ticksWaitingForSignal++; + // if chain signal try finding new path/destination every x ticks } } double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination; - if (targetDistance < 1 / 32f) { - train.speed = 0; - if (waitingForSignal != null) { - distanceToSignal = 0; - return; - } - distanceToDestination = 0; - currentPath.clear(); - train.arriveAt(destination); - destination = null; - return; - } else if (train.getCurrentStation() != null) { - // dont leave until green light + // always overshoot to ensure the travelling point crosses the target + targetDistance += 0.25d; + + // dont leave until green light + if (targetDistance > 1 / 32f && train.getCurrentStation() != null) { if (waitingForSignal != null && distanceToSignal < preDepartureLookAhead) return; train.leaveStation(); @@ -170,8 +232,13 @@ public class Navigation { train.currentlyBackwards = destinationBehindTrain; + if (targetDistance < -10) { + cancelNavigation(); + return; + } + if (targetDistance - Math.abs(train.speed) < 1 / 32f) { - train.speed = targetDistance * speedMod; + train.speed = Math.max(targetDistance, 1 / 32f) * speedMod; return; } @@ -198,12 +265,26 @@ public class Navigation { train.approachTargetSpeed(1); } - private boolean checkBlockingSignal() { + private boolean currentSignalResolved() { if (distanceToDestination < .5f) return true; SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst()); if (signal == null) return true; + + // Cross Signal + if (signal.types.get(waitingForSignal.getSecond()) == SignalType.CROSS_SIGNAL) { + for (UUID groupId : waitingForChainedGroups) { + SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); + if (signalEdgeGroup == null) + continue; + if (signalEdgeGroup.isOccupiedUnless(train)) + return false; + } + return true; + } + + // Entry Signal UUID groupId = signal.groups.get(waitingForSignal.getSecond()); if (groupId == null) return true; @@ -255,6 +336,7 @@ public class Navigation { destination.cancelReservation(train); destination = null; train.runtime.transitInterrupted(); + train.reservedSignalBlocks.clear(); } public double startNavigation(GlobalStation destination, double maxCost, boolean simulate) { @@ -267,16 +349,19 @@ public class Navigation { return cost; distanceToDestination = distance; - currentPath = pathTo.path; if (noneFound) { distanceToDestination = 0; + currentPath = new ArrayList<>(); if (this.destination != null) cancelNavigation(); return -1; } + currentPath = pathTo.path; destinationBehindTrain = pathTo.distance < 0; + train.reservedSignalBlocks.clear(); + train.navigation.waitingForSignal = null; if (this.destination == destination) return 0; @@ -315,7 +400,9 @@ public class Navigation { Couple results = Couple.create(null, null); for (boolean forward : Iterate.trueAndFalse) { - if (this.destination == destination && destinationBehindTrain == forward) + + // When updating destinations midtransit, avoid reversing out of path + if (this.destination != null && destinationBehindTrain == forward) continue; TravellingPoint initialPoint = forward ? train.carriages.get(0) @@ -377,6 +464,9 @@ public class Navigation { if (!canDriveForward) return back; +// Debug.debugChat("Front: " + front.distance + ", Back: " + back.distance); +// Debug.debugChat("FrontCost: " + front.cost + ", BackCost: " + back.cost); + boolean frontBetter = maxCost == -1 ? -back.distance > front.distance : back.cost > front.cost; return frontBetter ? front : back; } @@ -438,6 +528,8 @@ public class Navigation { for (Train otherTrain : Create.RAILWAYS.trains.values()) { if (otherTrain.graph != graph) continue; + if (otherTrain == train) + continue; int navigationPenalty = otherTrain.getNavigationPenalty(); otherTrain.getEndpointEdges() .forEach(nodes -> { @@ -474,6 +566,8 @@ public class Navigation { Search: while (!frontier.isEmpty()) { FrontierEntry entry = frontier.poll(); + if (!visited.add(entry.edge)) + continue; double distance = entry.distance; int penalty = entry.penalty; @@ -499,12 +593,15 @@ public class Navigation { if (!point.canNavigateVia(node2)) continue Search; if (point instanceof GlobalStation station) { - if (station.getPresentTrain() != null) + Train presentTrain = station.getPresentTrain(); + boolean isOwnStation = presentTrain == train; + if (presentTrain != null && !isOwnStation) penalty += Train.Penalties.STATION_WITH_TRAIN; if (station.canApproachFrom(node2) && stationTest.test(distance, distance + penalty, reachedVia, Pair.of(Couple.create(node1, node2), edge), station)) return; - penalty += Train.Penalties.STATION; + if (!isOwnStation) + penalty += Train.Penalties.STATION; } } } @@ -521,8 +618,6 @@ public class Navigation { Vec3 newDirection = newEdge.getDirection(node2, newNode, true); if (currentDirection.dot(newDirection) < 3 / 4f) continue; - if (!visited.add(connection.getValue())) - continue; validTargets.add(connection); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java index 5ba66432e..d101d6c2f 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/Train.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.logistics.trains.entity; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -23,11 +24,12 @@ import com.simibubi.create.content.logistics.trains.GraphLocation; import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ISignalBoundaryListener; +import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; 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.edgePoint.EdgeData; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; +import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup; import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation; @@ -82,7 +84,8 @@ public class Train { public List carriageSpacing; public boolean updateSignalBlocks; - public List occupiedSignalBlocks; + public Map occupiedSignalBlocks; + public Set reservedSignalBlocks; List migratingPoints; public int migrationCooldown; @@ -112,28 +115,35 @@ public class Train { migratingPoints = new ArrayList<>(); currentStation = null; manualSteer = SteerDirection.NONE; - occupiedSignalBlocks = new ArrayList<>(); + occupiedSignalBlocks = new HashMap<>(); + reservedSignalBlocks = new HashSet<>(); } public void earlyTick(Level level) { status.tick(level); if (graph == null && !migratingPoints.isEmpty()) reattachToTracks(level); + + addToSignalGroups(occupiedSignalBlocks.keySet()); + if (graph == null) return; - if (updateSignalBlocks) { updateSignalBlocks = false; collectInitiallyOccupiedSignalBlocks(); } - for (Iterator iterator = occupiedSignalBlocks.iterator(); iterator.hasNext();) { - SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(iterator.next()); - if (signalEdgeGroup == null) { + addToSignalGroups(reservedSignalBlocks); + } + + private void addToSignalGroups(Collection groups) { + Map groupMap = Create.RAILWAYS.signalEdgeGroups; + for (Iterator iterator = groups.iterator(); iterator.hasNext();) { + SignalEdgeGroup signalEdgeGroup = groupMap.get(iterator.next()); + if (signalEdgeGroup == null) iterator.remove(); - continue; - } - signalEdgeGroup.trains.add(this); + else + signalEdgeGroup.trains.add(this); } } @@ -212,6 +222,8 @@ public class Train { if (index == 0) { distance = actualDistance; collideWithOtherTrains(level, carriage); + if (graph == null) + return; } } @@ -226,23 +238,58 @@ public class Train { updateNavigationTarget(distance); } - public ISignalBoundaryListener frontSignalListener() { + public IEdgePointListener frontSignalListener() { return (distance, couple) -> { - UUID groupId = couple.getSecond() - .getSecond(); - SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); - SignalBoundary boundary = couple.getFirst(); - if (signalEdgeGroup != null) { - signalEdgeGroup.reserved = boundary; - occupiedSignalBlocks.add(groupId); + + if (couple.getFirst()instanceof GlobalStation station) { + if (!station.canApproachFrom(couple.getSecond() + .getSecond()) || navigation.destination != station) + return false; + speed = 0; + navigation.distanceToDestination = 0; + navigation.currentPath.clear(); + arriveAt(navigation.destination); + navigation.destination = null; + return true; } + + if (!(couple.getFirst()instanceof SignalBoundary signal)) + return false; + if (navigation.waitingForSignal != null && navigation.waitingForSignal.getFirst() + .equals(signal.id)) { + speed = 0; + navigation.distanceToSignal = 0; + return true; + } + + UUID groupId = signal.getGroup(couple.getSecond() + .getSecond()); + SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId); + if (signalEdgeGroup == null) + return false; + signalEdgeGroup.reserved = signal; + occupy(groupId, signal.id); + return false; + }; } - public ISignalBoundaryListener backSignalListener() { + private boolean occupy(UUID groupId, @Nullable UUID boundaryId) { + reservedSignalBlocks.remove(groupId); + if (boundaryId != null && occupiedSignalBlocks.containsKey(groupId)) + if (boundaryId.equals(occupiedSignalBlocks.get(groupId))) + return false; + return occupiedSignalBlocks.put(groupId, boundaryId) == null; + } + + public IEdgePointListener backSignalListener() { return (distance, couple) -> { - occupiedSignalBlocks.remove(couple.getSecond() + if (!(couple.getFirst()instanceof SignalBoundary signal)) + return false; + UUID groupId = signal.getGroup(couple.getSecond() .getFirst()); + occupiedSignalBlocks.remove(groupId); + return false; }; } @@ -250,32 +297,43 @@ public class Train { if (navigation.destination == null) return; - boolean recalculate = navigation.distanceToDestination % 100 > 20; - boolean imminentRecalculate = navigation.distanceToDestination > 5; + Pair blockingSignal = navigation.waitingForSignal; + boolean fullRefresh = navigation.distanceToDestination > 100 && navigation.distanceToDestination % 100 > 20; + boolean signalRefresh = blockingSignal != null && navigation.distanceToSignal % 50 > 5; + boolean partialRefresh = navigation.distanceToDestination < 100 && navigation.distanceToDestination % 50 > 5; + double toSubstract = navigation.destinationBehindTrain ? -distance : distance; - navigation.distanceToDestination -= toSubstract; - boolean signalMode = navigation.waitingForSignal != null; boolean navigatingManually = runtime.paused; - if (signalMode) { + navigation.distanceToDestination -= toSubstract; + if (blockingSignal != null) { navigation.distanceToSignal -= toSubstract; - recalculate = navigation.distanceToSignal % 100 > 20; + signalRefresh &= navigation.distanceToSignal % 50 < 5; } - if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20 - || imminentRecalculate && navigation.distanceToDestination <= 5) { - if (signalMode) { - navigation.waitingForSignal = null; - return; - } - GlobalStation destination = navigation.destination; - if (!navigatingManually) { - GlobalStation preferredDestination = runtime.findNextStation(); - if (preferredDestination != null) - destination = preferredDestination; - } - navigation.startNavigation(destination, navigatingManually ? -1 : Double.MAX_VALUE, false); + fullRefresh &= navigation.distanceToDestination % 100 <= 20; + partialRefresh &= navigation.distanceToDestination % 50 <= 5; + + if (blockingSignal != null && navigation.ticksWaitingForSignal % 100 == 50) { + SignalBoundary signal = graph.getPoint(EdgePointType.SIGNAL, blockingSignal.getFirst()); + fullRefresh |= signal != null && signal.types.get(blockingSignal.getSecond()) == SignalType.CROSS_SIGNAL; } + + if (signalRefresh) + navigation.waitingForSignal = null; + if (!fullRefresh && !partialRefresh) + return; + if (!reservedSignalBlocks.isEmpty()) + return; + + GlobalStation destination = navigation.destination; + if (!navigatingManually && fullRefresh) { + GlobalStation preferredDestination = runtime.findNextStation(); + if (preferredDestination != null) + destination = preferredDestination; + } + + navigation.startNavigation(destination, navigatingManually ? -1 : Double.MAX_VALUE, false); } private void tickDerailedSlowdown() { @@ -439,7 +497,7 @@ public class Train { if (currentStation != null) currentStation.cancelReservation(this); - Create.RAILWAYS.trains.remove(id); + Create.RAILWAYS.removeTrain(id); AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false)); return true; } @@ -598,6 +656,7 @@ public class Train { public void arriveAt(GlobalStation station) { setCurrentStation(station); + reservedSignalBlocks.clear(); runtime.destinationReached(); } @@ -645,6 +704,7 @@ public class Train { EdgeData signalData = edge.getEdgeData(); occupiedSignalBlocks.clear(); + reservedSignalBlocks.clear(); TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position); Map allGroups = Create.RAILWAYS.signalEdgeGroups; @@ -664,7 +724,7 @@ public class Train { if (prev != null) { UUID group = prev.getGroup(node2); if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) { - occupiedSignalBlocks.add(group); + occupy(group, null); prevGroup.setValue(group); } } @@ -672,26 +732,32 @@ public class Train { } else { UUID group = nextBoundary.getGroup(node1); if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) { - occupiedSignalBlocks.add(group); + occupy(group, null); prevGroup.setValue(group); } } } else if (signalData.singleSignalGroup != null && allGroups.containsKey(signalData.singleSignalGroup)) { - occupiedSignalBlocks.add(signalData.singleSignalGroup); + occupy(signalData.singleSignalGroup, null); prevGroup.setValue(signalData.singleSignalGroup); } forEachTravellingPointBackwards((tp, d) -> { - signalScout.travel(graph, d, signalScout.follow(tp), (distance, couple) -> couple.getSecond() - .forEach(id -> { - if (!Create.RAILWAYS.signalEdgeGroups.containsKey(id)) - return; - if (id.equals(prevGroup.getValue())) - return; - occupiedSignalBlocks.add(id); - prevGroup.setValue(id); - }), signalScout.ignoreTurns()); + signalScout.travel(graph, d, signalScout.follow(tp), (distance, couple) -> { + if (!(couple.getFirst()instanceof SignalBoundary signal)) + return false; + couple.getSecond() + .map(signal::getGroup) + .forEach(id -> { + if (!Create.RAILWAYS.signalEdgeGroups.containsKey(id)) + return; + if (id.equals(prevGroup.getValue())) + return; + occupy(id, null); + prevGroup.setValue(id); + }); + return false; + }, signalScout.ignoreTurns()); }); } @@ -740,7 +806,14 @@ public class Train { tag.putBoolean("StillAssembling", heldForAssembly); tag.putBoolean("Derailed", derailed); tag.putBoolean("UpdateSignals", updateSignalBlocks); - tag.put("SignalBlocks", NBTHelper.writeCompoundList(occupiedSignalBlocks, uid -> { + tag.put("SignalBlocks", NBTHelper.writeCompoundList(occupiedSignalBlocks.entrySet(), e -> { + CompoundTag compoundTag = new CompoundTag(); + compoundTag.putUUID("Id", e.getKey()); + if (e.getValue() != null) + compoundTag.putUUID("Boundary", e.getValue()); + return compoundTag; + })); + tag.put("ReservedSignalBlocks", NBTHelper.writeCompoundList(reservedSignalBlocks, uid -> { CompoundTag compoundTag = new CompoundTag(); compoundTag.putUUID("Id", uid); return compoundTag; @@ -778,9 +851,10 @@ public class Train { train.derailed = tag.getBoolean("Derailed"); train.updateSignalBlocks = tag.getBoolean("UpdateSignals"); - NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), - c -> train.occupiedSignalBlocks.add(c.getUUID("Id"))); - + NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks + .put(c.getUUID("Id"), c.contains("Boundary") ? c.getUUID("Boundary") : null)); + NBTHelper.iterateCompoundList(tag.getList("ReservedSignalBlocks", Tag.TAG_COMPOUND), + c -> train.reservedSignalBlocks.add(c.getUUID("Id"))); NBTHelper.iterateCompoundList(tag.getList("MigratingPoints", Tag.TAG_COMPOUND), c -> train.migratingPoints.add(TrainMigration.read(c))); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java index 2fbfd881b..a65a369f6 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TrainRelocator.java @@ -22,7 +22,7 @@ import com.simibubi.create.content.logistics.trains.TrackEdge; import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackGraphHelper; import com.simibubi.create.content.logistics.trains.TrackNode; -import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ISignalBoundaryListener; +import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.IEdgePointListener; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITrackSelector; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener; import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection; @@ -158,7 +158,7 @@ public class TrainRelocator { return false; TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position); - ISignalBoundaryListener ignoreSignals = probe.ignoreSignals(); + IEdgePointListener ignoreSignals = probe.ignoreEdgePoints(); ITurnListener ignoreTurns = probe.ignoreTurns(); List, Double>> recordedLocations = new ArrayList<>(); List recordedVecs = new ArrayList<>(); @@ -206,6 +206,7 @@ public class TrainRelocator { train.leaveStation(); train.derailed = false; + train.heldForAssembly = false; train.navigation.waitingForSignal = null; train.occupiedSignalBlocks.clear(); train.graph = graph; @@ -322,13 +323,12 @@ public class TrainRelocator { @OnlyIn(Dist.CLIENT) public static boolean carriageWrenched(Vec3 vec3, CarriageContraptionEntity entity) { Train train = getTrainFromEntity(entity); - if (train != null && !train.heldForAssembly) { - relocatingOrigin = vec3; - relocatingTrain = train.id; - relocatingEntityId = entity.getId(); - return true; - } - return false; + if (train == null) + return false; + relocatingOrigin = vec3; + relocatingTrain = train.id; + relocatingEntityId = entity.getId(); + return true; } @OnlyIn(Dist.CLIENT) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java index 6b8b2d307..833bf1614 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/entity/TravellingPoint.java @@ -6,10 +6,10 @@ import java.util.List; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; -import java.util.UUID; import java.util.Vector; import java.util.function.BiConsumer; import java.util.function.BiFunction; +import java.util.function.BiPredicate; import java.util.function.Consumer; import javax.annotation.Nullable; @@ -21,8 +21,7 @@ import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackNode; import com.simibubi.create.content.logistics.trains.TrackNodeLocation; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData; -import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; -import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary; +import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint; import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Pair; @@ -53,7 +52,7 @@ public class TravellingPoint { extends BiFunction>>, Entry> { }; - public static interface ISignalBoundaryListener extends BiConsumer>> { + public static interface IEdgePointListener extends BiPredicate>> { }; public static interface ITurnListener extends BiConsumer { @@ -68,9 +67,8 @@ public class TravellingPoint { this.position = position; } - public ISignalBoundaryListener ignoreSignals() { - return (d, c) -> { - }; + public IEdgePointListener ignoreEdgePoints() { + return (d, c) -> false; } public ITurnListener ignoreTurns() { @@ -178,7 +176,7 @@ public class TravellingPoint { } public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector, - ISignalBoundaryListener signalListener, ITurnListener turnListener) { + IEdgePointListener signalListener, ITurnListener turnListener) { blocked = false; double edgeLength = edge.getLength(node1, node2); if (distance == 0) @@ -193,7 +191,14 @@ public class TravellingPoint { boolean forward = distance > 0; double collectedDistance = forward ? -prevPos : -edgeLength + prevPos; - edgeTraversedFrom(graph, forward, signalListener, turnListener, prevPos, collectedDistance); + + Double blockedLocation = + edgeTraversedFrom(graph, forward, signalListener, turnListener, prevPos, collectedDistance); + if (blockedLocation != null) { + position = blockedLocation.doubleValue(); + traveled = position - prevPos; + return traveled; + } if (forward) { // Moving forward @@ -233,9 +238,17 @@ public class TravellingPoint { collectedDistance += edgeLength; if (edge.isTurn()) turnListener.accept(collectedDistance, edge); - edgeTraversedFrom(graph, forward, signalListener, turnListener, 0, collectedDistance); - prevPos = 0; + blockedLocation = edgeTraversedFrom(graph, forward, signalListener, turnListener, 0, collectedDistance); + + if (blockedLocation != null) { + traveled -= position; + position = blockedLocation.doubleValue(); + traveled += position; + break; + } + + prevPos = 0; edgeLength = edge.getLength(node1, node2); } @@ -261,7 +274,7 @@ public class TravellingPoint { } if (validTargets.isEmpty()) { - traveled -= position; + traveled += position; position = 0; blocked = true; break; @@ -278,7 +291,15 @@ public class TravellingPoint { edgeLength = edge.getLength(node1, node2); position += edgeLength; - edgeTraversedFrom(graph, forward, signalListener, turnListener, edgeLength, collectedDistance); + blockedLocation = + edgeTraversedFrom(graph, forward, signalListener, turnListener, edgeLength, collectedDistance); + + if (blockedLocation != null) { + traveled -= position; + position = blockedLocation.doubleValue(); + traveled += position; + break; + } } } @@ -286,42 +307,30 @@ public class TravellingPoint { return traveled; } - private void edgeTraversedFrom(TrackGraph graph, boolean forward, ISignalBoundaryListener signalListener, + private Double edgeTraversedFrom(TrackGraph graph, boolean forward, IEdgePointListener edgePointListener, ITurnListener turnListener, double prevPos, double totalDistance) { if (edge.isTurn()) turnListener.accept(Math.max(0, totalDistance), edge); - - EdgeData signalsOnEdge = edge.getEdgeData(); - if (!signalsOnEdge.hasSignalBoundaries()) - return; + EdgeData edgeData = edge.getEdgeData(); double from = forward ? prevPos : position; double to = forward ? position : prevPos; - SignalBoundary nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, from); - List discoveredBoundaries = null; + List edgePoints = edgeData.getPoints(); - while (nextBoundary != null) { - double d = nextBoundary.getLocationOn(node1, node2, edge); - if (d > to) - break; - if (discoveredBoundaries == null) - discoveredBoundaries = new ArrayList<>(); - discoveredBoundaries.add(nextBoundary); - nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, d); + double length = edge.getLength(node1, node2); + for (int i = 0; i < edgePoints.size(); i++) { + int index = forward ? i : edgePoints.size() - i - 1; + TrackEdgePoint nextBoundary = edgePoints.get(index); + double locationOn = nextBoundary.getLocationOn(node1, node2, edge); + double distance = forward ? locationOn : length - locationOn; + if (forward ? (locationOn < from || locationOn >= to) : (locationOn <= from || locationOn > to)) + continue; + Couple nodes = Couple.create(node1, node2); + if (edgePointListener.test(totalDistance + distance, Pair.of(nextBoundary, forward ? nodes : nodes.swap()))) + return locationOn; } - if (discoveredBoundaries == null) - return; - - for (int i = 0; i < discoveredBoundaries.size(); i++) { - int index = forward ? i : discoveredBoundaries.size() - i - 1; - nextBoundary = discoveredBoundaries.get(index); - double d = nextBoundary.getLocationOn(node1, node2, edge); - if (!forward) - d = edge.getLength(node1, node2) - d; - Couple nodes = Couple.create(nextBoundary.getGroup(node1), nextBoundary.getGroup(node2)); - signalListener.accept(totalDistance + d, Pair.of(nextBoundary, forward ? nodes : nodes.swap())); - } + return null; } public void reverse(TrackGraph graph) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java index 599f42535..27973def3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgeData.java @@ -70,6 +70,14 @@ public class EdgeData { return null; } + @Nullable + public TrackEdgePoint next(TrackNode node1, TrackNode node2, TrackEdge edge, double minPosition) { + for (TrackEdgePoint point : points) + if (point.getLocationOn(node1, node2, edge) > minPosition) + return point; + return null; + } + @Nullable public T get(EdgePointType type, TrackNode node1, TrackNode node2, TrackEdge edge, double exactPosition) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java index db6c72f23..22de62ca4 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/EdgePointStorage.java @@ -49,10 +49,10 @@ public class EdgePointStorage { return pointsByType.computeIfAbsent(type, t -> new HashMap<>()); } - public void tick(TrackGraph graph) { + public void tick(TrackGraph graph, boolean preTrains) { pointsByType.values() .forEach(map -> map.values() - .forEach(p -> p.tick(graph))); + .forEach(p -> p.tick(graph, preTrains))); } public void transferAll(TrackGraph target, EdgePointStorage other) { diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java index 2db5c4c79..cbb3d6f74 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/TrackTargetingBehaviour.java @@ -143,7 +143,7 @@ public class TrackTargetingBehaviour extends TileEntit } if (!otherPoint.canMerge()) return null; - otherPoint.tileAdded(getPos(), front); + otherPoint.tileAdded(tileEntity, front); id = otherPoint.getId(); tileEntity.setChanged(); return (T) otherPoint; @@ -158,7 +158,7 @@ public class TrackTargetingBehaviour extends TileEntit point.setId(id); point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position); - point.tileAdded(getPos(), front); + point.tileAdded(tileEntity, front); loc.graph.addPoint(edgePointType, point); return point; } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java index 7ad6acbd8..70b06dfe3 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBlock.java @@ -3,21 +3,41 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal import java.util.Random; import com.simibubi.create.AllTileEntities; +import com.simibubi.create.content.contraptions.wrench.IWrenchable; import com.simibubi.create.foundation.block.ITE; +import com.simibubi.create.foundation.utility.Lang; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.StringRepresentable; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.SimpleWaterloggedBlock; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition.Builder; +import net.minecraft.world.level.block.state.properties.EnumProperty; -public class SignalBlock extends Block implements SimpleWaterloggedBlock, ITE { +public class SignalBlock extends Block implements ITE, IWrenchable { + + public static final EnumProperty TYPE = EnumProperty.create("type", SignalType.class); + + public enum SignalType implements StringRepresentable { + ENTRY_SIGNAL, CROSS_SIGNAL; + + @Override + public String getSerializedName() { + return Lang.asId(name()); + } + } public SignalBlock(Properties p_53182_) { super(p_53182_); + registerDefaultState(defaultBlockState().setValue(TYPE, SignalType.ENTRY_SIGNAL)); } @Override @@ -25,11 +45,36 @@ public class SignalBlock extends Block implements SimpleWaterloggedBlock, ITE pBuilder) { + super.createBlockStateDefinition(pBuilder.add(TYPE)); + } + @Override public BlockEntityType getTileEntityType() { return AllTileEntities.TRACK_SIGNAL.get(); } + @Override + public InteractionResult onWrenched(BlockState state, UseOnContext context) { + Level level = context.getLevel(); + BlockPos pos = context.getClickedPos(); + if (level.isClientSide) + return InteractionResult.SUCCESS; + withTileEntityDo(level, pos, ste -> { + SignalBoundary signal = ste.getSignal(); + Player player = context.getPlayer(); + if (signal != null) { + signal.cycleSignalType(pos); + if (player != null) + player.displayClientMessage(Lang.translate("track_signal.mode_change." + signal.getTypeFor(pos) + .getSerializedName()), true); + } else if (player != null) + player.displayClientMessage(Lang.translate("track_signal.cannot_change_mode"), true); + }); + return InteractionResult.SUCCESS; + } + @Override public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) { return side != null; diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java index 291961427..ea0bbc308 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalBoundary.java @@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal import java.util.HashSet; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.UUID; @@ -9,6 +10,8 @@ import com.google.common.base.Objects; import com.simibubi.create.Create; import com.simibubi.create.content.logistics.trains.TrackGraph; import com.simibubi.create.content.logistics.trains.TrackNode; +import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; +import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.OverlayState; import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState; import com.simibubi.create.foundation.utility.Couple; @@ -21,23 +24,32 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; public class SignalBoundary extends TrackEdgePoint { - public Couple> signals; + public Couple> blockEntities; + public Couple types; public Couple groups; public Couple sidesToUpdate; + public Couple cachedStates; + + private Couple> chainedSignals; public SignalBoundary() { - signals = Couple.create(HashSet::new); + blockEntities = Couple.create(HashSet::new); + chainedSignals = Couple.create(null, null); groups = Couple.create(null, null); sidesToUpdate = Couple.create(true, true); + types = Couple.create(() -> SignalType.ENTRY_SIGNAL); + cachedStates = Couple.create(() -> SignalState.GREEN); } public void setGroup(TrackNode side, UUID groupId) { boolean primary = isPrimary(side); groups.set(primary, groupId); sidesToUpdate.set(primary, false); + chainedSignals.set(primary, null); } @Override @@ -47,19 +59,23 @@ public class SignalBoundary extends TrackEdgePoint { @Override public void invalidate(LevelAccessor level) { - signals.forEach(s -> s.forEach(pos -> invalidateAt(level, pos))); + blockEntities.forEach(s -> s.forEach(pos -> invalidateAt(level, pos))); } @Override - public void tileAdded(BlockPos tilePos, boolean front) { - signals.get(front) - .add(tilePos); + public void tileAdded(BlockEntity tile, boolean front) { + Set tilesOnSide = blockEntities.get(front); + if (tilesOnSide.isEmpty()) + tile.getBlockState() + .getOptionalValue(SignalBlock.TYPE) + .ifPresent(type -> types.set(front, type)); + tilesOnSide.add(tile.getBlockPos()); } @Override public void tileRemoved(BlockPos tilePos, boolean front) { - signals.forEach(s -> s.remove(tilePos)); - if (signals.both(Set::isEmpty)) + blockEntities.forEach(s -> s.remove(tilePos)); + if (blockEntities.both(Set::isEmpty)) removeFromAllGraphs(); } @@ -79,16 +95,16 @@ public class SignalBoundary extends TrackEdgePoint { @Override public boolean canNavigateVia(TrackNode side) { - return !signals.get(isPrimary(side)) + return !blockEntities.get(isPrimary(side)) .isEmpty(); } public OverlayState getOverlayFor(BlockPos tile) { for (boolean first : Iterate.trueAndFalse) { - Set set = signals.get(first); + Set set = blockEntities.get(first); for (BlockPos blockPos : set) { if (blockPos.equals(tile)) - return signals.get(!first) + return blockEntities.get(!first) .isEmpty() ? OverlayState.RENDER : OverlayState.DUAL; return OverlayState.SKIP; } @@ -96,58 +112,123 @@ public class SignalBoundary extends TrackEdgePoint { return OverlayState.SKIP; } + public SignalType getTypeFor(BlockPos tile) { + return types.get(blockEntities.getFirst() + .contains(tile)); + } + public SignalState getStateFor(BlockPos tile) { for (boolean first : Iterate.trueAndFalse) { - Set set = signals.get(first); - if (!set.contains(tile)) - continue; - UUID group = groups.get(first); - if (Objects.equal(group, groups.get(!first))) - return SignalState.INVALID; - Map signalEdgeGroups = Create.RAILWAYS.signalEdgeGroups; - SignalEdgeGroup signalEdgeGroup = signalEdgeGroups.get(group); - if (signalEdgeGroup == null) - return SignalState.INVALID; - return signalEdgeGroup.isOccupiedUnless(this) ? SignalState.RED : SignalState.GREEN; + Set set = blockEntities.get(first); + if (set.contains(tile)) + return cachedStates.get(first); } return SignalState.INVALID; } @Override - public void tick(TrackGraph graph) { - super.tick(graph); + public void tick(TrackGraph graph, boolean preTrains) { + super.tick(graph, preTrains); + if (!preTrains) { + tickState(graph); + return; + } for (boolean front : Iterate.trueAndFalse) { if (!sidesToUpdate.get(front)) continue; sidesToUpdate.set(front, false); SignalPropagator.propagateSignalGroup(graph, this, front); + chainedSignals.set(front, null); } } + private void tickState(TrackGraph graph) { + for (boolean current : Iterate.trueAndFalse) { + Set set = blockEntities.get(current); + if (set.isEmpty()) + continue; + + UUID group = groups.get(current); + if (Objects.equal(group, groups.get(!current))) { + cachedStates.set(current, SignalState.INVALID); + continue; + } + + Map signalEdgeGroups = Create.RAILWAYS.signalEdgeGroups; + SignalEdgeGroup signalEdgeGroup = signalEdgeGroups.get(group); + if (signalEdgeGroup == null) { + cachedStates.set(current, SignalState.INVALID); + continue; + } + + boolean occupiedUnlessBySelf = signalEdgeGroup.isOccupiedUnless(this); + cachedStates.set(current, occupiedUnlessBySelf ? SignalState.RED : resolveSignalChain(graph, current)); + } + } + + private SignalState resolveSignalChain(TrackGraph graph, boolean side) { + if (types.get(side) != SignalType.CROSS_SIGNAL) + return SignalState.GREEN; + + if (chainedSignals.get(side) == null) + chainedSignals.set(side, SignalPropagator.collectChainedSignals(graph, this, side)); + + boolean allPathsFree = true; + boolean noPathsFree = true; + boolean invalid = false; + + for (Entry entry : chainedSignals.get(side) + .entrySet()) { + UUID uuid = entry.getKey(); + boolean sideOfOther = entry.getValue(); + SignalBoundary otherSignal = graph.getPoint(EdgePointType.SIGNAL, uuid); + if (otherSignal == null) { + invalid = true; + break; + } + SignalState otherState = otherSignal.cachedStates.get(sideOfOther); + allPathsFree &= otherState == SignalState.GREEN || otherState == SignalState.INVALID; + noPathsFree &= otherState == SignalState.RED; + } + if (invalid) { + chainedSignals.set(side, null); + return SignalState.INVALID; + } + if (allPathsFree) + return SignalState.GREEN; + if (noPathsFree) + return SignalState.RED; + return SignalState.YELLOW; + } + @Override public void read(CompoundTag nbt, boolean migration) { super.read(nbt, migration); - + if (migration) return; - sidesToUpdate = Couple.create(true, true); - signals = Couple.create(HashSet::new); + blockEntities = Couple.create(HashSet::new); groups = Couple.create(null, null); for (int i = 1; i <= 2; i++) if (nbt.contains("Tiles" + i)) { boolean first = i == 1; - NBTHelper.iterateCompoundList(nbt.getList("Tiles" + i, Tag.TAG_COMPOUND), c -> signals.get(first) + NBTHelper.iterateCompoundList(nbt.getList("Tiles" + i, Tag.TAG_COMPOUND), c -> blockEntities.get(first) .add(NbtUtils.readBlockPos(c))); } + for (int i = 1; i <= 2; i++) if (nbt.contains("Group" + i)) groups.set(i == 1, nbt.getUUID("Group" + i)); for (int i = 1; i <= 2; i++) sidesToUpdate.set(i == 1, nbt.contains("Update" + i)); + for (int i = 1; i <= 2; i++) + types.set(i == 1, NBTHelper.readEnum(nbt, "Type" + i, SignalType.class)); + for (int i = 1; i <= 2; i++) + cachedStates.set(i == 1, NBTHelper.readEnum(nbt, "State" + i, SignalState.class)); } - + @Override public void read(FriendlyByteBuf buffer) { super.read(buffer); @@ -161,17 +242,21 @@ public class SignalBoundary extends TrackEdgePoint { public void write(CompoundTag nbt) { super.write(nbt); for (int i = 1; i <= 2; i++) - if (!signals.get(i == 1) + if (!blockEntities.get(i == 1) .isEmpty()) - nbt.put("Tiles" + i, NBTHelper.writeCompoundList(signals.get(i == 1), NbtUtils::writeBlockPos)); + nbt.put("Tiles" + i, NBTHelper.writeCompoundList(blockEntities.get(i == 1), NbtUtils::writeBlockPos)); for (int i = 1; i <= 2; i++) if (groups.get(i == 1) != null) nbt.putUUID("Group" + i, groups.get(i == 1)); for (int i = 1; i <= 2; i++) if (sidesToUpdate.get(i == 1)) nbt.putBoolean("Update" + i, true); + for (int i = 1; i <= 2; i++) + NBTHelper.writeEnum(nbt, "Type" + i, types.get(i == 1)); + for (int i = 1; i <= 2; i++) + NBTHelper.writeEnum(nbt, "State" + i, cachedStates.get(i == 1)); } - + @Override public void write(FriendlyByteBuf buffer) { super.write(buffer); @@ -183,4 +268,9 @@ public class SignalBoundary extends TrackEdgePoint { } } + public void cycleSignalType(BlockPos pos) { + types.set(blockEntities.getFirst() + .contains(pos), SignalType.values()[(getTypeFor(pos).ordinal() + 1) % SignalType.values().length]); + } + } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java index ccb9d1583..09b0fe31b 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalPropagator.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -23,6 +24,8 @@ import com.simibubi.create.foundation.utility.Couple; import com.simibubi.create.foundation.utility.Iterate; import com.simibubi.create.foundation.utility.Pair; +import net.minecraft.world.phys.Vec3; + public class SignalPropagator { public static void onSignalRemoved(TrackGraph graph, SignalBoundary signal) { @@ -38,7 +41,7 @@ public class SignalPropagator { SignalBoundary boundary = pair.getSecond(); boundary.queueUpdate(node1); return false; - }, Predicates.alwaysFalse()); + }, Predicates.alwaysFalse(), false); } } @@ -50,7 +53,7 @@ public class SignalPropagator { SignalBoundary boundary = pair.getSecond(); boundary.queueUpdate(node1); return false; - }, Predicates.alwaysFalse()); + }, Predicates.alwaysFalse(), false); } public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) { @@ -82,11 +85,22 @@ public class SignalPropagator { signalData.singleSignalGroup = groupId; return true; - }); + }, false); + } + + public static Map collectChainedSignals(TrackGraph graph, SignalBoundary signal, boolean front) { + HashMap map = new HashMap<>(); + walkSignals(graph, signal, front, pair -> { + SignalBoundary boundary = pair.getSecond(); + map.put(boundary.id, !boundary.isPrimary(pair.getFirst())); + return false; + }, Predicates.alwaysFalse(), true); + return map; } public static void walkSignals(TrackGraph graph, SignalBoundary signal, boolean front, - Predicate> boundaryCallback, Predicate nonBoundaryCallback) { + Predicate> boundaryCallback, Predicate nonBoundaryCallback, + boolean forCollection) { Couple edgeLocation = signal.edgeLocation; Couple startNodes = edgeLocation.map(graph::locateNode); @@ -101,7 +115,8 @@ public class SignalPropagator { if (startEdge == null) return; - Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge); + if (!forCollection) + Create.RAILWAYS.sync.edgeDataChanged(graph, node1, node2, startEdge, oppositeEdge); // Check for signal on the same edge SignalBoundary immediateBoundary = startEdge.getEdgeData() @@ -115,11 +130,12 @@ public class SignalPropagator { // Search for any connected signals List> frontier = new ArrayList<>(); frontier.add(Couple.create(node2, node1)); - walkSignals(graph, frontier, boundaryCallback, nonBoundaryCallback); + walkSignals(graph, frontier, boundaryCallback, nonBoundaryCallback, forCollection); } private static void walkSignals(TrackGraph graph, List> frontier, - Predicate> boundaryCallback, Predicate nonBoundaryCallback) { + Predicate> boundaryCallback, Predicate nonBoundaryCallback, + boolean forCollection) { Set visited = new HashSet<>(); while (!frontier.isEmpty()) { Couple couple = frontier.remove(0); @@ -138,6 +154,16 @@ public class SignalPropagator { if (!visited.add(edge)) continue; + // chain signal: check if reachable + if (forCollection) { + Vec3 currentDirection = graph.getConnectionsFrom(prevNode) + .get(currentNode) + .getDirection(prevNode, currentNode, false); + Vec3 newDirection = edge.getDirection(currentNode, nextNode, true); + if (currentDirection.dot(newDirection) < 3 / 4f) + continue; + } + TrackEdge oppositeEdge = graph.getConnectionsFrom(nextNode) .get(currentNode); visited.add(oppositeEdge); diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java index 2d01a6298..b50772f23 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SignalTileEntity.java @@ -6,6 +6,7 @@ import javax.annotation.Nullable; import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType; import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour; +import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBlock.SignalType; import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.utility.NBTHelper; @@ -25,19 +26,23 @@ public class SignalTileEntity extends SmartTileEntity { } public static enum SignalState { - RED, GREEN, INVALID, TRAIN_ENTERING; + RED, YELLOW, GREEN, INVALID; public boolean isRedLight(float renderTime) { return this == RED || this == INVALID && renderTime % 40 < 3; } - public boolean isGreenLight(float renderTime) { - return this == GREEN || this == TRAIN_ENTERING; + public boolean isYellowLight(float renderTime) { + return this == YELLOW; + } + + public boolean isGreenLight(float renderTime) { + return this == GREEN; } } public TrackTargetingBehaviour edgePoint; - + private SignalState state; private OverlayState overlay; private int switchToRedAfterTrainEntered; @@ -67,7 +72,7 @@ public class SignalTileEntity extends SmartTileEntity { public SignalBoundary getSignal() { return edgePoint.getEdgePoint(); } - + public boolean isPowered() { return state == SignalState.RED; } @@ -94,12 +99,23 @@ public class SignalTileEntity extends SmartTileEntity { super.tick(); if (level.isClientSide) return; + SignalBoundary boundary = getSignal(); if (boundary == null) { enterState(SignalState.INVALID); setOverlay(OverlayState.RENDER); return; } + + getBlockState().getOptionalValue(SignalBlock.TYPE) + .ifPresent(stateType -> { + SignalType targetType = boundary.getTypeFor(worldPosition); + if (stateType != targetType) { + level.setBlock(worldPosition, getBlockState().setValue(SignalBlock.TYPE, targetType), 3); + refreshBlockState(); + } + }); + enterState(boundary.getStateFor(worldPosition)); setOverlay(boundary.getOverlayFor(worldPosition)); } @@ -127,7 +143,7 @@ public class SignalTileEntity extends SmartTileEntity { if (state == SignalState.RED && switchToRedAfterTrainEntered > 0) return; this.state = state; - switchToRedAfterTrainEntered = state == SignalState.GREEN ? 15 : 0; + switchToRedAfterTrainEntered = state == SignalState.GREEN || state == SignalState.YELLOW ? 15 : 0; notifyUpdate(); scheduleBlockTick(); } diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java index aadf28fd3..10ad13829 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/SingleTileEdgePoint.java @@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; public abstract class SingleTileEdgePoint extends TrackEdgePoint { @@ -14,8 +15,8 @@ public abstract class SingleTileEdgePoint extends TrackEdgePoint { } @Override - public void tileAdded(BlockPos tilePos, boolean front) { - this.tilePos = tilePos; + public void tileAdded(BlockEntity tile, boolean front) { + this.tilePos = tile.getBlockPos(); } @Override diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java index 4959d1a9a..99b519972 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/signal/TrackEdgePoint.java @@ -18,6 +18,7 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.Tag; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.entity.BlockEntity; public abstract class TrackEdgePoint { @@ -59,7 +60,7 @@ public abstract class TrackEdgePoint { behaviour.invalidateEdgePoint(migrationData); } - public abstract void tileAdded(BlockPos tilePos, boolean front); + public abstract void tileAdded(BlockEntity tile, boolean front); public abstract void tileRemoved(BlockPos tilePos, boolean front); @@ -112,7 +113,7 @@ public abstract class TrackEdgePoint { buffer.writeDouble(position); } - public void tick(TrackGraph graph) {} + public void tick(TrackGraph graph, boolean preTrains) {} protected void removeFromAllGraphs() { for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values()) diff --git a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java index ffaef3754..cf0a64464 100644 --- a/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java +++ b/src/main/java/com/simibubi/create/content/logistics/trains/management/edgePoint/station/StationTileEntity.java @@ -496,7 +496,7 @@ public class StationTileEntity extends SmartTileEntity { } train.collectInitiallyOccupiedSignalBlocks(); - Create.RAILWAYS.trains.put(train.id, train); + Create.RAILWAYS.addTrain(train); AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, true)); clearException(); } diff --git a/src/main/resources/assets/create/lang/default/interface.json b/src/main/resources/assets/create/lang/default/interface.json index 7598aa187..f682b6224 100644 --- a/src/main/resources/assets/create/lang/default/interface.json +++ b/src/main/resources/assets/create/lang/default/interface.json @@ -648,6 +648,10 @@ "create.train.relocate.invalid": "Cannot relocate Train to here", "create.train.relocate.too_far": "Cannot relocate Train this far away", + "create.track_signal.cannot_change_mode": "Unable to switch mode of this Signal", + "create.track_signal.mode_change.entry_signal": "-> Allow passage if section unoccupied", + "create.track_signal.mode_change.cross_signal": "-> Allow passage if section fully traversable", + "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", diff --git a/src/main/resources/assets/create/models/block/track_signal/block_cross_signal.json b/src/main/resources/assets/create/models/block/track_signal/block_cross_signal.json new file mode 100644 index 000000000..697b0c780 --- /dev/null +++ b/src/main/resources/assets/create/models/block/track_signal/block_cross_signal.json @@ -0,0 +1,85 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "textures": { + "0": "create:block/chain_signal_box", + "1": "create:block/chain_signal_box_top", + "particle": "create:block/chain_signal_box" + }, + "elements": [ + { + "from": [0, 14, 0], + "to": [16, 16, 16], + "faces": { + "north": {"uv": [0, 0, 16, 2], "texture": "#0"}, + "east": {"uv": [0, 0, 16, 2], "texture": "#0"}, + "south": {"uv": [0, 0, 16, 2], "texture": "#0"}, + "west": {"uv": [0, 0, 16, 2], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [0, 0, 0], + "to": [16, 2, 16], + "faces": { + "north": {"uv": [0, 14, 16, 16], "texture": "#0"}, + "east": {"uv": [0, 14, 16, 16], "texture": "#0"}, + "south": {"uv": [0, 14, 16, 16], "texture": "#0"}, + "west": {"uv": [0, 14, 16, 16], "texture": "#0"}, + "up": {"uv": [0, 0, 16, 16], "texture": "#1"}, + "down": {"uv": [0, 0, 16, 16], "texture": "#1"} + } + }, + { + "from": [1, 2, 1], + "to": [15, 14, 15], + "faces": { + "north": {"uv": [1, 2, 15, 14], "texture": "#0"}, + "east": {"uv": [1, 2, 15, 14], "texture": "#0"}, + "south": {"uv": [1, 2, 15, 14], "texture": "#0"}, + "west": {"uv": [1, 2, 15, 14], "texture": "#0"} + } + }, + { + "from": [13, 2, 13], + "to": [16, 14, 16], + "faces": { + "north": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "east": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "south": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "west": {"uv": [0, 2, 3, 14], "texture": "#0"} + } + }, + { + "from": [0, 2, 0], + "to": [3, 14, 3], + "faces": { + "north": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "east": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "south": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "west": {"uv": [0, 2, 3, 14], "texture": "#0"} + } + }, + { + "from": [13, 2, 0], + "to": [16, 14, 3], + "faces": { + "north": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "east": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "south": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "west": {"uv": [13, 2, 16, 14], "texture": "#0"} + } + }, + { + "from": [0, 2, 13], + "to": [3, 14, 16], + "faces": { + "north": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "east": {"uv": [13, 2, 16, 14], "texture": "#0"}, + "south": {"uv": [0, 2, 3, 14], "texture": "#0"}, + "west": {"uv": [13, 2, 16, 14], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/track_signal/block.json b/src/main/resources/assets/create/models/block/track_signal/block_entry_signal.json similarity index 100% rename from src/main/resources/assets/create/models/block/track_signal/block.json rename to src/main/resources/assets/create/models/block/track_signal/block_entry_signal.json diff --git a/src/main/resources/assets/create/models/block/track_signal/yellow_cube.json b/src/main/resources/assets/create/models/block/track_signal/yellow_cube.json new file mode 100644 index 000000000..49e698307 --- /dev/null +++ b/src/main/resources/assets/create/models/block/track_signal/yellow_cube.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/signal_glow_2", + "particle": "create:block/signal_glow_2" + }, + "elements": [ + { + "from": [-0.5, -0.5, -0.5], + "to": [0.5, 0.5, 0.5], + "faces": { + "north": {"uv": [1, 1, 2, 2], "texture": "#0"}, + "east": {"uv": [1, 1, 2, 2], "texture": "#0"}, + "south": {"uv": [1, 1, 2, 2], "texture": "#0"}, + "west": {"uv": [1, 1, 2, 2], "texture": "#0"}, + "up": {"uv": [1, 1, 2, 2], "texture": "#0"}, + "down": {"uv": [1, 1, 2, 2], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/track_signal/yellow_glow.json b/src/main/resources/assets/create/models/block/track_signal/yellow_glow.json new file mode 100644 index 000000000..231d4961a --- /dev/null +++ b/src/main/resources/assets/create/models/block/track_signal/yellow_glow.json @@ -0,0 +1,21 @@ +{ + "credit": "Made with Blockbench", + "textures": { + "0": "create:block/signal_glow_2", + "particle": "create:block/signal_glow_2" + }, + "elements": [ + { + "from": [-0.5, -0.5, -0.5], + "to": [0.5, 0.5, 0.5], + "faces": { + "north": {"uv": [1, 0, 2, 1], "texture": "#0"}, + "east": {"uv": [1, 0, 2, 1], "texture": "#0"}, + "south": {"uv": [1, 0, 2, 1], "texture": "#0"}, + "west": {"uv": [1, 0, 2, 1], "texture": "#0"}, + "up": {"uv": [1, 0, 2, 1], "texture": "#0"}, + "down": {"uv": [1, 0, 2, 1], "texture": "#0"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/track_signal/yellow_tube.json b/src/main/resources/assets/create/models/block/track_signal/yellow_tube.json new file mode 100644 index 000000000..2aac3c674 --- /dev/null +++ b/src/main/resources/assets/create/models/block/track_signal/yellow_tube.json @@ -0,0 +1,39 @@ +{ + "credit": "Made with Blockbench", + "parent": "block/block", + "ambientocclusion": false, + "textures": { + "2": "create:block/signal_glow_2", + "particle": "create:block/signal_glow_2" + }, + "elements": [ + { + "name": "tube3", + "from": [-3, -4.5, -3], + "to": [3, 4.5, 3], + "rotation": {"angle": 0, "axis": "z", "origin": [8, 8, 8]}, + "faces": { + "north": {"uv": [10, 7, 16, 16], "texture": "#2"}, + "east": {"uv": [10, 7, 16, 16], "texture": "#2"}, + "south": {"uv": [10, 7, 16, 16], "texture": "#2"}, + "west": {"uv": [10, 7, 16, 16], "texture": "#2"}, + "up": {"uv": [10, 0, 16, 6], "rotation": 90, "texture": "#2"}, + "down": {"uv": [10, 0, 16, 6], "rotation": 90, "texture": "#2"} + } + } + ], + "groups": [ + { + "name": "group", + "origin": [17, 14, 13], + "color": 0, + "children": [] + }, + { + "name": "group", + "origin": [17, 14, 13], + "color": 0, + "children": [0] + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/chain_signal_box.png b/src/main/resources/assets/create/textures/block/chain_signal_box.png new file mode 100644 index 000000000..3724d0cbe Binary files /dev/null and b/src/main/resources/assets/create/textures/block/chain_signal_box.png differ diff --git a/src/main/resources/assets/create/textures/block/chain_signal_box_top.png b/src/main/resources/assets/create/textures/block/chain_signal_box_top.png new file mode 100644 index 000000000..b87fa490d Binary files /dev/null and b/src/main/resources/assets/create/textures/block/chain_signal_box_top.png differ diff --git a/src/main/resources/assets/create/textures/block/signal_box_top.png b/src/main/resources/assets/create/textures/block/signal_box_top.png index 44c4ed115..427c6e614 100644 Binary files a/src/main/resources/assets/create/textures/block/signal_box_top.png and b/src/main/resources/assets/create/textures/block/signal_box_top.png differ diff --git a/src/main/resources/assets/create/textures/block/signal_glow_2.png b/src/main/resources/assets/create/textures/block/signal_glow_2.png new file mode 100644 index 000000000..334e7e511 Binary files /dev/null and b/src/main/resources/assets/create/textures/block/signal_glow_2.png differ