Train crash, game crash
- Added a new signal mode for easier junction & platform management - Fixed crash during trains' tick after a collision - Fixed Trains trying to avoid their own carriages in navigation - Fixed Trains trying to avoid their own station in navigation - Fixed Trains triggering signals behind their targeted station - Fixed Trains reversing mid-travel when path cost behind them is lower - Wait time at signals now affects the tick order of Trains - Trains no longer change destination when they are close to arriving at their initial choice - Fixed crashed trains no longer keeping signal blocks occupied - Fixed crash when a trains' path update is unable to find the original destination - Improved precision of trains arriving at signals/stations
This commit is contained in:
parent
71e18eb505
commit
a9a37b313c
48 changed files with 1041 additions and 254 deletions
|
@ -484,7 +484,7 @@ e815bfd854c2653f10828bb11950f7fb991d7efc assets/create/blockstates/stressometer.
|
||||||
8b0c2c7ac72529565b3339aa8df7565858100afa assets/create/blockstates/tiled_glass.json
|
8b0c2c7ac72529565b3339aa8df7565858100afa assets/create/blockstates/tiled_glass.json
|
||||||
a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_pane.json
|
a2454400b1cf9889f70aebdc89c52a1be25f543c assets/create/blockstates/tiled_glass_pane.json
|
||||||
85b57776edf426c2f8df6698b2482ea925914a5c assets/create/blockstates/track.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
|
aa08785f906d41933e0dd1086ea7b08f5b93aa24 assets/create/blockstates/track_station.json
|
||||||
29af21c8d82891139d48d69f0393f612f2b6f8f1 assets/create/blockstates/tuff_pillar.json
|
29af21c8d82891139d48d69f0393f612f2b6f8f1 assets/create/blockstates/tuff_pillar.json
|
||||||
a8094531617e27a545c4815ab2062bf0ffca3633 assets/create/blockstates/turntable.json
|
a8094531617e27a545c4815ab2062bf0ffca3633 assets/create/blockstates/turntable.json
|
||||||
|
@ -541,21 +541,21 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
|
||||||
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
|
||||||
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
|
||||||
255e47ab7894ba35851a2f34c82be3dc9c9e8784 assets/create/lang/en_ud.json
|
255e47ab7894ba35851a2f34c82be3dc9c9e8784 assets/create/lang/en_ud.json
|
||||||
b908dd7c47b286d05a57b8a58c60051363ffff86 assets/create/lang/en_us.json
|
e6698e4672c04cf7b8251e2267b1fe3d6c60e50c assets/create/lang/en_us.json
|
||||||
29ad91d27ee183b9d4de8d152d0fb8ed2a388a0c assets/create/lang/unfinished/de_de.json
|
dfd5234276f508edfb10160fa2b7859363acc313 assets/create/lang/unfinished/de_de.json
|
||||||
8d33ba82d3cca307c5ae0dda41a49ec16f1c7b74 assets/create/lang/unfinished/es_cl.json
|
c23ca905e7aa9983057c970d9e799b4ba91a9acd assets/create/lang/unfinished/es_cl.json
|
||||||
ae674553b564a9e09a7d10c9c2d8c1be1307f40a assets/create/lang/unfinished/es_es.json
|
1781ed3854e04116319528699b4edee9cff4a435 assets/create/lang/unfinished/es_es.json
|
||||||
318149855f383fb90439f2f0818e8e83fee3924e assets/create/lang/unfinished/fr_fr.json
|
24d421795a67a19efd3a092b693c2397b3b84d9b assets/create/lang/unfinished/fr_fr.json
|
||||||
e7321dbe8f98c96e778b5c46823c98500b3001bc assets/create/lang/unfinished/it_it.json
|
50107fc09f422527f20b0a2ddee7e961540e4f6c assets/create/lang/unfinished/it_it.json
|
||||||
5a2da425fd0dd276c3d7cf66f6bb43f229574306 assets/create/lang/unfinished/ja_jp.json
|
570cc561fcb7f1839212e7ba3e1a68886874c846 assets/create/lang/unfinished/ja_jp.json
|
||||||
98fc1956e8b25aec27e889ada3a160800b958dfd assets/create/lang/unfinished/ko_kr.json
|
f5ddd8b98314636c4c763cdd8aee7acd462b00a9 assets/create/lang/unfinished/ko_kr.json
|
||||||
67cefb6690f5cccce93d776a760ebdadc7f2631e assets/create/lang/unfinished/nl_nl.json
|
f3696cf3bfcdff92eb11882be9be9fa2759c51c6 assets/create/lang/unfinished/nl_nl.json
|
||||||
9a7f4d369d2a54aaf5c422fae740244025a13af4 assets/create/lang/unfinished/pl_pl.json
|
3df68a7b3fb44dd666de541d7437c300d596aa7b assets/create/lang/unfinished/pl_pl.json
|
||||||
3656897ffc5c89bf16a32ad11efe33cd5b4bfb23 assets/create/lang/unfinished/pt_br.json
|
6a7fb1146f15117abca1a0ea970ab4054a1ee6a7 assets/create/lang/unfinished/pt_br.json
|
||||||
c84995ec524b6469fc42f39574be21b9dbee24e3 assets/create/lang/unfinished/pt_pt.json
|
6e993c9e6f5faa55448a8b24456082096cb10935 assets/create/lang/unfinished/pt_pt.json
|
||||||
bcf41d9fd8454296dc56326b6e26ee41e2ad52e5 assets/create/lang/unfinished/ru_ru.json
|
d8fc231286d4a53e249037905c92513857432c4c assets/create/lang/unfinished/ru_ru.json
|
||||||
d3dfdab017748fa82f9e952a35bd6e82fe063771 assets/create/lang/unfinished/zh_cn.json
|
3aedca5bf7cf2f08cb53d6e8b5949009cddc1843 assets/create/lang/unfinished/zh_cn.json
|
||||||
dda3aee2ece5503edd53dbd4aa9db7363e4beafc assets/create/lang/unfinished/zh_tw.json
|
30f01dd054c4706d37f6d5ece0fc09ad241a6214 assets/create/lang/unfinished/zh_tw.json
|
||||||
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
|
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
|
||||||
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
|
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
|
||||||
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
|
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
{
|
{
|
||||||
"variants": {
|
"variants": {
|
||||||
"": {
|
"type=entry_signal": {
|
||||||
"model": "create:block/track_signal/block"
|
"model": "create:block/track_signal/block_entry_signal"
|
||||||
|
},
|
||||||
|
"type=cross_signal": {
|
||||||
|
"model": "create:block/track_signal/block_cross_signal"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1424,6 +1424,10 @@
|
||||||
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "Cannot relocate Train this far away",
|
"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.start_controlling": "Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 1435",
|
"_": "Missing Localizations: 1438",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 446",
|
"_": "Missing Localizations: 449",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 446",
|
"_": "Missing Localizations: 449",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 1697",
|
"_": "Missing Localizations: 1700",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 1386",
|
"_": "Missing Localizations: 1389",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 116",
|
"_": "Missing Localizations: 119",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 118",
|
"_": "Missing Localizations: 121",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 2050",
|
"_": "Missing Localizations: 2053",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 485",
|
"_": "Missing Localizations: 488",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 1669",
|
"_": "Missing Localizations: 1672",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 1669",
|
"_": "Missing Localizations: 1672",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 490",
|
"_": "Missing Localizations: 493",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 116",
|
"_": "Missing Localizations: 119",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"_": "Missing Localizations: 504",
|
"_": "Missing Localizations: 507",
|
||||||
|
|
||||||
"_": "->------------------------] Game Elements [------------------------<-",
|
"_": "->------------------------] Game Elements [------------------------<-",
|
||||||
|
|
||||||
|
@ -1425,6 +1425,10 @@
|
||||||
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
"create.train.relocate.invalid": "UNLOCALIZED: Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
"create.train.relocate.too_far": "UNLOCALIZED: Cannot relocate Train this far away",
|
||||||
|
|
||||||
|
"create.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.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -151,6 +151,9 @@ public class AllBlockPartials {
|
||||||
SIGNAL_RED_CUBE = block("track_signal/red_cube"),
|
SIGNAL_RED_CUBE = block("track_signal/red_cube"),
|
||||||
SIGNAL_RED_GLOW = block("track_signal/red_glow"),
|
SIGNAL_RED_GLOW = block("track_signal/red_glow"),
|
||||||
SIGNAL_RED = block("track_signal/red_tube"),
|
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_1x1 = entity("crafting_blueprint_small"),
|
||||||
CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"),
|
CRAFTING_BLUEPRINT_2x2 = entity("crafting_blueprint_medium"),
|
||||||
|
|
|
@ -1336,7 +1336,11 @@ public class AllBlocks {
|
||||||
.initialProperties(SharedProperties::softMetal)
|
.initialProperties(SharedProperties::softMetal)
|
||||||
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
|
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
|
||||||
.transform(pickaxeOnly())
|
.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")
|
.lang("Train Signal")
|
||||||
.item(TrackTargetingBlockItem::new)
|
.item(TrackTargetingBlockItem::new)
|
||||||
.transform(customItemModel())
|
.transform(customItemModel())
|
||||||
|
|
|
@ -177,10 +177,11 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
|
||||||
|
|
||||||
if (first && !te.signalState.isRedLight(renderTime))
|
if (first && !te.signalState.isRedLight(renderTime))
|
||||||
continue;
|
continue;
|
||||||
if (!first && !te.signalState.isGreenLight(renderTime))
|
if (!first && !te.signalState.isGreenLight(renderTime) && !te.signalState.isYellowLight(renderTime))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
boolean flip = first == invertTubes;
|
boolean flip = first == invertTubes;
|
||||||
|
boolean yellow = te.signalState.isYellowLight(renderTime);
|
||||||
|
|
||||||
ms.pushPose();
|
ms.pushPose();
|
||||||
ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0);
|
ms.translate(flip ? 4 / 16f : -4 / 16f, 0, 0);
|
||||||
|
@ -188,22 +189,29 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
|
||||||
if (diff.lengthSqr() < 36 * 36) {
|
if (diff.lengthSqr() < 36 * 36) {
|
||||||
boolean vert = first ^ facing.getAxis()
|
boolean vert = first ^ facing.getAxis()
|
||||||
.isHorizontal();
|
.isHorizontal();
|
||||||
|
float longSide = yellow ? 1 : 4;
|
||||||
|
float longSideGlow = yellow ? 2 : 5.125f;
|
||||||
|
|
||||||
CachedBufferer.partial(AllBlockPartials.SIGNAL_WHITE_CUBE, blockState)
|
CachedBufferer.partial(AllBlockPartials.SIGNAL_WHITE_CUBE, blockState)
|
||||||
.light(0xf000f0)
|
.light(0xf000f0)
|
||||||
.disableDiffuseMult()
|
.disableDiffuseMult()
|
||||||
.scale(vert ? 4 : 1, vert ? 1 : 4, 1)
|
.scale(vert ? longSide : 1, vert ? 1 : longSide, 1)
|
||||||
.renderInto(ms, buffer.getBuffer(RenderType.translucent()));
|
.renderInto(ms, buffer.getBuffer(RenderType.translucent()));
|
||||||
|
|
||||||
CachedBufferer
|
CachedBufferer
|
||||||
.partial(first ? AllBlockPartials.SIGNAL_RED_GLOW : AllBlockPartials.SIGNAL_WHITE_GLOW, blockState)
|
.partial(
|
||||||
|
first ? AllBlockPartials.SIGNAL_RED_GLOW
|
||||||
|
: yellow ? AllBlockPartials.SIGNAL_YELLOW_GLOW : AllBlockPartials.SIGNAL_WHITE_GLOW,
|
||||||
|
blockState)
|
||||||
.light(0xf000f0)
|
.light(0xf000f0)
|
||||||
.disableDiffuseMult()
|
.disableDiffuseMult()
|
||||||
.scale(vert ? 5.125f : 2, vert ? 2 : 5.125f, 2)
|
.scale(vert ? longSideGlow : 2, vert ? 2 : longSideGlow, 2)
|
||||||
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
.renderInto(ms, buffer.getBuffer(RenderTypes.getAdditive()));
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedBufferer.partial(first ? AllBlockPartials.SIGNAL_RED : AllBlockPartials.SIGNAL_WHITE, blockState)
|
CachedBufferer
|
||||||
|
.partial(first ? AllBlockPartials.SIGNAL_RED
|
||||||
|
: yellow ? AllBlockPartials.SIGNAL_YELLOW : AllBlockPartials.SIGNAL_WHITE, blockState)
|
||||||
.light(0xF000F0)
|
.light(0xF000F0)
|
||||||
.disableDiffuseMult()
|
.disableDiffuseMult()
|
||||||
.scale(1 + 1 / 16f)
|
.scale(1 + 1 / 16f)
|
||||||
|
|
|
@ -3,6 +3,8 @@ package com.simibubi.create.content.logistics.trains;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -39,6 +41,9 @@ public class GlobalRailwayManager {
|
||||||
public Map<UUID, Train> trains;
|
public Map<UUID, Train> trains;
|
||||||
public TrackGraphSync sync;
|
public TrackGraphSync sync;
|
||||||
|
|
||||||
|
private List<Train> movingTrains;
|
||||||
|
private List<Train> waitingTrains;
|
||||||
|
|
||||||
private RailwaySavedData savedData;
|
private RailwaySavedData savedData;
|
||||||
|
|
||||||
public GlobalRailwayManager() {
|
public GlobalRailwayManager() {
|
||||||
|
@ -75,6 +80,8 @@ public class GlobalRailwayManager {
|
||||||
trains = savedData.getTrains();
|
trains = savedData.getTrains();
|
||||||
trackNetworks = savedData.getTrackNetworks();
|
trackNetworks = savedData.getTrackNetworks();
|
||||||
signalEdgeGroups = savedData.getSignalBlocks();
|
signalEdgeGroups = savedData.getSignalBlocks();
|
||||||
|
trains.values()
|
||||||
|
.forEach(movingTrains::add);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void cleanUp() {
|
public void cleanUp() {
|
||||||
|
@ -82,6 +89,8 @@ public class GlobalRailwayManager {
|
||||||
signalEdgeGroups = new HashMap<>();
|
signalEdgeGroups = new HashMap<>();
|
||||||
trains = new HashMap<>();
|
trains = new HashMap<>();
|
||||||
sync = new TrackGraphSync();
|
sync = new TrackGraphSync();
|
||||||
|
movingTrains = new LinkedList<>();
|
||||||
|
waitingTrains = new LinkedList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void markTracksDirty() {
|
public void markTracksDirty() {
|
||||||
|
@ -89,6 +98,19 @@ public class GlobalRailwayManager {
|
||||||
savedData.setDirty();
|
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) {
|
public TrackGraph getOrCreateGraph(UUID graphID) {
|
||||||
|
@ -145,22 +167,51 @@ public class GlobalRailwayManager {
|
||||||
group.trains.clear();
|
group.trains.clear();
|
||||||
group.reserved = null;
|
group.reserved = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (TrackGraph graph : trackNetworks.values())
|
for (TrackGraph graph : trackNetworks.values())
|
||||||
graph.tickPoints();
|
graph.tickPoints(true);
|
||||||
for (Train train : trains.values())
|
|
||||||
train.earlyTick(level);
|
|
||||||
for (Train train : trains.values())
|
|
||||||
train.tick(level);
|
|
||||||
|
|
||||||
// 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()
|
// trackNetworks.values()
|
||||||
// .forEach(TrackGraph::debugViewSignalData);
|
// .forEach(TrackGraph::debugViewReserved);
|
||||||
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
// if (AllKeys.isKeyDown(GLFW.GLFW_KEY_J) && AllKeys.altDown())
|
||||||
// trackNetworks.values()
|
// trackNetworks.values()
|
||||||
// .forEach(TrackGraph::debugViewNodes);
|
// .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<Train> iterator = waitingTrains.iterator(); iterator.hasNext();) {
|
||||||
|
Train train = iterator.next();
|
||||||
|
if (train.navigation.waitingForSignal != null)
|
||||||
|
continue;
|
||||||
|
movingTrains.add(train);
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Iterator<Train> iterator = movingTrains.iterator(); iterator.hasNext();) {
|
||||||
|
Train train = iterator.next();
|
||||||
|
if (train.navigation.waitingForSignal == null)
|
||||||
|
continue;
|
||||||
|
waitingTrains.add(train);
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void clientTick() {
|
public void clientTick() {
|
||||||
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown())
|
if (AllKeys.isKeyDown(GLFW.GLFW_KEY_H) && !AllKeys.altDown())
|
||||||
trackNetworks.values()
|
trackNetworks.values()
|
||||||
|
|
|
@ -98,8 +98,8 @@ public class TrackGraph {
|
||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tickPoints() {
|
public void tickPoints(boolean preTrains) {
|
||||||
edgePoints.tick(this);
|
edgePoints.tick(this, preTrains);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -425,6 +425,129 @@ public class TrackGraph {
|
||||||
return graph;
|
return graph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void debugViewReserved() {
|
||||||
|
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
||||||
|
if (cameraEntity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Set<UUID> reserved = new HashSet<>();
|
||||||
|
Set<UUID> 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<TrackNodeLocation, TrackNode> 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<TrackNode, TrackEdge> map = connectionsByNode.get(node);
|
||||||
|
if (map == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int hashCode = node.hashCode();
|
||||||
|
for (Entry<TrackNode, TrackEdge> 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() {
|
public void debugViewSignalData() {
|
||||||
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
Entity cameraEntity = Minecraft.getInstance().cameraEntity;
|
||||||
if (cameraEntity == null)
|
if (cameraEntity == null)
|
||||||
|
|
|
@ -11,7 +11,7 @@ import javax.annotation.Nullable;
|
||||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||||
|
|
||||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
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.content.logistics.trains.entity.TravellingPoint.ITrackSelector;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.Iterate;
|
import com.simibubi.create.foundation.utility.Iterate;
|
||||||
|
@ -131,9 +131,9 @@ public class Carriage {
|
||||||
boolean atBack =
|
boolean atBack =
|
||||||
(type == LAST || type == BOTH) && !actuallyFirstWheel && (!actuallyFirstBogey || !onTwoBogeys);
|
(type == LAST || type == BOTH) && !actuallyFirstWheel && (!actuallyFirstBogey || !onTwoBogeys);
|
||||||
|
|
||||||
ISignalBoundaryListener frontListener = train.frontSignalListener();
|
IEdgePointListener frontListener = train.frontSignalListener();
|
||||||
ISignalBoundaryListener backListener = train.backSignalListener();
|
IEdgePointListener backListener = train.backSignalListener();
|
||||||
ISignalBoundaryListener passiveListener = point.ignoreSignals();
|
IEdgePointListener passiveListener = point.ignoreEdgePoints();
|
||||||
|
|
||||||
toMove += correction + bogeyCorrection;
|
toMove += correction + bogeyCorrection;
|
||||||
double moved =
|
double moved =
|
||||||
|
|
|
@ -239,7 +239,7 @@ public class CarriageSyncData {
|
||||||
TravellingPoint toApproach = pointsToApproach[index];
|
TravellingPoint toApproach = pointsToApproach[index];
|
||||||
|
|
||||||
point.travel(graph, partial * f,
|
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());
|
point.ignoreTurns());
|
||||||
|
|
||||||
// could not pathfind to server location
|
// could not pathfind to server location
|
||||||
|
|
|
@ -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.entity.TravellingPoint.ITrackSelector;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgeData;
|
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.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.SignalBoundary;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
|
@ -52,6 +53,7 @@ public class Navigation {
|
||||||
|
|
||||||
private TravellingPoint signalScout;
|
private TravellingPoint signalScout;
|
||||||
public Pair<UUID, Boolean> waitingForSignal;
|
public Pair<UUID, Boolean> waitingForSignal;
|
||||||
|
private Set<UUID> waitingForChainedGroups;
|
||||||
public double distanceToSignal;
|
public double distanceToSignal;
|
||||||
public int ticksWaitingForSignal;
|
public int ticksWaitingForSignal;
|
||||||
|
|
||||||
|
@ -59,6 +61,7 @@ public class Navigation {
|
||||||
this.train = train;
|
this.train = train;
|
||||||
currentPath = new ArrayList<>();
|
currentPath = new ArrayList<>();
|
||||||
signalScout = new TravellingPoint();
|
signalScout = new TravellingPoint();
|
||||||
|
waitingForChainedGroups = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(Level level) {
|
public void tick(Level level) {
|
||||||
|
@ -97,8 +100,13 @@ public class Navigation {
|
||||||
|
|
||||||
// Signals
|
// Signals
|
||||||
if (train.graph != null) {
|
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;
|
waitingForSignal = null;
|
||||||
|
waitingForChainedGroups.clear();
|
||||||
|
}
|
||||||
|
|
||||||
TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0)
|
TravellingPoint leadingPoint = !destinationBehindTrain ? train.carriages.get(0)
|
||||||
.getLeadingPoint()
|
.getLeadingPoint()
|
||||||
|
@ -120,49 +128,103 @@ public class Navigation {
|
||||||
|
|
||||||
double brakingDistanceNoFlicker =
|
double brakingDistanceNoFlicker =
|
||||||
Math.max(preDepartureLookAhead, brakingDistance + 3 - (brakingDistance % 3));
|
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) -> {
|
MutableDouble crossSignalDistanceTracker = new MutableDouble(-1);
|
||||||
UUID entering = couple.getSecond()
|
MutableObject<Pair<UUID, Boolean>> trackingCrossSignal = new MutableObject<>(null);
|
||||||
.getSecond();
|
waitingForChainedGroups.clear();
|
||||||
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(entering);
|
// train.reservedSignalBlocks.clear();
|
||||||
if (signalEdgeGroup == null)
|
|
||||||
return;
|
signalScout.travel(train.graph, distanceToDestination * speedMod, controlSignalScout(),
|
||||||
SignalBoundary boundary = couple.getFirst();
|
(distance, couple) -> {
|
||||||
if (signalEdgeGroup.isOccupiedUnless(train)) {
|
// > scanDistance and not following down a cross signal
|
||||||
distanceToSignal = Math.min(distance, distanceToSignal);
|
boolean crossSignalTracked = trackingCrossSignal.getValue() != null;
|
||||||
waitingForSignal = Pair.of(boundary.id, entering.equals(boundary.groups.getFirst()));
|
if (!crossSignalTracked && distance > scanDistance)
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
|
Couple<TrackNode> 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();
|
distanceToNextCurve = curveDistanceTracker.floatValue();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ticksWaitingForSignal++;
|
ticksWaitingForSignal++;
|
||||||
|
// if chain signal try finding new path/destination every x ticks
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination;
|
double targetDistance = waitingForSignal != null ? distanceToSignal : distanceToDestination;
|
||||||
|
|
||||||
if (targetDistance < 1 / 32f) {
|
// always overshoot to ensure the travelling point crosses the target
|
||||||
train.speed = 0;
|
targetDistance += 0.25d;
|
||||||
if (waitingForSignal != null) {
|
|
||||||
distanceToSignal = 0;
|
// dont leave until green light
|
||||||
return;
|
if (targetDistance > 1 / 32f && train.getCurrentStation() != null) {
|
||||||
}
|
|
||||||
distanceToDestination = 0;
|
|
||||||
currentPath.clear();
|
|
||||||
train.arriveAt(destination);
|
|
||||||
destination = null;
|
|
||||||
return;
|
|
||||||
} else if (train.getCurrentStation() != null) {
|
|
||||||
// dont leave until green light
|
|
||||||
if (waitingForSignal != null && distanceToSignal < preDepartureLookAhead)
|
if (waitingForSignal != null && distanceToSignal < preDepartureLookAhead)
|
||||||
return;
|
return;
|
||||||
train.leaveStation();
|
train.leaveStation();
|
||||||
|
@ -170,8 +232,13 @@ public class Navigation {
|
||||||
|
|
||||||
train.currentlyBackwards = destinationBehindTrain;
|
train.currentlyBackwards = destinationBehindTrain;
|
||||||
|
|
||||||
|
if (targetDistance < -10) {
|
||||||
|
cancelNavigation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetDistance - Math.abs(train.speed) < 1 / 32f) {
|
if (targetDistance - Math.abs(train.speed) < 1 / 32f) {
|
||||||
train.speed = targetDistance * speedMod;
|
train.speed = Math.max(targetDistance, 1 / 32f) * speedMod;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,12 +265,26 @@ public class Navigation {
|
||||||
train.approachTargetSpeed(1);
|
train.approachTargetSpeed(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkBlockingSignal() {
|
private boolean currentSignalResolved() {
|
||||||
if (distanceToDestination < .5f)
|
if (distanceToDestination < .5f)
|
||||||
return true;
|
return true;
|
||||||
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst());
|
SignalBoundary signal = train.graph.getPoint(EdgePointType.SIGNAL, waitingForSignal.getFirst());
|
||||||
if (signal == null)
|
if (signal == null)
|
||||||
return true;
|
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());
|
UUID groupId = signal.groups.get(waitingForSignal.getSecond());
|
||||||
if (groupId == null)
|
if (groupId == null)
|
||||||
return true;
|
return true;
|
||||||
|
@ -255,6 +336,7 @@ public class Navigation {
|
||||||
destination.cancelReservation(train);
|
destination.cancelReservation(train);
|
||||||
destination = null;
|
destination = null;
|
||||||
train.runtime.transitInterrupted();
|
train.runtime.transitInterrupted();
|
||||||
|
train.reservedSignalBlocks.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public double startNavigation(GlobalStation destination, double maxCost, boolean simulate) {
|
public double startNavigation(GlobalStation destination, double maxCost, boolean simulate) {
|
||||||
|
@ -267,16 +349,19 @@ public class Navigation {
|
||||||
return cost;
|
return cost;
|
||||||
|
|
||||||
distanceToDestination = distance;
|
distanceToDestination = distance;
|
||||||
currentPath = pathTo.path;
|
|
||||||
|
|
||||||
if (noneFound) {
|
if (noneFound) {
|
||||||
distanceToDestination = 0;
|
distanceToDestination = 0;
|
||||||
|
currentPath = new ArrayList<>();
|
||||||
if (this.destination != null)
|
if (this.destination != null)
|
||||||
cancelNavigation();
|
cancelNavigation();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentPath = pathTo.path;
|
||||||
destinationBehindTrain = pathTo.distance < 0;
|
destinationBehindTrain = pathTo.distance < 0;
|
||||||
|
train.reservedSignalBlocks.clear();
|
||||||
|
train.navigation.waitingForSignal = null;
|
||||||
|
|
||||||
if (this.destination == destination)
|
if (this.destination == destination)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -315,7 +400,9 @@ public class Navigation {
|
||||||
|
|
||||||
Couple<DiscoveredPath> results = Couple.create(null, null);
|
Couple<DiscoveredPath> results = Couple.create(null, null);
|
||||||
for (boolean forward : Iterate.trueAndFalse) {
|
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;
|
continue;
|
||||||
|
|
||||||
TravellingPoint initialPoint = forward ? train.carriages.get(0)
|
TravellingPoint initialPoint = forward ? train.carriages.get(0)
|
||||||
|
@ -377,6 +464,9 @@ public class Navigation {
|
||||||
if (!canDriveForward)
|
if (!canDriveForward)
|
||||||
return back;
|
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;
|
boolean frontBetter = maxCost == -1 ? -back.distance > front.distance : back.cost > front.cost;
|
||||||
return frontBetter ? front : back;
|
return frontBetter ? front : back;
|
||||||
}
|
}
|
||||||
|
@ -438,6 +528,8 @@ public class Navigation {
|
||||||
for (Train otherTrain : Create.RAILWAYS.trains.values()) {
|
for (Train otherTrain : Create.RAILWAYS.trains.values()) {
|
||||||
if (otherTrain.graph != graph)
|
if (otherTrain.graph != graph)
|
||||||
continue;
|
continue;
|
||||||
|
if (otherTrain == train)
|
||||||
|
continue;
|
||||||
int navigationPenalty = otherTrain.getNavigationPenalty();
|
int navigationPenalty = otherTrain.getNavigationPenalty();
|
||||||
otherTrain.getEndpointEdges()
|
otherTrain.getEndpointEdges()
|
||||||
.forEach(nodes -> {
|
.forEach(nodes -> {
|
||||||
|
@ -474,6 +566,8 @@ public class Navigation {
|
||||||
|
|
||||||
Search: while (!frontier.isEmpty()) {
|
Search: while (!frontier.isEmpty()) {
|
||||||
FrontierEntry entry = frontier.poll();
|
FrontierEntry entry = frontier.poll();
|
||||||
|
if (!visited.add(entry.edge))
|
||||||
|
continue;
|
||||||
|
|
||||||
double distance = entry.distance;
|
double distance = entry.distance;
|
||||||
int penalty = entry.penalty;
|
int penalty = entry.penalty;
|
||||||
|
@ -499,12 +593,15 @@ public class Navigation {
|
||||||
if (!point.canNavigateVia(node2))
|
if (!point.canNavigateVia(node2))
|
||||||
continue Search;
|
continue Search;
|
||||||
if (point instanceof GlobalStation station) {
|
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;
|
penalty += Train.Penalties.STATION_WITH_TRAIN;
|
||||||
if (station.canApproachFrom(node2) && stationTest.test(distance, distance + penalty, reachedVia,
|
if (station.canApproachFrom(node2) && stationTest.test(distance, distance + penalty, reachedVia,
|
||||||
Pair.of(Couple.create(node1, node2), edge), station))
|
Pair.of(Couple.create(node1, node2), edge), station))
|
||||||
return;
|
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);
|
Vec3 newDirection = newEdge.getDirection(node2, newNode, true);
|
||||||
if (currentDirection.dot(newDirection) < 3 / 4f)
|
if (currentDirection.dot(newDirection) < 3 / 4f)
|
||||||
continue;
|
continue;
|
||||||
if (!visited.add(connection.getValue()))
|
|
||||||
continue;
|
|
||||||
validTargets.add(connection);
|
validTargets.add(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.content.logistics.trains.entity;
|
package com.simibubi.create.content.logistics.trains.entity;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
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.TrackEdge;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||||
import com.simibubi.create.content.logistics.trains.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.ITrackSelector;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
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.EdgeData;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
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.SignalBoundary;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalEdgeGroup;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.station.GlobalStation;
|
||||||
|
@ -82,7 +84,8 @@ public class Train {
|
||||||
public List<Integer> carriageSpacing;
|
public List<Integer> carriageSpacing;
|
||||||
|
|
||||||
public boolean updateSignalBlocks;
|
public boolean updateSignalBlocks;
|
||||||
public List<UUID> occupiedSignalBlocks;
|
public Map<UUID, UUID> occupiedSignalBlocks;
|
||||||
|
public Set<UUID> reservedSignalBlocks;
|
||||||
|
|
||||||
List<TrainMigration> migratingPoints;
|
List<TrainMigration> migratingPoints;
|
||||||
public int migrationCooldown;
|
public int migrationCooldown;
|
||||||
|
@ -112,28 +115,35 @@ public class Train {
|
||||||
migratingPoints = new ArrayList<>();
|
migratingPoints = new ArrayList<>();
|
||||||
currentStation = null;
|
currentStation = null;
|
||||||
manualSteer = SteerDirection.NONE;
|
manualSteer = SteerDirection.NONE;
|
||||||
occupiedSignalBlocks = new ArrayList<>();
|
occupiedSignalBlocks = new HashMap<>();
|
||||||
|
reservedSignalBlocks = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void earlyTick(Level level) {
|
public void earlyTick(Level level) {
|
||||||
status.tick(level);
|
status.tick(level);
|
||||||
if (graph == null && !migratingPoints.isEmpty())
|
if (graph == null && !migratingPoints.isEmpty())
|
||||||
reattachToTracks(level);
|
reattachToTracks(level);
|
||||||
|
|
||||||
|
addToSignalGroups(occupiedSignalBlocks.keySet());
|
||||||
|
|
||||||
if (graph == null)
|
if (graph == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (updateSignalBlocks) {
|
if (updateSignalBlocks) {
|
||||||
updateSignalBlocks = false;
|
updateSignalBlocks = false;
|
||||||
collectInitiallyOccupiedSignalBlocks();
|
collectInitiallyOccupiedSignalBlocks();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Iterator<UUID> iterator = occupiedSignalBlocks.iterator(); iterator.hasNext();) {
|
addToSignalGroups(reservedSignalBlocks);
|
||||||
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(iterator.next());
|
}
|
||||||
if (signalEdgeGroup == null) {
|
|
||||||
|
private void addToSignalGroups(Collection<UUID> groups) {
|
||||||
|
Map<UUID, SignalEdgeGroup> groupMap = Create.RAILWAYS.signalEdgeGroups;
|
||||||
|
for (Iterator<UUID> iterator = groups.iterator(); iterator.hasNext();) {
|
||||||
|
SignalEdgeGroup signalEdgeGroup = groupMap.get(iterator.next());
|
||||||
|
if (signalEdgeGroup == null)
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
continue;
|
else
|
||||||
}
|
signalEdgeGroup.trains.add(this);
|
||||||
signalEdgeGroup.trains.add(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,6 +222,8 @@ public class Train {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
distance = actualDistance;
|
distance = actualDistance;
|
||||||
collideWithOtherTrains(level, carriage);
|
collideWithOtherTrains(level, carriage);
|
||||||
|
if (graph == null)
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,23 +238,58 @@ public class Train {
|
||||||
updateNavigationTarget(distance);
|
updateNavigationTarget(distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISignalBoundaryListener frontSignalListener() {
|
public IEdgePointListener frontSignalListener() {
|
||||||
return (distance, couple) -> {
|
return (distance, couple) -> {
|
||||||
UUID groupId = couple.getSecond()
|
|
||||||
.getSecond();
|
if (couple.getFirst()instanceof GlobalStation station) {
|
||||||
SignalEdgeGroup signalEdgeGroup = Create.RAILWAYS.signalEdgeGroups.get(groupId);
|
if (!station.canApproachFrom(couple.getSecond()
|
||||||
SignalBoundary boundary = couple.getFirst();
|
.getSecond()) || navigation.destination != station)
|
||||||
if (signalEdgeGroup != null) {
|
return false;
|
||||||
signalEdgeGroup.reserved = boundary;
|
speed = 0;
|
||||||
occupiedSignalBlocks.add(groupId);
|
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) -> {
|
return (distance, couple) -> {
|
||||||
occupiedSignalBlocks.remove(couple.getSecond()
|
if (!(couple.getFirst()instanceof SignalBoundary signal))
|
||||||
|
return false;
|
||||||
|
UUID groupId = signal.getGroup(couple.getSecond()
|
||||||
.getFirst());
|
.getFirst());
|
||||||
|
occupiedSignalBlocks.remove(groupId);
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,32 +297,43 @@ public class Train {
|
||||||
if (navigation.destination == null)
|
if (navigation.destination == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
boolean recalculate = navigation.distanceToDestination % 100 > 20;
|
Pair<UUID, Boolean> blockingSignal = navigation.waitingForSignal;
|
||||||
boolean imminentRecalculate = navigation.distanceToDestination > 5;
|
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;
|
double toSubstract = navigation.destinationBehindTrain ? -distance : distance;
|
||||||
navigation.distanceToDestination -= toSubstract;
|
|
||||||
boolean signalMode = navigation.waitingForSignal != null;
|
|
||||||
boolean navigatingManually = runtime.paused;
|
boolean navigatingManually = runtime.paused;
|
||||||
|
|
||||||
if (signalMode) {
|
navigation.distanceToDestination -= toSubstract;
|
||||||
|
if (blockingSignal != null) {
|
||||||
navigation.distanceToSignal -= toSubstract;
|
navigation.distanceToSignal -= toSubstract;
|
||||||
recalculate = navigation.distanceToSignal % 100 > 20;
|
signalRefresh &= navigation.distanceToSignal % 50 < 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recalculate && (signalMode ? navigation.distanceToSignal : navigation.distanceToDestination) % 100 <= 20
|
fullRefresh &= navigation.distanceToDestination % 100 <= 20;
|
||||||
|| imminentRecalculate && navigation.distanceToDestination <= 5) {
|
partialRefresh &= navigation.distanceToDestination % 50 <= 5;
|
||||||
if (signalMode) {
|
|
||||||
navigation.waitingForSignal = null;
|
if (blockingSignal != null && navigation.ticksWaitingForSignal % 100 == 50) {
|
||||||
return;
|
SignalBoundary signal = graph.getPoint(EdgePointType.SIGNAL, blockingSignal.getFirst());
|
||||||
}
|
fullRefresh |= signal != null && signal.types.get(blockingSignal.getSecond()) == SignalType.CROSS_SIGNAL;
|
||||||
GlobalStation destination = navigation.destination;
|
|
||||||
if (!navigatingManually) {
|
|
||||||
GlobalStation preferredDestination = runtime.findNextStation();
|
|
||||||
if (preferredDestination != null)
|
|
||||||
destination = preferredDestination;
|
|
||||||
}
|
|
||||||
navigation.startNavigation(destination, navigatingManually ? -1 : Double.MAX_VALUE, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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() {
|
private void tickDerailedSlowdown() {
|
||||||
|
@ -439,7 +497,7 @@ public class Train {
|
||||||
if (currentStation != null)
|
if (currentStation != null)
|
||||||
currentStation.cancelReservation(this);
|
currentStation.cancelReservation(this);
|
||||||
|
|
||||||
Create.RAILWAYS.trains.remove(id);
|
Create.RAILWAYS.removeTrain(id);
|
||||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false));
|
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(this, false));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -598,6 +656,7 @@ public class Train {
|
||||||
|
|
||||||
public void arriveAt(GlobalStation station) {
|
public void arriveAt(GlobalStation station) {
|
||||||
setCurrentStation(station);
|
setCurrentStation(station);
|
||||||
|
reservedSignalBlocks.clear();
|
||||||
runtime.destinationReached();
|
runtime.destinationReached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -645,6 +704,7 @@ public class Train {
|
||||||
EdgeData signalData = edge.getEdgeData();
|
EdgeData signalData = edge.getEdgeData();
|
||||||
|
|
||||||
occupiedSignalBlocks.clear();
|
occupiedSignalBlocks.clear();
|
||||||
|
reservedSignalBlocks.clear();
|
||||||
|
|
||||||
TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position);
|
TravellingPoint signalScout = new TravellingPoint(node1, node2, edge, position);
|
||||||
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
|
Map<UUID, SignalEdgeGroup> allGroups = Create.RAILWAYS.signalEdgeGroups;
|
||||||
|
@ -664,7 +724,7 @@ public class Train {
|
||||||
if (prev != null) {
|
if (prev != null) {
|
||||||
UUID group = prev.getGroup(node2);
|
UUID group = prev.getGroup(node2);
|
||||||
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
||||||
occupiedSignalBlocks.add(group);
|
occupy(group, null);
|
||||||
prevGroup.setValue(group);
|
prevGroup.setValue(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -672,26 +732,32 @@ public class Train {
|
||||||
} else {
|
} else {
|
||||||
UUID group = nextBoundary.getGroup(node1);
|
UUID group = nextBoundary.getGroup(node1);
|
||||||
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
if (Create.RAILWAYS.signalEdgeGroups.containsKey(group)) {
|
||||||
occupiedSignalBlocks.add(group);
|
occupy(group, null);
|
||||||
prevGroup.setValue(group);
|
prevGroup.setValue(group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (signalData.singleSignalGroup != null && allGroups.containsKey(signalData.singleSignalGroup)) {
|
} else if (signalData.singleSignalGroup != null && allGroups.containsKey(signalData.singleSignalGroup)) {
|
||||||
occupiedSignalBlocks.add(signalData.singleSignalGroup);
|
occupy(signalData.singleSignalGroup, null);
|
||||||
prevGroup.setValue(signalData.singleSignalGroup);
|
prevGroup.setValue(signalData.singleSignalGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
forEachTravellingPointBackwards((tp, d) -> {
|
forEachTravellingPointBackwards((tp, d) -> {
|
||||||
signalScout.travel(graph, d, signalScout.follow(tp), (distance, couple) -> couple.getSecond()
|
signalScout.travel(graph, d, signalScout.follow(tp), (distance, couple) -> {
|
||||||
.forEach(id -> {
|
if (!(couple.getFirst()instanceof SignalBoundary signal))
|
||||||
if (!Create.RAILWAYS.signalEdgeGroups.containsKey(id))
|
return false;
|
||||||
return;
|
couple.getSecond()
|
||||||
if (id.equals(prevGroup.getValue()))
|
.map(signal::getGroup)
|
||||||
return;
|
.forEach(id -> {
|
||||||
occupiedSignalBlocks.add(id);
|
if (!Create.RAILWAYS.signalEdgeGroups.containsKey(id))
|
||||||
prevGroup.setValue(id);
|
return;
|
||||||
}), signalScout.ignoreTurns());
|
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("StillAssembling", heldForAssembly);
|
||||||
tag.putBoolean("Derailed", derailed);
|
tag.putBoolean("Derailed", derailed);
|
||||||
tag.putBoolean("UpdateSignals", updateSignalBlocks);
|
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 compoundTag = new CompoundTag();
|
||||||
compoundTag.putUUID("Id", uid);
|
compoundTag.putUUID("Id", uid);
|
||||||
return compoundTag;
|
return compoundTag;
|
||||||
|
@ -778,9 +851,10 @@ public class Train {
|
||||||
train.derailed = tag.getBoolean("Derailed");
|
train.derailed = tag.getBoolean("Derailed");
|
||||||
train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
|
train.updateSignalBlocks = tag.getBoolean("UpdateSignals");
|
||||||
|
|
||||||
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND),
|
NBTHelper.iterateCompoundList(tag.getList("SignalBlocks", Tag.TAG_COMPOUND), c -> train.occupiedSignalBlocks
|
||||||
c -> train.occupiedSignalBlocks.add(c.getUUID("Id")));
|
.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),
|
NBTHelper.iterateCompoundList(tag.getList("MigratingPoints", Tag.TAG_COMPOUND),
|
||||||
c -> train.migratingPoints.add(TrainMigration.read(c)));
|
c -> train.migratingPoints.add(TrainMigration.read(c)));
|
||||||
|
|
||||||
|
|
|
@ -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.TrackGraph;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackGraphHelper;
|
import com.simibubi.create.content.logistics.trains.TrackGraphHelper;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.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.ITrackSelector;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener;
|
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.ITurnListener;
|
||||||
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
import com.simibubi.create.content.logistics.trains.entity.TravellingPoint.SteerDirection;
|
||||||
|
@ -158,7 +158,7 @@ public class TrainRelocator {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position);
|
TravellingPoint probe = new TravellingPoint(node1, node2, edge, graphLocation.position);
|
||||||
ISignalBoundaryListener ignoreSignals = probe.ignoreSignals();
|
IEdgePointListener ignoreSignals = probe.ignoreEdgePoints();
|
||||||
ITurnListener ignoreTurns = probe.ignoreTurns();
|
ITurnListener ignoreTurns = probe.ignoreTurns();
|
||||||
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();
|
List<Pair<Couple<TrackNode>, Double>> recordedLocations = new ArrayList<>();
|
||||||
List<Vec3> recordedVecs = new ArrayList<>();
|
List<Vec3> recordedVecs = new ArrayList<>();
|
||||||
|
@ -206,6 +206,7 @@ public class TrainRelocator {
|
||||||
|
|
||||||
train.leaveStation();
|
train.leaveStation();
|
||||||
train.derailed = false;
|
train.derailed = false;
|
||||||
|
train.heldForAssembly = false;
|
||||||
train.navigation.waitingForSignal = null;
|
train.navigation.waitingForSignal = null;
|
||||||
train.occupiedSignalBlocks.clear();
|
train.occupiedSignalBlocks.clear();
|
||||||
train.graph = graph;
|
train.graph = graph;
|
||||||
|
@ -322,13 +323,12 @@ public class TrainRelocator {
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
public static boolean carriageWrenched(Vec3 vec3, CarriageContraptionEntity entity) {
|
public static boolean carriageWrenched(Vec3 vec3, CarriageContraptionEntity entity) {
|
||||||
Train train = getTrainFromEntity(entity);
|
Train train = getTrainFromEntity(entity);
|
||||||
if (train != null && !train.heldForAssembly) {
|
if (train == null)
|
||||||
relocatingOrigin = vec3;
|
return false;
|
||||||
relocatingTrain = train.id;
|
relocatingOrigin = vec3;
|
||||||
relocatingEntityId = entity.getId();
|
relocatingTrain = train.id;
|
||||||
return true;
|
relocatingEntityId = entity.getId();
|
||||||
}
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnlyIn(Dist.CLIENT)
|
@OnlyIn(Dist.CLIENT)
|
||||||
|
|
|
@ -6,10 +6,10 @@ import java.util.List;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.BiPredicate;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
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.TrackNode;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNodeLocation;
|
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.EdgeData;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.EdgePointType;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.TrackEdgePoint;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalBoundary;
|
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
|
@ -53,7 +52,7 @@ public class TravellingPoint {
|
||||||
extends BiFunction<TrackGraph, Pair<Boolean, List<Entry<TrackNode, TrackEdge>>>, Entry<TrackNode, TrackEdge>> {
|
extends BiFunction<TrackGraph, Pair<Boolean, List<Entry<TrackNode, TrackEdge>>>, Entry<TrackNode, TrackEdge>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public static interface ISignalBoundaryListener extends BiConsumer<Double, Pair<SignalBoundary, Couple<UUID>>> {
|
public static interface IEdgePointListener extends BiPredicate<Double, Pair<TrackEdgePoint, Couple<TrackNode>>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
public static interface ITurnListener extends BiConsumer<Double, TrackEdge> {
|
public static interface ITurnListener extends BiConsumer<Double, TrackEdge> {
|
||||||
|
@ -68,9 +67,8 @@ public class TravellingPoint {
|
||||||
this.position = position;
|
this.position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ISignalBoundaryListener ignoreSignals() {
|
public IEdgePointListener ignoreEdgePoints() {
|
||||||
return (d, c) -> {
|
return (d, c) -> false;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITurnListener ignoreTurns() {
|
public ITurnListener ignoreTurns() {
|
||||||
|
@ -178,7 +176,7 @@ public class TravellingPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
public double travel(TrackGraph graph, double distance, ITrackSelector trackSelector,
|
||||||
ISignalBoundaryListener signalListener, ITurnListener turnListener) {
|
IEdgePointListener signalListener, ITurnListener turnListener) {
|
||||||
blocked = false;
|
blocked = false;
|
||||||
double edgeLength = edge.getLength(node1, node2);
|
double edgeLength = edge.getLength(node1, node2);
|
||||||
if (distance == 0)
|
if (distance == 0)
|
||||||
|
@ -193,7 +191,14 @@ public class TravellingPoint {
|
||||||
|
|
||||||
boolean forward = distance > 0;
|
boolean forward = distance > 0;
|
||||||
double collectedDistance = forward ? -prevPos : -edgeLength + prevPos;
|
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) {
|
if (forward) {
|
||||||
// Moving forward
|
// Moving forward
|
||||||
|
@ -233,9 +238,17 @@ public class TravellingPoint {
|
||||||
collectedDistance += edgeLength;
|
collectedDistance += edgeLength;
|
||||||
if (edge.isTurn())
|
if (edge.isTurn())
|
||||||
turnListener.accept(collectedDistance, edge);
|
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);
|
edgeLength = edge.getLength(node1, node2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +274,7 @@ public class TravellingPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (validTargets.isEmpty()) {
|
if (validTargets.isEmpty()) {
|
||||||
traveled -= position;
|
traveled += position;
|
||||||
position = 0;
|
position = 0;
|
||||||
blocked = true;
|
blocked = true;
|
||||||
break;
|
break;
|
||||||
|
@ -278,7 +291,15 @@ public class TravellingPoint {
|
||||||
edgeLength = edge.getLength(node1, node2);
|
edgeLength = edge.getLength(node1, node2);
|
||||||
position += edgeLength;
|
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;
|
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) {
|
ITurnListener turnListener, double prevPos, double totalDistance) {
|
||||||
if (edge.isTurn())
|
if (edge.isTurn())
|
||||||
turnListener.accept(Math.max(0, totalDistance), edge);
|
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 from = forward ? prevPos : position;
|
||||||
double to = forward ? position : prevPos;
|
double to = forward ? position : prevPos;
|
||||||
SignalBoundary nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, from);
|
List<TrackEdgePoint> edgePoints = edgeData.getPoints();
|
||||||
List<SignalBoundary> discoveredBoundaries = null;
|
|
||||||
|
|
||||||
while (nextBoundary != null) {
|
double length = edge.getLength(node1, node2);
|
||||||
double d = nextBoundary.getLocationOn(node1, node2, edge);
|
for (int i = 0; i < edgePoints.size(); i++) {
|
||||||
if (d > to)
|
int index = forward ? i : edgePoints.size() - i - 1;
|
||||||
break;
|
TrackEdgePoint nextBoundary = edgePoints.get(index);
|
||||||
if (discoveredBoundaries == null)
|
double locationOn = nextBoundary.getLocationOn(node1, node2, edge);
|
||||||
discoveredBoundaries = new ArrayList<>();
|
double distance = forward ? locationOn : length - locationOn;
|
||||||
discoveredBoundaries.add(nextBoundary);
|
if (forward ? (locationOn < from || locationOn >= to) : (locationOn <= from || locationOn > to))
|
||||||
nextBoundary = signalsOnEdge.next(EdgePointType.SIGNAL, node1, node2, edge, d);
|
continue;
|
||||||
|
Couple<TrackNode> nodes = Couple.create(node1, node2);
|
||||||
|
if (edgePointListener.test(totalDistance + distance, Pair.of(nextBoundary, forward ? nodes : nodes.swap())))
|
||||||
|
return locationOn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (discoveredBoundaries == null)
|
return 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<UUID> nodes = Couple.create(nextBoundary.getGroup(node1), nextBoundary.getGroup(node2));
|
|
||||||
signalListener.accept(totalDistance + d, Pair.of(nextBoundary, forward ? nodes : nodes.swap()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reverse(TrackGraph graph) {
|
public void reverse(TrackGraph graph) {
|
||||||
|
|
|
@ -70,6 +70,14 @@ public class EdgeData {
|
||||||
return null;
|
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
|
@Nullable
|
||||||
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
public <T extends TrackEdgePoint> T get(EdgePointType<T> type, TrackNode node1, TrackNode node2, TrackEdge edge,
|
||||||
double exactPosition) {
|
double exactPosition) {
|
||||||
|
|
|
@ -49,10 +49,10 @@ public class EdgePointStorage {
|
||||||
return pointsByType.computeIfAbsent(type, t -> new HashMap<>());
|
return pointsByType.computeIfAbsent(type, t -> new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(TrackGraph graph) {
|
public void tick(TrackGraph graph, boolean preTrains) {
|
||||||
pointsByType.values()
|
pointsByType.values()
|
||||||
.forEach(map -> map.values()
|
.forEach(map -> map.values()
|
||||||
.forEach(p -> p.tick(graph)));
|
.forEach(p -> p.tick(graph, preTrains)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void transferAll(TrackGraph target, EdgePointStorage other) {
|
public void transferAll(TrackGraph target, EdgePointStorage other) {
|
||||||
|
|
|
@ -143,7 +143,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
||||||
}
|
}
|
||||||
if (!otherPoint.canMerge())
|
if (!otherPoint.canMerge())
|
||||||
return null;
|
return null;
|
||||||
otherPoint.tileAdded(getPos(), front);
|
otherPoint.tileAdded(tileEntity, front);
|
||||||
id = otherPoint.getId();
|
id = otherPoint.getId();
|
||||||
tileEntity.setChanged();
|
tileEntity.setChanged();
|
||||||
return (T) otherPoint;
|
return (T) otherPoint;
|
||||||
|
@ -158,7 +158,7 @@ public class TrackTargetingBehaviour<T extends TrackEdgePoint> extends TileEntit
|
||||||
|
|
||||||
point.setId(id);
|
point.setId(id);
|
||||||
point.setLocation(reverseEdge ? loc.edge : loc.edge.swap(), reverseEdge ? loc.position : length - loc.position);
|
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);
|
loc.graph.addPoint(edgePointType, point);
|
||||||
return point;
|
return point;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,21 +3,41 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
import com.simibubi.create.AllTileEntities;
|
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.block.ITE;
|
||||||
|
import com.simibubi.create.foundation.utility.Lang;
|
||||||
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
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.BlockGetter;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.Block;
|
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.entity.BlockEntityType;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
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<SignalTileEntity> {
|
public class SignalBlock extends Block implements ITE<SignalTileEntity>, IWrenchable {
|
||||||
|
|
||||||
|
public static final EnumProperty<SignalType> 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_) {
|
public SignalBlock(Properties p_53182_) {
|
||||||
super(p_53182_);
|
super(p_53182_);
|
||||||
|
registerDefaultState(defaultBlockState().setValue(TYPE, SignalType.ENTRY_SIGNAL));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,11 +45,36 @@ public class SignalBlock extends Block implements SimpleWaterloggedBlock, ITE<Si
|
||||||
return SignalTileEntity.class;
|
return SignalTileEntity.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
|
||||||
|
super.createBlockStateDefinition(pBuilder.add(TYPE));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockEntityType<? extends SignalTileEntity> getTileEntityType() {
|
public BlockEntityType<? extends SignalTileEntity> getTileEntityType() {
|
||||||
return AllTileEntities.TRACK_SIGNAL.get();
|
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
|
@Override
|
||||||
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) {
|
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, Direction side) {
|
||||||
return side != null;
|
return side != null;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.simibubi.create.content.logistics.trains.management.edgePoint.signal
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ import com.google.common.base.Objects;
|
||||||
import com.simibubi.create.Create;
|
import com.simibubi.create.Create;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
import com.simibubi.create.content.logistics.trains.TrackGraph;
|
||||||
import com.simibubi.create.content.logistics.trains.TrackNode;
|
import com.simibubi.create.content.logistics.trains.TrackNode;
|
||||||
|
import com.simibubi.create.content.logistics.trains.management.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.OverlayState;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState;
|
import com.simibubi.create.content.logistics.trains.management.edgePoint.signal.SignalTileEntity.SignalState;
|
||||||
import com.simibubi.create.foundation.utility.Couple;
|
import com.simibubi.create.foundation.utility.Couple;
|
||||||
|
@ -21,23 +24,32 @@ import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
public class SignalBoundary extends TrackEdgePoint {
|
public class SignalBoundary extends TrackEdgePoint {
|
||||||
|
|
||||||
public Couple<Set<BlockPos>> signals;
|
public Couple<Set<BlockPos>> blockEntities;
|
||||||
|
public Couple<SignalType> types;
|
||||||
public Couple<UUID> groups;
|
public Couple<UUID> groups;
|
||||||
public Couple<Boolean> sidesToUpdate;
|
public Couple<Boolean> sidesToUpdate;
|
||||||
|
public Couple<SignalState> cachedStates;
|
||||||
|
|
||||||
|
private Couple<Map<UUID, Boolean>> chainedSignals;
|
||||||
|
|
||||||
public SignalBoundary() {
|
public SignalBoundary() {
|
||||||
signals = Couple.create(HashSet::new);
|
blockEntities = Couple.create(HashSet::new);
|
||||||
|
chainedSignals = Couple.create(null, null);
|
||||||
groups = Couple.create(null, null);
|
groups = Couple.create(null, null);
|
||||||
sidesToUpdate = Couple.create(true, true);
|
sidesToUpdate = Couple.create(true, true);
|
||||||
|
types = Couple.create(() -> SignalType.ENTRY_SIGNAL);
|
||||||
|
cachedStates = Couple.create(() -> SignalState.GREEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroup(TrackNode side, UUID groupId) {
|
public void setGroup(TrackNode side, UUID groupId) {
|
||||||
boolean primary = isPrimary(side);
|
boolean primary = isPrimary(side);
|
||||||
groups.set(primary, groupId);
|
groups.set(primary, groupId);
|
||||||
sidesToUpdate.set(primary, false);
|
sidesToUpdate.set(primary, false);
|
||||||
|
chainedSignals.set(primary, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -47,19 +59,23 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidate(LevelAccessor level) {
|
public void invalidate(LevelAccessor level) {
|
||||||
signals.forEach(s -> s.forEach(pos -> invalidateAt(level, pos)));
|
blockEntities.forEach(s -> s.forEach(pos -> invalidateAt(level, pos)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tileAdded(BlockPos tilePos, boolean front) {
|
public void tileAdded(BlockEntity tile, boolean front) {
|
||||||
signals.get(front)
|
Set<BlockPos> tilesOnSide = blockEntities.get(front);
|
||||||
.add(tilePos);
|
if (tilesOnSide.isEmpty())
|
||||||
|
tile.getBlockState()
|
||||||
|
.getOptionalValue(SignalBlock.TYPE)
|
||||||
|
.ifPresent(type -> types.set(front, type));
|
||||||
|
tilesOnSide.add(tile.getBlockPos());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tileRemoved(BlockPos tilePos, boolean front) {
|
public void tileRemoved(BlockPos tilePos, boolean front) {
|
||||||
signals.forEach(s -> s.remove(tilePos));
|
blockEntities.forEach(s -> s.remove(tilePos));
|
||||||
if (signals.both(Set::isEmpty))
|
if (blockEntities.both(Set::isEmpty))
|
||||||
removeFromAllGraphs();
|
removeFromAllGraphs();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,16 +95,16 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canNavigateVia(TrackNode side) {
|
public boolean canNavigateVia(TrackNode side) {
|
||||||
return !signals.get(isPrimary(side))
|
return !blockEntities.get(isPrimary(side))
|
||||||
.isEmpty();
|
.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public OverlayState getOverlayFor(BlockPos tile) {
|
public OverlayState getOverlayFor(BlockPos tile) {
|
||||||
for (boolean first : Iterate.trueAndFalse) {
|
for (boolean first : Iterate.trueAndFalse) {
|
||||||
Set<BlockPos> set = signals.get(first);
|
Set<BlockPos> set = blockEntities.get(first);
|
||||||
for (BlockPos blockPos : set) {
|
for (BlockPos blockPos : set) {
|
||||||
if (blockPos.equals(tile))
|
if (blockPos.equals(tile))
|
||||||
return signals.get(!first)
|
return blockEntities.get(!first)
|
||||||
.isEmpty() ? OverlayState.RENDER : OverlayState.DUAL;
|
.isEmpty() ? OverlayState.RENDER : OverlayState.DUAL;
|
||||||
return OverlayState.SKIP;
|
return OverlayState.SKIP;
|
||||||
}
|
}
|
||||||
|
@ -96,58 +112,123 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
return OverlayState.SKIP;
|
return OverlayState.SKIP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SignalType getTypeFor(BlockPos tile) {
|
||||||
|
return types.get(blockEntities.getFirst()
|
||||||
|
.contains(tile));
|
||||||
|
}
|
||||||
|
|
||||||
public SignalState getStateFor(BlockPos tile) {
|
public SignalState getStateFor(BlockPos tile) {
|
||||||
for (boolean first : Iterate.trueAndFalse) {
|
for (boolean first : Iterate.trueAndFalse) {
|
||||||
Set<BlockPos> set = signals.get(first);
|
Set<BlockPos> set = blockEntities.get(first);
|
||||||
if (!set.contains(tile))
|
if (set.contains(tile))
|
||||||
continue;
|
return cachedStates.get(first);
|
||||||
UUID group = groups.get(first);
|
|
||||||
if (Objects.equal(group, groups.get(!first)))
|
|
||||||
return SignalState.INVALID;
|
|
||||||
Map<UUID, SignalEdgeGroup> signalEdgeGroups = Create.RAILWAYS.signalEdgeGroups;
|
|
||||||
SignalEdgeGroup signalEdgeGroup = signalEdgeGroups.get(group);
|
|
||||||
if (signalEdgeGroup == null)
|
|
||||||
return SignalState.INVALID;
|
|
||||||
return signalEdgeGroup.isOccupiedUnless(this) ? SignalState.RED : SignalState.GREEN;
|
|
||||||
}
|
}
|
||||||
return SignalState.INVALID;
|
return SignalState.INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick(TrackGraph graph) {
|
public void tick(TrackGraph graph, boolean preTrains) {
|
||||||
super.tick(graph);
|
super.tick(graph, preTrains);
|
||||||
|
if (!preTrains) {
|
||||||
|
tickState(graph);
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (boolean front : Iterate.trueAndFalse) {
|
for (boolean front : Iterate.trueAndFalse) {
|
||||||
if (!sidesToUpdate.get(front))
|
if (!sidesToUpdate.get(front))
|
||||||
continue;
|
continue;
|
||||||
sidesToUpdate.set(front, false);
|
sidesToUpdate.set(front, false);
|
||||||
SignalPropagator.propagateSignalGroup(graph, this, front);
|
SignalPropagator.propagateSignalGroup(graph, this, front);
|
||||||
|
chainedSignals.set(front, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void tickState(TrackGraph graph) {
|
||||||
|
for (boolean current : Iterate.trueAndFalse) {
|
||||||
|
Set<BlockPos> 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<UUID, SignalEdgeGroup> 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<UUID, Boolean> 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
|
@Override
|
||||||
public void read(CompoundTag nbt, boolean migration) {
|
public void read(CompoundTag nbt, boolean migration) {
|
||||||
super.read(nbt, migration);
|
super.read(nbt, migration);
|
||||||
|
|
||||||
if (migration)
|
if (migration)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sidesToUpdate = Couple.create(true, true);
|
blockEntities = Couple.create(HashSet::new);
|
||||||
signals = Couple.create(HashSet::new);
|
|
||||||
groups = Couple.create(null, null);
|
groups = Couple.create(null, null);
|
||||||
|
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
if (nbt.contains("Tiles" + i)) {
|
if (nbt.contains("Tiles" + i)) {
|
||||||
boolean first = i == 1;
|
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)));
|
.add(NbtUtils.readBlockPos(c)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
if (nbt.contains("Group" + i))
|
if (nbt.contains("Group" + i))
|
||||||
groups.set(i == 1, nbt.getUUID("Group" + i));
|
groups.set(i == 1, nbt.getUUID("Group" + i));
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
sidesToUpdate.set(i == 1, nbt.contains("Update" + 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
|
@Override
|
||||||
public void read(FriendlyByteBuf buffer) {
|
public void read(FriendlyByteBuf buffer) {
|
||||||
super.read(buffer);
|
super.read(buffer);
|
||||||
|
@ -161,17 +242,21 @@ public class SignalBoundary extends TrackEdgePoint {
|
||||||
public void write(CompoundTag nbt) {
|
public void write(CompoundTag nbt) {
|
||||||
super.write(nbt);
|
super.write(nbt);
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
if (!signals.get(i == 1)
|
if (!blockEntities.get(i == 1)
|
||||||
.isEmpty())
|
.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++)
|
for (int i = 1; i <= 2; i++)
|
||||||
if (groups.get(i == 1) != null)
|
if (groups.get(i == 1) != null)
|
||||||
nbt.putUUID("Group" + i, groups.get(i == 1));
|
nbt.putUUID("Group" + i, groups.get(i == 1));
|
||||||
for (int i = 1; i <= 2; i++)
|
for (int i = 1; i <= 2; i++)
|
||||||
if (sidesToUpdate.get(i == 1))
|
if (sidesToUpdate.get(i == 1))
|
||||||
nbt.putBoolean("Update" + i, true);
|
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
|
@Override
|
||||||
public void write(FriendlyByteBuf buffer) {
|
public void write(FriendlyByteBuf buffer) {
|
||||||
super.write(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]);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
package com.simibubi.create.content.logistics.trains.management.edgePoint.signal;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
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.Iterate;
|
||||||
import com.simibubi.create.foundation.utility.Pair;
|
import com.simibubi.create.foundation.utility.Pair;
|
||||||
|
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
public class SignalPropagator {
|
public class SignalPropagator {
|
||||||
|
|
||||||
public static void onSignalRemoved(TrackGraph graph, SignalBoundary signal) {
|
public static void onSignalRemoved(TrackGraph graph, SignalBoundary signal) {
|
||||||
|
@ -38,7 +41,7 @@ public class SignalPropagator {
|
||||||
SignalBoundary boundary = pair.getSecond();
|
SignalBoundary boundary = pair.getSecond();
|
||||||
boundary.queueUpdate(node1);
|
boundary.queueUpdate(node1);
|
||||||
return false;
|
return false;
|
||||||
}, Predicates.alwaysFalse());
|
}, Predicates.alwaysFalse(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +53,7 @@ public class SignalPropagator {
|
||||||
SignalBoundary boundary = pair.getSecond();
|
SignalBoundary boundary = pair.getSecond();
|
||||||
boundary.queueUpdate(node1);
|
boundary.queueUpdate(node1);
|
||||||
return false;
|
return false;
|
||||||
}, Predicates.alwaysFalse());
|
}, Predicates.alwaysFalse(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) {
|
public static void propagateSignalGroup(TrackGraph graph, SignalBoundary signal, boolean front) {
|
||||||
|
@ -82,11 +85,22 @@ public class SignalPropagator {
|
||||||
signalData.singleSignalGroup = groupId;
|
signalData.singleSignalGroup = groupId;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
});
|
}, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<UUID, Boolean> collectChainedSignals(TrackGraph graph, SignalBoundary signal, boolean front) {
|
||||||
|
HashMap<UUID, Boolean> 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,
|
public static void walkSignals(TrackGraph graph, SignalBoundary signal, boolean front,
|
||||||
Predicate<Pair<TrackNode, SignalBoundary>> boundaryCallback, Predicate<EdgeData> nonBoundaryCallback) {
|
Predicate<Pair<TrackNode, SignalBoundary>> boundaryCallback, Predicate<EdgeData> nonBoundaryCallback,
|
||||||
|
boolean forCollection) {
|
||||||
|
|
||||||
Couple<TrackNodeLocation> edgeLocation = signal.edgeLocation;
|
Couple<TrackNodeLocation> edgeLocation = signal.edgeLocation;
|
||||||
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
Couple<TrackNode> startNodes = edgeLocation.map(graph::locateNode);
|
||||||
|
@ -101,7 +115,8 @@ public class SignalPropagator {
|
||||||
if (startEdge == null)
|
if (startEdge == null)
|
||||||
return;
|
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
|
// Check for signal on the same edge
|
||||||
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
SignalBoundary immediateBoundary = startEdge.getEdgeData()
|
||||||
|
@ -115,11 +130,12 @@ public class SignalPropagator {
|
||||||
// Search for any connected signals
|
// Search for any connected signals
|
||||||
List<Couple<TrackNode>> frontier = new ArrayList<>();
|
List<Couple<TrackNode>> frontier = new ArrayList<>();
|
||||||
frontier.add(Couple.create(node2, node1));
|
frontier.add(Couple.create(node2, node1));
|
||||||
walkSignals(graph, frontier, boundaryCallback, nonBoundaryCallback);
|
walkSignals(graph, frontier, boundaryCallback, nonBoundaryCallback, forCollection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void walkSignals(TrackGraph graph, List<Couple<TrackNode>> frontier,
|
private static void walkSignals(TrackGraph graph, List<Couple<TrackNode>> frontier,
|
||||||
Predicate<Pair<TrackNode, SignalBoundary>> boundaryCallback, Predicate<EdgeData> nonBoundaryCallback) {
|
Predicate<Pair<TrackNode, SignalBoundary>> boundaryCallback, Predicate<EdgeData> nonBoundaryCallback,
|
||||||
|
boolean forCollection) {
|
||||||
Set<TrackEdge> visited = new HashSet<>();
|
Set<TrackEdge> visited = new HashSet<>();
|
||||||
while (!frontier.isEmpty()) {
|
while (!frontier.isEmpty()) {
|
||||||
Couple<TrackNode> couple = frontier.remove(0);
|
Couple<TrackNode> couple = frontier.remove(0);
|
||||||
|
@ -138,6 +154,16 @@ public class SignalPropagator {
|
||||||
if (!visited.add(edge))
|
if (!visited.add(edge))
|
||||||
continue;
|
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)
|
TrackEdge oppositeEdge = graph.getConnectionsFrom(nextNode)
|
||||||
.get(currentNode);
|
.get(currentNode);
|
||||||
visited.add(oppositeEdge);
|
visited.add(oppositeEdge);
|
||||||
|
|
|
@ -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.EdgePointType;
|
||||||
import com.simibubi.create.content.logistics.trains.management.edgePoint.TrackTargetingBehaviour;
|
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.SmartTileEntity;
|
||||||
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
|
||||||
import com.simibubi.create.foundation.utility.NBTHelper;
|
import com.simibubi.create.foundation.utility.NBTHelper;
|
||||||
|
@ -25,19 +26,23 @@ public class SignalTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static enum SignalState {
|
public static enum SignalState {
|
||||||
RED, GREEN, INVALID, TRAIN_ENTERING;
|
RED, YELLOW, GREEN, INVALID;
|
||||||
|
|
||||||
public boolean isRedLight(float renderTime) {
|
public boolean isRedLight(float renderTime) {
|
||||||
return this == RED || this == INVALID && renderTime % 40 < 3;
|
return this == RED || this == INVALID && renderTime % 40 < 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isGreenLight(float renderTime) {
|
public boolean isYellowLight(float renderTime) {
|
||||||
return this == GREEN || this == TRAIN_ENTERING;
|
return this == YELLOW;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isGreenLight(float renderTime) {
|
||||||
|
return this == GREEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TrackTargetingBehaviour<SignalBoundary> edgePoint;
|
public TrackTargetingBehaviour<SignalBoundary> edgePoint;
|
||||||
|
|
||||||
private SignalState state;
|
private SignalState state;
|
||||||
private OverlayState overlay;
|
private OverlayState overlay;
|
||||||
private int switchToRedAfterTrainEntered;
|
private int switchToRedAfterTrainEntered;
|
||||||
|
@ -67,7 +72,7 @@ public class SignalTileEntity extends SmartTileEntity {
|
||||||
public SignalBoundary getSignal() {
|
public SignalBoundary getSignal() {
|
||||||
return edgePoint.getEdgePoint();
|
return edgePoint.getEdgePoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPowered() {
|
public boolean isPowered() {
|
||||||
return state == SignalState.RED;
|
return state == SignalState.RED;
|
||||||
}
|
}
|
||||||
|
@ -94,12 +99,23 @@ public class SignalTileEntity extends SmartTileEntity {
|
||||||
super.tick();
|
super.tick();
|
||||||
if (level.isClientSide)
|
if (level.isClientSide)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SignalBoundary boundary = getSignal();
|
SignalBoundary boundary = getSignal();
|
||||||
if (boundary == null) {
|
if (boundary == null) {
|
||||||
enterState(SignalState.INVALID);
|
enterState(SignalState.INVALID);
|
||||||
setOverlay(OverlayState.RENDER);
|
setOverlay(OverlayState.RENDER);
|
||||||
return;
|
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));
|
enterState(boundary.getStateFor(worldPosition));
|
||||||
setOverlay(boundary.getOverlayFor(worldPosition));
|
setOverlay(boundary.getOverlayFor(worldPosition));
|
||||||
}
|
}
|
||||||
|
@ -127,7 +143,7 @@ public class SignalTileEntity extends SmartTileEntity {
|
||||||
if (state == SignalState.RED && switchToRedAfterTrainEntered > 0)
|
if (state == SignalState.RED && switchToRedAfterTrainEntered > 0)
|
||||||
return;
|
return;
|
||||||
this.state = state;
|
this.state = state;
|
||||||
switchToRedAfterTrainEntered = state == SignalState.GREEN ? 15 : 0;
|
switchToRedAfterTrainEntered = state == SignalState.GREEN || state == SignalState.YELLOW ? 15 : 0;
|
||||||
notifyUpdate();
|
notifyUpdate();
|
||||||
scheduleBlockTick();
|
scheduleBlockTick();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtUtils;
|
import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
public abstract class SingleTileEdgePoint extends TrackEdgePoint {
|
public abstract class SingleTileEdgePoint extends TrackEdgePoint {
|
||||||
|
|
||||||
|
@ -14,8 +15,8 @@ public abstract class SingleTileEdgePoint extends TrackEdgePoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tileAdded(BlockPos tilePos, boolean front) {
|
public void tileAdded(BlockEntity tile, boolean front) {
|
||||||
this.tilePos = tilePos;
|
this.tilePos = tile.getBlockPos();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,6 +18,7 @@ import net.minecraft.nbt.NbtUtils;
|
||||||
import net.minecraft.nbt.Tag;
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.network.FriendlyByteBuf;
|
import net.minecraft.network.FriendlyByteBuf;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||||
|
|
||||||
public abstract class TrackEdgePoint {
|
public abstract class TrackEdgePoint {
|
||||||
|
|
||||||
|
@ -59,7 +60,7 @@ public abstract class TrackEdgePoint {
|
||||||
behaviour.invalidateEdgePoint(migrationData);
|
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);
|
public abstract void tileRemoved(BlockPos tilePos, boolean front);
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ public abstract class TrackEdgePoint {
|
||||||
buffer.writeDouble(position);
|
buffer.writeDouble(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void tick(TrackGraph graph) {}
|
public void tick(TrackGraph graph, boolean preTrains) {}
|
||||||
|
|
||||||
protected void removeFromAllGraphs() {
|
protected void removeFromAllGraphs() {
|
||||||
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values())
|
for (TrackGraph trackGraph : Create.RAILWAYS.trackNetworks.values())
|
||||||
|
|
|
@ -496,7 +496,7 @@ public class StationTileEntity extends SmartTileEntity {
|
||||||
}
|
}
|
||||||
|
|
||||||
train.collectInitiallyOccupiedSignalBlocks();
|
train.collectInitiallyOccupiedSignalBlocks();
|
||||||
Create.RAILWAYS.trains.put(train.id, train);
|
Create.RAILWAYS.addTrain(train);
|
||||||
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, true));
|
AllPackets.channel.send(PacketDistributor.ALL.noArg(), new TrainPacket(train, true));
|
||||||
clearException();
|
clearException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -648,6 +648,10 @@
|
||||||
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
"create.train.relocate.invalid": "Cannot relocate Train to here",
|
||||||
"create.train.relocate.too_far": "Cannot relocate Train this far away",
|
"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.start_controlling": "Now controlling: %1$s",
|
||||||
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
|
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
|
||||||
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
|
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
|
||||||
|
|
|
@ -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"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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"}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -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]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 393 B |
Binary file not shown.
After Width: | Height: | Size: 340 B |
Binary file not shown.
Before Width: | Height: | Size: 303 B After Width: | Height: | Size: 323 B |
Binary file not shown.
After Width: | Height: | Size: 469 B |
Loading…
Reference in a new issue