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