Next level elevation

- Added the Contraption Controls
- Added the Elevator Pulley
- Pulley ropes are now climbable
- Lowered hitbox of seats for improved traversability inside contraptions
- Improved safety for players standing on vertically moving contraptions
- Fixed seated entities on controlled contraptions not rendering at the correct location
- Multiple pulleys can now attach to contraptions in a synchronised group
- Display Boards now update text instantaneously at high input rpm
This commit is contained in:
simibubi 2022-10-18 19:31:26 +02:00
parent 0c5ccf38ee
commit 1a475f7373
138 changed files with 5615 additions and 466 deletions

View file

@ -50,6 +50,7 @@ b59324f051f21d8ce1a48a08f4721a61a3c414d6 assets/create/blockstates/chute.json
1f33834c685e3243882acfe20183fe64dfa872be assets/create/blockstates/clutch.json
e5e3757e99c139d67b2a70288466d8a74d818841 assets/create/blockstates/cogwheel.json
36f54136a7756c97f71bc6b47ef4e8e575e72879 assets/create/blockstates/content_observer.json
7ecbf72c0557d97514aadc5a794bd8720c2fc48b assets/create/blockstates/contraption_controls.json
7d11142092c89ccba3e74e0a3bdd0ccb446d63b5 assets/create/blockstates/controller_rail.json
80d71365995d4c2a61dd1c15e99cae18551af6e8 assets/create/blockstates/controls.json
961b615124ea9a5a5735e8a79f81a702de7da2cf assets/create/blockstates/copper_backtank.json
@ -199,6 +200,8 @@ ac85f55d82d96fc15750e6b954297cfd1e00d04d assets/create/blockstates/deployer.json
62cc543abb242836570d07d619fcdb4c79c75db4 assets/create/blockstates/display_board.json
6766818ea63026a3af2fb9d81110d3887c74b0f8 assets/create/blockstates/display_link.json
30b3422bfee9878c92521429b2536d3e0313cedb assets/create/blockstates/dripstone_pillar.json
8c3ab1fc1fa0f705145212c62bde4787be392ac0 assets/create/blockstates/elevator_contact.json
98eaeef191c52eaf0f08cf2251237d704a4fc9ad assets/create/blockstates/elevator_pulley.json
35fc68eb1d031d28ad09b7b603e64ae459634179 assets/create/blockstates/encased_chain_drive.json
7b2b836649e729feafa60972bf95e3afb2143131 assets/create/blockstates/encased_fan.json
d13940ed213d7acbc6ebe3bdd21175ef89e4d613 assets/create/blockstates/encased_fluid_pipe.json
@ -558,24 +561,24 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json
c219c77242e645f32704201dd80e279b3759b794 assets/create/lang/en_us.json
cf37534c3f98098f42b181083fd7cc1063ac2bbb assets/create/lang/unfinished/de_de.json
83d427726fdc38ec3c5b8c3c0f6f87f49d3e5ff3 assets/create/lang/unfinished/es_cl.json
d21caeb0cbe871e38dc101c34ab89ece3cbe2127 assets/create/lang/unfinished/es_es.json
2215688baa2b0beffe0c19f71a3238df1d01b0c1 assets/create/lang/unfinished/fr_fr.json
79484f2c3eba2b40f5d82ffdc3abeb3d2e6962d2 assets/create/lang/unfinished/it_it.json
d659570c9dc89653f03cd4cc82ed50db443638d8 assets/create/lang/unfinished/ja_jp.json
03c30521d9b1bc7a6eb85d2a59a4c4676dca581e assets/create/lang/unfinished/ko_kr.json
3a56d579d022cc1b20746e9d3a1483e6fa8fb4be assets/create/lang/unfinished/nl_nl.json
d5bfeacb442236c8b075fddb41364f85c8cb7feb assets/create/lang/unfinished/pl_pl.json
0f3f51d065d896a7e3b4abd8c2801fa3e8fbd8c3 assets/create/lang/unfinished/pt_br.json
9f2ec0b2f8fa9b380c7edb56bfb806bcce621cce assets/create/lang/unfinished/pt_pt.json
1f88f0d91bdf5c68224cb65249f77272771939c9 assets/create/lang/unfinished/ro_ro.json
928ac3ad2ab5e7fa3d582b8b956258c110bea868 assets/create/lang/unfinished/ru_ru.json
ed29ef4ae8f3633533485d56f7fa8cb77b790a0a assets/create/lang/unfinished/uk_ua.json
e5cf7b657be816bc15b331dd058f7ccdabee8c14 assets/create/lang/unfinished/zh_cn.json
316dae07f95fb65c984fe7c424b566eb8ddba5f9 assets/create/lang/unfinished/zh_tw.json
030897fc54ff8948c4f75c12fc0cb75b7533a7d3 assets/create/lang/en_ud.json
b1efd3b09b9b99864c62946609e2fda2b27289ca assets/create/lang/en_us.json
0674019c1a174515a411399f8072014c0262e9e3 assets/create/lang/unfinished/de_de.json
c97060d5ac1e4e1ec44e9c24ddfe981414c5d38c assets/create/lang/unfinished/es_cl.json
118ccd144daec81fd505cd09f97d55dc054a663b assets/create/lang/unfinished/es_es.json
26fc490f390650044c853be59d6b27e2bd0accc5 assets/create/lang/unfinished/fr_fr.json
d64bcf8740ef1c117148388399f332015b1a35c2 assets/create/lang/unfinished/it_it.json
cc277bc6cc78bf7c943b428321d685a64bc25ebd assets/create/lang/unfinished/ja_jp.json
0c9199e23e24af99b7878b9278308ebf63db1eb9 assets/create/lang/unfinished/ko_kr.json
086ca8f196d987b1bb0b7cfe2b285c173d46a499 assets/create/lang/unfinished/nl_nl.json
0ce3cc278b14d36493f48aeb221ce9f6e7153b3f assets/create/lang/unfinished/pl_pl.json
7ef6bb7a596f4d5ac9273a0f5e8424229ca457ee assets/create/lang/unfinished/pt_br.json
c93a7d9275c0cc755e859ad57e352b9f1e2ee2f9 assets/create/lang/unfinished/pt_pt.json
c4aaebf10dd4a94e64d0fc2f48e4242d63cc6f71 assets/create/lang/unfinished/ro_ro.json
2fddf07de6613c3d680a645325d83d925c82aebc assets/create/lang/unfinished/ru_ru.json
ab7e76507c58c93e2e0619bbf78dd1a7c6459b00 assets/create/lang/unfinished/uk_ua.json
46e97308f1bfe26232952139f99d902f7f465c1a assets/create/lang/unfinished/zh_cn.json
d0d72e70e30f7d3a02293f15acd31e042deda59b 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
@ -1675,6 +1678,7 @@ c1da21be9f1af4f7a2ef4ec9cd92195d65ada316 assets/create/models/item/clockwork_bea
0a2a0f0aafeab0088172f77afd40c1fa2cc1f2b8 assets/create/models/item/clutch.json
dcb09deae110077bcddf090996b51cc66e9a7de3 assets/create/models/item/cogwheel.json
7717e3b21cff39f497f07687c70c1fa40eaa756d assets/create/models/item/content_observer.json
f5f1ad973341f8bebc474d5e65ff877ac6303b0d assets/create/models/item/contraption_controls.json
9dbd63c9e1b09a663fd4b83d76e3ab5967086167 assets/create/models/item/controller_rail.json
9a93b3ccef02cd0abd8106edec954dc0f2269229 assets/create/models/item/controls.json
10397036fc0bb1e18a767cfd7b19b10d805a83fe assets/create/models/item/copper_backtank.json
@ -1844,6 +1848,8 @@ df8cfe7e8eb527329094396e11222e9097e309d7 assets/create/models/item/diving_helmet
4b2af721dccfcf4e5b5a7b0f64f295d7cfd27f69 assets/create/models/item/dough.json
c25cd4d5cdf67b0d7e15f5a56c63e6bf35fe2917 assets/create/models/item/dripstone_pillar.json
5c45bf31bc4b6d2c6482318f19a660ad949d796b assets/create/models/item/electron_tube.json
5958eae9379424b0bdaef0d4230185773aa351e0 assets/create/models/item/elevator_contact.json
485f89a600a98141a2826ecef5bf32a83060efbf assets/create/models/item/elevator_pulley.json
971be8e52e8dfef50c8329be83f9c5d5ea869279 assets/create/models/item/empty_blaze_burner.json
5312db341e777c79feeaec99e5cb85bb99bb76ff assets/create/models/item/empty_schematic.json
cf34fd7e891a131d763126aa070d5b919e304a51 assets/create/models/item/encased_chain_drive.json
@ -3426,6 +3432,7 @@ bd4ed53c029fcd6e5da7e43ebe4d15030d3fd9de data/create/loot_tables/blocks/clockwor
8a5655e16f3da654e801cbfd81478c30180892a0 data/create/loot_tables/blocks/clutch.json
982a41e1bccd9a130a2874aff995d4f7da0f0316 data/create/loot_tables/blocks/cogwheel.json
c2b075008849e152f20e8da946e89c9722325df6 data/create/loot_tables/blocks/content_observer.json
69b4b25d7d271458177fbbaeba2c797daccc38a2 data/create/loot_tables/blocks/contraption_controls.json
28856dc862efc6bcc421d035d26386740458f868 data/create/loot_tables/blocks/controller_rail.json
2c2785e39e1891dff2c50cba93e814b56d935154 data/create/loot_tables/blocks/controls.json
3abf04f6132955275ad490668cd28f481afb4ec2 data/create/loot_tables/blocks/copper_backtank.json
@ -3574,6 +3581,8 @@ b6118279802f1a27e6e0c3d0feca86f0792f85df data/create/loot_tables/blocks/depot.js
2a8d81a07e9d209349264787eee93a0b973d2510 data/create/loot_tables/blocks/display_board.json
fd63effdc29cf565f561f8901a93c8ee3124bcaa data/create/loot_tables/blocks/display_link.json
7ab5f0aa32d6641999943636766c806a1d59e1d2 data/create/loot_tables/blocks/dripstone_pillar.json
5ef611585677ea3108fa034b2629434a98a9bb5c data/create/loot_tables/blocks/elevator_contact.json
3dd62aeec55972379dbf1b6a5033891cb190cbb2 data/create/loot_tables/blocks/elevator_pulley.json
2186860c4a0cb47a66bdfdefcde302c599cddeea data/create/loot_tables/blocks/encased_chain_drive.json
7fcc15674a7583b965441fb079b8997e4244a4ff data/create/loot_tables/blocks/encased_fan.json
b4df9a8b28f29587e75ffe11ca26d85ddbe926da data/create/loot_tables/blocks/encased_fluid_pipe.json
@ -5720,13 +5729,13 @@ cfa16b75227c9bf4f245c97ac55999b3903e5471 data/forge/tags/items/stripped_logs.jso
e002dfedc5e8762de0f97ea1f3fa546e92e748ae data/forge/tags/items/tools/wrench.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/azalea_root_replaceable.json
9f7a428085b1aac66da32a43e9d51c7efc1f0d81 data/minecraft/tags/blocks/beacon_base_blocks.json
dea0b54b33b1ae3b4fa8091dfcc4ad5687978ab1 data/minecraft/tags/blocks/climbable.json
f5cc2ea490ede338c9ea94a5775ad626b0ebc83b data/minecraft/tags/blocks/climbable.json
e16d74571ae10007f06f3b86ddf05d3ca9b73559 data/minecraft/tags/blocks/doors.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/dripstone_replaceable_blocks.json
69f596fcb065e26b02ce246760432b5174191b76 data/minecraft/tags/blocks/impermeable.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/lush_ground_replaceable.json
71480793b5e5ac5eb33c5271118c62227a2769d8 data/minecraft/tags/blocks/mineable/axe.json
77511f0fca91aa40c8b2566bf9bfb78964a56db3 data/minecraft/tags/blocks/mineable/pickaxe.json
f1d3b91aab8ea3c59a06b8ccc1a469b3ef953220 data/minecraft/tags/blocks/mineable/axe.json
95508e50d0c11690a4a8938c731930cca3384c90 data/minecraft/tags/blocks/mineable/pickaxe.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/moss_replaceable.json
e157c1d3af30e409e34bbefbe15a037e6e1c8daa data/minecraft/tags/blocks/needs_iron_tool.json
a08f67865337f62601c5e333b4011382d10020e4 data/minecraft/tags/blocks/needs_stone_tool.json

View file

@ -0,0 +1,124 @@
{
"variants": {
"facing=north,open=false,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=false,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=false,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=false,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=true,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=true,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=true,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=true,virtual=false,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=false,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=false,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=false,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=false,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=true,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=true,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=true,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=true,virtual=true,waterlogged=false": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=false,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=false,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=false,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=false,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=true,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=true,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=true,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=true,virtual=false,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=false,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=false,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=false,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=false,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 90
},
"facing=north,open=true,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block"
},
"facing=south,open=true,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 180
},
"facing=west,open=true,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 270
},
"facing=east,open=true,virtual=true,waterlogged=true": {
"model": "create:block/contraption_controls/block",
"y": 90
}
}
}

View file

@ -0,0 +1,212 @@
{
"variants": {
"calling=false,facing=down,powered=false,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 180
},
"calling=true,facing=down,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 180
},
"calling=false,facing=up,powered=false,powering=false": {
"model": "create:block/elevator_contact/block"
},
"calling=true,facing=up,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim"
},
"calling=false,facing=north,powered=false,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90
},
"calling=true,facing=north,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90
},
"calling=false,facing=south,powered=false,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 180
},
"calling=true,facing=south,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 180
},
"calling=false,facing=west,powered=false,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 270
},
"calling=true,facing=west,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 270
},
"calling=false,facing=east,powered=false,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 90
},
"calling=true,facing=east,powered=false,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 90
},
"calling=false,facing=down,powered=true,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 180
},
"calling=true,facing=down,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 180
},
"calling=false,facing=up,powered=true,powering=false": {
"model": "create:block/elevator_contact/block"
},
"calling=true,facing=up,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim"
},
"calling=false,facing=north,powered=true,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90
},
"calling=true,facing=north,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90
},
"calling=false,facing=south,powered=true,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 180
},
"calling=true,facing=south,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 180
},
"calling=false,facing=west,powered=true,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 270
},
"calling=true,facing=west,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 270
},
"calling=false,facing=east,powered=true,powering=false": {
"model": "create:block/elevator_contact/block",
"x": 90,
"y": 90
},
"calling=true,facing=east,powered=true,powering=false": {
"model": "create:block/elevator_contact/block_dim",
"x": 90,
"y": 90
},
"calling=false,facing=down,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 180
},
"calling=true,facing=down,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 180
},
"calling=false,facing=up,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered"
},
"calling=true,facing=up,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered"
},
"calling=false,facing=north,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90
},
"calling=true,facing=north,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90
},
"calling=false,facing=south,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 180
},
"calling=true,facing=south,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 180
},
"calling=false,facing=west,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 270
},
"calling=true,facing=west,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 270
},
"calling=false,facing=east,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 90
},
"calling=true,facing=east,powered=false,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 90
},
"calling=false,facing=down,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 180
},
"calling=true,facing=down,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 180
},
"calling=false,facing=up,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered"
},
"calling=true,facing=up,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered"
},
"calling=false,facing=north,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90
},
"calling=true,facing=north,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90
},
"calling=false,facing=south,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 180
},
"calling=true,facing=south,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 180
},
"calling=false,facing=west,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 270
},
"calling=true,facing=west,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 270
},
"calling=false,facing=east,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 90
},
"calling=true,facing=east,powered=true,powering=true": {
"model": "create:block/elevator_contact/block_powered",
"x": 90,
"y": 90
}
}
}

View file

@ -0,0 +1,19 @@
{
"variants": {
"facing=north": {
"model": "create:block/elevator_pulley/block"
},
"facing=south": {
"model": "create:block/elevator_pulley/block",
"y": 180
},
"facing=west": {
"model": "create:block/elevator_pulley/block",
"y": 270
},
"facing=east": {
"model": "create:block/elevator_pulley/block",
"y": 90
}
}
}

View file

@ -51,6 +51,7 @@
"block.create.clutch": "\u0265\u0254\u0287n\u05DF\u0186",
"block.create.cogwheel": "\u05DF\u01DD\u01DD\u0265\u028Dbo\u0186",
"block.create.content_observer": "\u0279\u01DD\u028C\u0279\u01DDsqO \u0287u\u01DD\u0287uo\u0186",
"block.create.contraption_controls": "s\u05DFo\u0279\u0287uo\u0186 uo\u0131\u0287d\u0250\u0279\u0287uo\u0186",
"block.create.controller_rail": "\u05DF\u0131\u0250\u1D1A \u0279\u01DD\u05DF\u05DFo\u0279\u0287uo\u0186",
"block.create.controls": "s\u05DFo\u0279\u0287uo\u0186 u\u0131\u0250\u0279\u27D8",
"block.create.copper_backtank": "\u029Eu\u0250\u0287\u029E\u0254\u0250\u15FA \u0279\u01DDddo\u0186",
@ -200,6 +201,8 @@
"block.create.display_board": "p\u0279\u0250o\u15FA \u028E\u0250\u05DFds\u0131\u15E1",
"block.create.display_link": "\u029Eu\u0131\uA780 \u028E\u0250\u05DFds\u0131\u15E1",
"block.create.dripstone_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 \u01DDuo\u0287sd\u0131\u0279\u15E1",
"block.create.elevator_contact": "\u0287\u0254\u0250\u0287uo\u0186 \u0279o\u0287\u0250\u028C\u01DD\u05DF\u018E",
"block.create.elevator_pulley": "\u028E\u01DD\u05DF\u05DFn\u0500 \u0279o\u0287\u0250\u028C\u01DD\u05DF\u018E",
"block.create.encased_chain_drive": "\u01DD\u028C\u0131\u0279\u15E1 u\u0131\u0250\u0265\u0186 p\u01DDs\u0250\u0254u\u018E",
"block.create.encased_fan": "u\u0250\u2132 p\u01DDs\u0250\u0254u\u018E",
"block.create.encased_fluid_pipe": "\u01DDd\u0131\u0500 p\u0131n\u05DF\u2132 p\u01DDs\u0250\u0254u\u018E",

View file

@ -54,6 +54,7 @@
"block.create.clutch": "Clutch",
"block.create.cogwheel": "Cogwheel",
"block.create.content_observer": "Content Observer",
"block.create.contraption_controls": "Contraption Controls",
"block.create.controller_rail": "Controller Rail",
"block.create.controls": "Train Controls",
"block.create.copper_backtank": "Copper Backtank",
@ -203,6 +204,8 @@
"block.create.display_board": "Display Board",
"block.create.display_link": "Display Link",
"block.create.dripstone_pillar": "Dripstone Pillar",
"block.create.elevator_contact": "Elevator Contact",
"block.create.elevator_pulley": "Elevator Pulley",
"block.create.encased_chain_drive": "Encased Chain Drive",
"block.create.encased_fan": "Encased Fan",
"block.create.encased_fluid_pipe": "Encased Fluid Pipe",
@ -1423,6 +1426,10 @@
"create.boiler.via_one_engine": "via 1 engine",
"create.boiler.via_engines": "via %1$s engines",
"create.elevator_contact.title": "Elevator Contact",
"create.elevator_contact.floor_identifier": "Floor Identifier",
"create.elevator_contact.floor_description": "Floor Description",
"create.gui.schedule.lmb_edit": "Left-Click to Edit",
"create.gui.schedule.rmb_remove": "Right-Click to Remove",
"create.gui.schedule.duplicate": "Duplicate",
@ -1628,6 +1635,10 @@
"create.contraption.controls.start_controlling": "Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "Stopped controlling contraption",
"create.contraption.controls.approach_station": "Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "%1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "On",
"create.contraption.controls.actor_toggle.off": "Off",
"create.display_link.set": "Targeted position selected",
"create.display_link.success": "Successfully bound to targeted position",
@ -1690,6 +1701,7 @@
"create.display_source.max_enchant_level": "Max Enchanting Cost",
"create.display_source.boiler_status": "Boiler Status",
"create.display_source.entity_name": "Entity Name",
"create.display_source.current_floor": "Elevator Location",
"create.display_source.kinetic_speed": "Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "Ignore Direction",
"create.display_source.kinetic_speed.directional": "Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 842",
"_": "Missing Localizations: 853",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Kupplung",
"block.create.cogwheel": "Zahnrad",
"block.create.content_observer": "Inhaltsbeobachter",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Steuerungsschiene",
"block.create.controls": "Zugsteuerung",
"block.create.copper_backtank": "Kupferne Druckluftflasche",
@ -204,6 +205,8 @@
"block.create.display_board": "Anzeigetafel",
"block.create.display_link": "Anzeige-Link",
"block.create.dripstone_pillar": "Tropfstein-Säule",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Ummantelter Kettenriemen",
"block.create.encased_fan": "Ummantelter Lüfter",
"block.create.encased_fluid_pipe": "Ummanteltes Rohr",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "mit einer Dampfmaschine",
"create.boiler.via_engines": "mit %1$s Dampfmaschinen",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "Links-Klick zum Bearbeiten",
"create.gui.schedule.rmb_remove": "Rechts-Klick zum Entfernen",
"create.gui.schedule.duplicate": "Duplizieren",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "Du steuerst jetzt: %1$s",
"create.contraption.controls.stop_controlling": "Du steuerst den Zug nicht mehr",
"create.contraption.controls.approach_station": "Halte %1$s gedrückt, um bei %2$s zu halten",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "Anvisierte Position ausgewählt",
"create.display_link.success": "Erfolgreich mit ausgewählter Position gebunden",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "Max. Verzauberungskosten",
"create.display_source.boiler_status": "Kesselstatus",
"create.display_source.entity_name": "Entitätenname",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "Drehgeschwindigkeit (RPM)",
"create.display_source.kinetic_speed.absolute": "Ignoriere Richtung",
"create.display_source.kinetic_speed.directional": "Beachte Richtung",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 988",
"_": "Missing Localizations: 999",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Embrague",
"block.create.cogwheel": "Engranaje",
"block.create.content_observer": "Observador de Contenidos",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Raíl Controlador",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "Tanque-Mochila de Cobre",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Conductor en Cadena Encubierto",
"block.create.encased_fan": "Ventilador Encubierto",
"block.create.encased_fluid_pipe": "Tubería de Fluidos Encubierta",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 8",
"_": "Missing Localizations: 19",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Embrague",
"block.create.cogwheel": "Engranaje",
"block.create.content_observer": "Observador de contenidos",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Raíl de control",
"block.create.controls": "Controles de tren",
"block.create.copper_backtank": "Depósito trasero de cobre",
@ -204,6 +205,8 @@
"block.create.display_board": "Pantalla de visualización",
"block.create.display_link": "Enlace de pantalla",
"block.create.dripstone_pillar": "Pilar de espeleotema",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Cadena de transmisión revestida",
"block.create.encased_fan": "Ventilador revestido",
"block.create.encased_fluid_pipe": "Tubería de fluidos de cobre reforzada",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "a través de 1 motor",
"create.boiler.via_engines": "a través de %1$s motores",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "Clic izquierdo para editar",
"create.gui.schedule.rmb_remove": "Clic derecho para eliminar",
"create.gui.schedule.duplicate": "Duplicar",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "Controlando actualmente: %1$s",
"create.contraption.controls.stop_controlling": "Se ha parado de controlar el artefacto móvil",
"create.contraption.controls.approach_station": "Mantén %1$s para acercarte a %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "Posición objetivo seleccionada",
"create.display_link.success": "Posición objetivo vinculada con éxito",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "Coste máximo de encantamiento",
"create.display_source.boiler_status": "Estado de la caldera",
"create.display_source.entity_name": "Nombre de la entidad",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "Velocidad de rotación (RPM)",
"create.display_source.kinetic_speed.absolute": "Ignorar dirección",
"create.display_source.kinetic_speed.directional": "Incluir dirección",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2139",
"_": "Missing Localizations: 2150",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Embrayage",
"block.create.cogwheel": "Roue dentée",
"block.create.content_observer": "Observateur de contenu",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Rails controlleurs",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "UNLOCALIZED: Copper Backtank",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Chaine de transmission",
"block.create.encased_fan": "Ventilateur enchâssé",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2",
"_": "Missing Localizations: 13",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Frizione",
"block.create.cogwheel": "Ingranaggio",
"block.create.content_observer": "Osservatore di contenuti",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Binario di controllo",
"block.create.controls": "Comandi del treno",
"block.create.copper_backtank": "Zaino serbatoio",
@ -204,6 +205,8 @@
"block.create.display_board": "Tabellone",
"block.create.display_link": "Lettore di dati",
"block.create.dripstone_pillar": "Pilastro di speleotema",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Trasmissione a catena",
"block.create.encased_fan": "Ventilatore",
"block.create.encased_fluid_pipe": "Tubo per fluidi rivestito",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "tramite 1 motore",
"create.boiler.via_engines": "tramite %1$s motori",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "Click sinistro per modificare",
"create.gui.schedule.rmb_remove": "Click destro per rimuovere",
"create.gui.schedule.duplicate": "Duplica",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "Al comando di: %1$s",
"create.contraption.controls.stop_controlling": "Hai smesso di guidare il macchinario",
"create.contraption.controls.approach_station": "Tieni premuto %1$s per fermarti a %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "Bersaglio selezionato",
"create.display_link.success": "Connesso con successo alla posizione selezionata",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "Livello massimo",
"create.display_source.boiler_status": "Stato della Caldaia",
"create.display_source.entity_name": "Nome entità",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "Velocità di rotazione",
"create.display_source.kinetic_speed.absolute": "Ignora direzione",
"create.display_source.kinetic_speed.directional": "Includi direzione",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 4",
"_": "Missing Localizations: 15",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "クラッチ",
"block.create.cogwheel": "歯車",
"block.create.content_observer": "コンテンツオブザーバー",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "コントローラーレール",
"block.create.controls": "列車運転台",
"block.create.copper_backtank": "銅のバックタンク",
@ -204,6 +205,8 @@
"block.create.display_board": "ディスプレイボード",
"block.create.display_link": "ディスプレイリンク",
"block.create.dripstone_pillar": "鍾乳石の柱",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "ケース入りチェーンドライブ",
"block.create.encased_fan": "ケース入りファン",
"block.create.encased_fluid_pipe": "ケース入り液体パイプ",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "1基のエンジン経由",
"create.boiler.via_engines": "%1$s基のエンジン経由",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "左クリックで編集",
"create.gui.schedule.rmb_remove": "右クリックで削除",
"create.gui.schedule.duplicate": "複製",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "運転中: %1$s",
"create.contraption.controls.stop_controlling": "運転終了",
"create.contraption.controls.approach_station": "%1$sキーを長押しで%2$sに停車",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "対象の位置を選択しました",
"create.display_link.success": "対象の位置と結び付けられました",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "最大エンチャントコスト",
"create.display_source.boiler_status": "ボイラー状態",
"create.display_source.entity_name": "エンティティ名",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "回転速度(RPM)",
"create.display_source.kinetic_speed.absolute": "回転方向を無視",
"create.display_source.kinetic_speed.directional": "回転方向を含める",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 8",
"_": "Missing Localizations: 19",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "클러치",
"block.create.cogwheel": "톱니바퀴",
"block.create.content_observer": "정보 감지기",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "방향 레일",
"block.create.controls": "기차 조종기",
"block.create.copper_backtank": "구리 산소통",
@ -204,6 +205,8 @@
"block.create.display_board": "디스플레이 화면",
"block.create.display_link": "디스플레이 링크",
"block.create.dripstone_pillar": "점적석 기둥",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "체인 드라이브",
"block.create.encased_fan": "선풍기",
"block.create.encased_fluid_pipe": "구리 케이스를 씌운 파이프",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "엔진 1개",
"create.boiler.via_engines": "엔진 %1$s개",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "좌클릭으로 수정",
"create.gui.schedule.rmb_remove": "우클릭으로 삭제",
"create.gui.schedule.duplicate": "복제",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "%1$s를 조종합니다",
"create.contraption.controls.stop_controlling": "구조물 조종을 멈췄습니다",
"create.contraption.controls.approach_station": "%1$s을(를) 눌러 %2$s에 접근합니다",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "표시할 대상을 선택했습니다",
"create.display_link.success": "성공적으로 대상과 연결되었습니다",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "최대 마법부여 수치",
"create.display_source.boiler_status": "보일러 상태",
"create.display_source.entity_name": "엔티티 이름",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "회전 속도 (RPM)",
"create.display_source.kinetic_speed.absolute": "방향 무시",
"create.display_source.kinetic_speed.directional": "방향 포함",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2487",
"_": "Missing Localizations: 2498",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Koppeling",
"block.create.cogwheel": "Tandwiel",
"block.create.content_observer": "UNLOCALIZED: Content Observer",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "UNLOCALIZED: Controller Rail",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "UNLOCALIZED: Copper Backtank",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "UNLOCALIZED: Encased Chain Drive",
"block.create.encased_fan": "Omhulsde Ventilator",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 12",
"_": "Missing Localizations: 23",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Sprzęgło",
"block.create.cogwheel": "Koło zębate",
"block.create.content_observer": "Detektor zawartości",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Tory sterujące",
"block.create.controls": "Kontroler pociągów",
"block.create.copper_backtank": "Miedziany zbiornik w plecaku",
@ -204,6 +205,8 @@
"block.create.display_board": "Tablica wyświetlająca",
"block.create.display_link": "Nadajnik wyświetlacza",
"block.create.dripstone_pillar": "Naciekowy filar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Izolowany przekaźnik łańcuchowy",
"block.create.encased_fan": "Izolowany wiatrak",
"block.create.encased_fluid_pipe": "Izolowana rura",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "poprzez 1 silnik",
"create.boiler.via_engines": "poprzez %1$s silniki(ów)",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "Kliknij LPM, aby edytować",
"create.gui.schedule.rmb_remove": "Kliknij PPM, aby usunąć",
"create.gui.schedule.duplicate": "Duplikuj",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "Teraz kontrolowane: %1$s",
"create.contraption.controls.stop_controlling": "Przestano kontrolować maszynę",
"create.contraption.controls.approach_station": "Przytrzymaj %1$s aby podjechać do %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "Pozycja docelowa zaznaczona",
"create.display_link.success": "Pomyślnie przypisano do pozycji docelowej",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "Maksymalny koszt zaklinania",
"create.display_source.boiler_status": "Stan boilera",
"create.display_source.entity_name": "Nazwa bytu",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "Prędkość obrotu (Ob/min)",
"create.display_source.kinetic_speed.absolute": "Ignoruj kierunek",
"create.display_source.kinetic_speed.directional": "Pokaż kierunek",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1331",
"_": "Missing Localizations: 1342",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Embreagem",
"block.create.cogwheel": "Roda Dentada",
"block.create.content_observer": "Observador de Conteúdo",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Trilho Controlador",
"block.create.controls": "Controles do trem",
"block.create.copper_backtank": "Tanque Traseiro de Cobre",
@ -204,6 +205,8 @@
"block.create.display_board": "Placa de exibição",
"block.create.display_link": "Conexão de placa de exibição",
"block.create.dripstone_pillar": "Pilar de espeleotema",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Correia Revestida",
"block.create.encased_fan": "Ventilador Revestida",
"block.create.encased_fluid_pipe": "Cano de Fluidos Revestido",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2196",
"_": "Missing Localizations: 2207",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Embreagem",
"block.create.cogwheel": "Roda Dentada",
"block.create.content_observer": "Observador de Conteúdo",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Trilho Controlador",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "Tanque Traseiro de Cobre",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Correia Revestida",
"block.create.encased_fan": "Ventilador Revestida",
"block.create.encased_fluid_pipe": "Cano de Fluidos Revestido",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 655",
"_": "Missing Localizations: 666",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Ambreiaj",
"block.create.cogwheel": "Roată Dințată",
"block.create.content_observer": "Observator De Conținut",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Controlor De Șină",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "Backtank De Cupru",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "Coloană De Dripstone",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Lanț De Distribuție Încapsulat",
"block.create.encased_fan": "Ventilator Încapsulat",
"block.create.encased_fluid_pipe": "Conductă De Fluide Încapsulată",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 0",
"_": "Missing Localizations: 11",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Сцепление",
"block.create.cogwheel": "Шестерня",
"block.create.content_observer": "Наблюдатель за содержимым",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Контролирующие рельсы",
"block.create.controls": "Контроллер поезда",
"block.create.copper_backtank": "Медный баллон",
@ -204,6 +205,8 @@
"block.create.display_board": "Механическое табло",
"block.create.display_link": "Передатчик информации",
"block.create.dripstone_pillar": "Колонна из натёчного камня",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Цепной привод в корпусе",
"block.create.encased_fan": "Вентилятор в корпусе",
"block.create.encased_fluid_pipe": "Жидкостная труба в корпусе",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "с помощью 1 двигателя",
"create.boiler.via_engines": "с помощью %1$s двигателей",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "ЛКМ для редактирования",
"create.gui.schedule.rmb_remove": "ПКМ для удаления",
"create.gui.schedule.duplicate": "Дублировать",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "Под управлением: %1$s",
"create.contraption.controls.stop_controlling": "Выход из режима управления",
"create.contraption.controls.approach_station": "Зажмите %1$s для прибытия на %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "Выбрана целевая позиция",
"create.display_link.success": "Успешно привязан к целевой позиции",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "Уровень чар",
"create.display_source.boiler_status": "Статус котла",
"create.display_source.entity_name": "Имя существа",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "Обороты в минуту",
"create.display_source.kinetic_speed.absolute": "Без направления",
"create.display_source.kinetic_speed.directional": "С направлением",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 986",
"_": "Missing Localizations: 997",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "Зчеплення",
"block.create.cogwheel": "Шестірня",
"block.create.content_observer": "Спостерігач вмісту",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "Контролерна рейка",
"block.create.controls": "UNLOCALIZED: Train Controls",
"block.create.copper_backtank": "Мідний резервуар",
@ -204,6 +205,8 @@
"block.create.display_board": "UNLOCALIZED: Display Board",
"block.create.display_link": "UNLOCALIZED: Display Link",
"block.create.dripstone_pillar": "UNLOCALIZED: Dripstone Pillar",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "Ланцюговий привід у корпусі",
"block.create.encased_fan": "Вентилятор у корпусі",
"block.create.encased_fluid_pipe": "Труба для рідини в корпусі",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "UNLOCALIZED: via 1 engine",
"create.boiler.via_engines": "UNLOCALIZED: via %1$s engines",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "UNLOCALIZED: Left-Click to Edit",
"create.gui.schedule.rmb_remove": "UNLOCALIZED: Right-Click to Remove",
"create.gui.schedule.duplicate": "UNLOCALIZED: Duplicate",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "UNLOCALIZED: Now controlling: %1$s",
"create.contraption.controls.stop_controlling": "UNLOCALIZED: Stopped controlling contraption",
"create.contraption.controls.approach_station": "UNLOCALIZED: Hold %1$s to approach %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "UNLOCALIZED: Targeted position selected",
"create.display_link.success": "UNLOCALIZED: Successfully bound to targeted position",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "UNLOCALIZED: Max Enchanting Cost",
"create.display_source.boiler_status": "UNLOCALIZED: Boiler Status",
"create.display_source.entity_name": "UNLOCALIZED: Entity Name",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "UNLOCALIZED: Rotation Speed (RPM)",
"create.display_source.kinetic_speed.absolute": "UNLOCALIZED: Ignore Direction",
"create.display_source.kinetic_speed.directional": "UNLOCALIZED: Include Direction",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 0",
"_": "Missing Localizations: 11",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "离合器",
"block.create.cogwheel": "齿轮",
"block.create.content_observer": "物品侦测器",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "控制铁轨",
"block.create.controls": "列车驾驶台",
"block.create.copper_backtank": "铜背罐",
@ -204,6 +205,8 @@
"block.create.display_board": "翻牌显示器",
"block.create.display_link": "显示链接器",
"block.create.dripstone_pillar": "滴水石柱",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "链式传动箱",
"block.create.encased_fan": "鼓风机",
"block.create.encased_fluid_pipe": "流体管道箱",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "通过1个引擎",
"create.boiler.via_engines": "通过%1$s个引擎",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "左键点击编辑",
"create.gui.schedule.rmb_remove": "右键点击移除",
"create.gui.schedule.duplicate": "复制",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "现在控制:%1$s",
"create.contraption.controls.stop_controlling": "停止控制装置",
"create.contraption.controls.approach_station": "按住%1$s以接近%2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "已选择目标位置",
"create.display_link.success": "成功绑定到目标位置",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "最大附魔花费",
"create.display_source.boiler_status": "锅炉状态",
"create.display_source.entity_name": "实体名称",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "转速RPM",
"create.display_source.kinetic_speed.absolute": "无视转向",
"create.display_source.kinetic_speed.directional": "包含转向",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 8",
"_": "Missing Localizations: 19",
"_": "->------------------------] Game Elements [------------------------<-",
@ -55,6 +55,7 @@
"block.create.clutch": "離合器",
"block.create.cogwheel": "齒輪",
"block.create.content_observer": "物品偵測器",
"block.create.contraption_controls": "UNLOCALIZED: Contraption Controls",
"block.create.controller_rail": "控制軌道",
"block.create.controls": "火車控制台",
"block.create.copper_backtank": "銅製後背包",
@ -204,6 +205,8 @@
"block.create.display_board": "顯示板",
"block.create.display_link": "顯示鏈路",
"block.create.dripstone_pillar": "鐘乳石柱",
"block.create.elevator_contact": "UNLOCALIZED: Elevator Contact",
"block.create.elevator_pulley": "UNLOCALIZED: Elevator Pulley",
"block.create.encased_chain_drive": "鏈式傳動箱",
"block.create.encased_fan": "鼓風機",
"block.create.encased_fluid_pipe": "流體管道箱",
@ -1424,6 +1427,10 @@
"create.boiler.via_one_engine": "透過 1 個引擎",
"create.boiler.via_engines": "透過 %1$s 個引擎",
"create.elevator_contact.title": "UNLOCALIZED: Elevator Contact",
"create.elevator_contact.floor_identifier": "UNLOCALIZED: Floor Identifier",
"create.elevator_contact.floor_description": "UNLOCALIZED: Floor Description",
"create.gui.schedule.lmb_edit": "左鍵點擊編輯",
"create.gui.schedule.rmb_remove": "右鍵點擊移除",
"create.gui.schedule.duplicate": "複製",
@ -1629,6 +1636,10 @@
"create.contraption.controls.start_controlling": "正在控制:%1$s",
"create.contraption.controls.stop_controlling": "停止控制裝置",
"create.contraption.controls.approach_station": "按住 %1$s 以接近 %2$s",
"create.contraption.controls.specific_actor_toggle": "UNLOCALIZED: %1$s Actors: %2$s",
"create.contraption.controls.all_actor_toggle": "UNLOCALIZED: All Actors: %1$s",
"create.contraption.controls.actor_toggle.on": "UNLOCALIZED: On",
"create.contraption.controls.actor_toggle.off": "UNLOCALIZED: Off",
"create.display_link.set": "已選定目標位置",
"create.display_link.success": "成功綁定到目標位置",
@ -1691,6 +1702,7 @@
"create.display_source.max_enchant_level": "最大附魔費用",
"create.display_source.boiler_status": "鍋爐狀態",
"create.display_source.entity_name": "實體名稱",
"create.display_source.current_floor": "UNLOCALIZED: Elevator Location",
"create.display_source.kinetic_speed": "轉速 (RPM)",
"create.display_source.kinetic_speed.absolute": "無視轉向",
"create.display_source.kinetic_speed.directional": "顯示轉向",

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/contraption_controls/item"
}

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/elevator_contact/block"
}

View file

@ -0,0 +1,3 @@
{
"parent": "create:block/elevator_pulley/item"
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "create:contraption_controls"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "create:redstone_contact"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,20 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1.0,
"bonus_rolls": 0.0,
"entries": [
{
"type": "minecraft:item",
"name": "create:elevator_pulley"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -3,6 +3,8 @@
"values": [
"create:andesite_ladder",
"create:brass_ladder",
"create:copper_ladder"
"create:copper_ladder",
"create:rope",
"create:pulley_magnet"
]
}

View file

@ -42,10 +42,12 @@
"create:mechanical_bearing",
"create:clockwork_bearing",
"create:rope_pulley",
"create:elevator_pulley",
"create:cart_assembler",
"create:linear_chassis",
"create:secondary_linear_chassis",
"create:radial_chassis",
"create:contraption_controls",
"create:mechanical_drill",
"create:mechanical_saw",
"create:deployer",
@ -97,6 +99,7 @@
"create:rotation_speed_controller",
"create:mechanical_arm",
"create:railway_casing",
"create:elevator_contact",
"create:content_observer",
"create:stockpile_switch",
"create:creative_crate",

View file

@ -89,12 +89,14 @@
"create:mechanical_bearing",
"create:clockwork_bearing",
"create:rope_pulley",
"create:elevator_pulley",
"create:cart_assembler",
"create:controller_rail",
"create:linear_chassis",
"create:secondary_linear_chassis",
"create:radial_chassis",
"create:sticker",
"create:contraption_controls",
"create:mechanical_drill",
"create:mechanical_saw",
"create:deployer",
@ -124,6 +126,7 @@
"create:train_trapdoor",
"create:framed_glass_door",
"create:framed_glass_trapdoor",
"create:elevator_contact",
"create:item_vault",
"create:andesite_funnel",
"create:andesite_belt_funnel",

View file

@ -1,7 +1,9 @@
package com.simibubi.create;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jozufozu.flywheel.core.PartialModel;
@ -64,6 +66,9 @@ public class AllBlockPartials {
HOSE_MAGNET = block("hose_pulley/pulley_magnet"), HOSE_HALF = block("hose_pulley/rope_half"),
HOSE_HALF_MAGNET = block("hose_pulley/rope_half_magnet"),
ELEVATOR_COIL = block("elevator_pulley/rope_coil"), ELEVATOR_MAGNET = block("elevator_pulley/pulley_magnet"),
ELEVATOR_BELT = block("elevator_pulley/rope"), ELEVATOR_BELT_HALF = block("elevator_pulley/rope_half"),
MILLSTONE_COG = block("millstone/inner"),
SYMMETRY_PLANE = block("symmetry_effect/plane"), SYMMETRY_CROSSPLANE = block("symmetry_effect/crossplane"),
@ -120,6 +125,7 @@ public class AllBlockPartials {
TRAIN_COUPLING_CABLE = block("track/bogey/coupling_cable"),
TRAIN_CONTROLS_COVER = block("controls/train/cover"), TRAIN_CONTROLS_LEVER = block("controls/train/lever"),
CONTRAPTION_CONTROLS_BUTTON = block("contraption_controls/button"),
ENGINE_PISTON = block("steam_engine/piston"), ENGINE_LINKAGE = block("steam_engine/linkage"),
ENGINE_CONNECTOR = block("steam_engine/shaft_connector"), BOILER_GAUGE = block("steam_engine/gauge"),
@ -166,6 +172,7 @@ public class AllBlockPartials {
public static final Map<Direction, PartialModel> METAL_GIRDER_BRACKETS = new EnumMap<>(Direction.class);
public static final Map<DyeColor, PartialModel> TOOLBOX_LIDS = new EnumMap<>(DyeColor.class);
public static final List<PartialModel> CONTRAPTION_CONTROLS_INDICATOR = new ArrayList<>();
static {
for (FluidTransportBehaviour.AttachmentTypes.ComponentPartials type : FluidTransportBehaviour.AttachmentTypes.ComponentPartials.values()) {
@ -180,6 +187,8 @@ public class AllBlockPartials {
TOOLBOX_LIDS.put(color, block("toolbox/lid/" + Lang.asId(color.name())));
for (Direction d : Iterate.horizontalDirections)
METAL_GIRDER_BRACKETS.put(d, block("metal_girder/bracket_" + Lang.asId(d.name())));
for (int i = 0; i < 8; i++)
CONTRAPTION_CONTROLS_INDICATOR.add(block("contraption_controls/indicator_" + i));
}
private static PartialModel block(String path) {

View file

@ -31,6 +31,9 @@ import com.simibubi.create.content.contraptions.components.actors.SawMovementBeh
import com.simibubi.create.content.contraptions.components.actors.SeatBlock;
import com.simibubi.create.content.contraptions.components.actors.SeatInteractionBehaviour;
import com.simibubi.create.content.contraptions.components.actors.SeatMovementBehaviour;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsBlock;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovingInteraction;
import com.simibubi.create.content.contraptions.components.clock.CuckooClockBlock;
import com.simibubi.create.content.contraptions.components.crafter.CrafterCTBehaviour;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterBlock;
@ -66,6 +69,8 @@ import com.simibubi.create.content.contraptions.components.structureMovement.cha
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.LinearChassisBlock.ChassisCTBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.RadialChassisBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContactBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorPulleyBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsInteractionBehaviour;
@ -165,6 +170,7 @@ import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlockItem;
import com.simibubi.create.content.logistics.block.display.source.AccumulatedItemCountDisplaySource;
import com.simibubi.create.content.logistics.block.display.source.BoilerDisplaySource;
import com.simibubi.create.content.logistics.block.display.source.CurrentFloorDisplaySource;
import com.simibubi.create.content.logistics.block.display.source.EntityNameDisplaySource;
import com.simibubi.create.content.logistics.block.display.source.FillLevelDisplaySource;
import com.simibubi.create.content.logistics.block.display.source.FluidAmountDisplaySource;
@ -197,6 +203,7 @@ import com.simibubi.create.content.logistics.block.redstone.ContentObserverBlock
import com.simibubi.create.content.logistics.block.redstone.NixieTubeBlock;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeGenerator;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactItem;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkBlock;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkGenerator;
import com.simibubi.create.content.logistics.block.redstone.RoseQuartzLampBlock;
@ -1135,6 +1142,7 @@ public class AllBlocks {
public static final BlockEntry<PulleyBlock.RopeBlock> ROPE = REGISTRATE.block("rope", PulleyBlock.RopeBlock::new)
.initialProperties(SharedProperties.BELT_MATERIAL, MaterialColor.COLOR_BROWN)
.tag(AllBlockTags.BRITTLE.tag)
.tag(BlockTags.CLIMBABLE)
.properties(p -> p.sound(SoundType.WOOL))
.blockstate((c, p) -> p.simpleBlock(c.get(), p.models()
.getExistingFile(p.modLoc("block/rope_pulley/" + c.getName()))))
@ -1144,10 +1152,22 @@ public class AllBlocks {
REGISTRATE.block("pulley_magnet", PulleyBlock.MagnetBlock::new)
.initialProperties(SharedProperties::stone)
.tag(AllBlockTags.BRITTLE.tag)
.tag(BlockTags.CLIMBABLE)
.blockstate((c, p) -> p.simpleBlock(c.get(), p.models()
.getExistingFile(p.modLoc("block/rope_pulley/" + c.getName()))))
.register();
public static final BlockEntry<ElevatorPulleyBlock> ELEVATOR_PULLEY =
REGISTRATE.block("elevator_pulley", ElevatorPulleyBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN))
.transform(axeOrPickaxe())
.blockstate(BlockStateGen.horizontalBlockProvider(true))
.transform(BlockStressDefaults.setImpact(4.0))
.item()
.transform(customItemModel())
.register();
public static final BlockEntry<CartAssemblerBlock> CART_ASSEMBLER =
REGISTRATE.block("cart_assembler", CartAssemblerBlock::new)
.initialProperties(SharedProperties::stone)
@ -1229,6 +1249,19 @@ public class AllBlocks {
.transform(customItemModel())
.register();
public static final BlockEntry<ContraptionControlsBlock> CONTRAPTION_CONTROLS =
REGISTRATE.block("contraption_controls", ContraptionControlsBlock::new)
.initialProperties(SharedProperties::stone)
.properties(p -> p.color(MaterialColor.PODZOL))
.addLayer(() -> RenderType::cutoutMipped)
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.horizontalBlock(c.get(), s -> AssetLookup.partialBaseModel(c, p)))
.onRegister(movementBehaviour(new ContraptionControlsMovement()))
.onRegister(interactionBehaviour(new ContraptionControlsMovingInteraction()))
.item()
.transform(customItemModel())
.register();
public static final BlockEntry<DrillBlock> MECHANICAL_DRILL = REGISTRATE.block("mechanical_drill", DrillBlock::new)
.initialProperties(SharedProperties::stone)
.properties(p -> p.color(MaterialColor.PODZOL))
@ -1282,7 +1315,7 @@ public class AllBlocks {
.transform(axeOrPickaxe())
.onRegister(movementBehaviour(new ContactMovementBehaviour()))
.blockstate((c, p) -> p.directionalBlock(c.get(), AssetLookup.forPowered(c, p)))
.item()
.item(RedstoneContactItem::new)
.transform(customItemModel("_", "block"))
.register();
@ -1579,7 +1612,7 @@ public class AllBlocks {
.transform(BuilderTransformers.bogey())
.register();
public static final BlockEntry<ControlsBlock> CONTROLS = REGISTRATE.block("controls", ControlsBlock::new)
public static final BlockEntry<ControlsBlock> TRAIN_CONTROLS = REGISTRATE.block("controls", ControlsBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_BROWN))
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK))
@ -1629,9 +1662,28 @@ public class AllBlocks {
.addLayer(() -> RenderType::cutoutMipped)
.register();
public static final BlockEntry<ElevatorContactBlock> ELEVATOR_CONTACT =
REGISTRATE.block("elevator_contact", ElevatorContactBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW))
.properties(p -> p.lightLevel(ElevatorContactBlock::getLight))
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.directionalBlock(c.get(), state -> {
Boolean calling = state.getValue(ElevatorContactBlock.CALLING);
Boolean powering = state.getValue(ElevatorContactBlock.POWERING);
return powering ? AssetLookup.partialBaseModel(c, p, "powered")
: calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p);
}))
.loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get()))
.onRegister(assignDataBehaviour(new CurrentFloorDisplaySource(), "current_floor"))
.item()
.transform(customItemModel("_", "block"))
.register();
public static final BlockEntry<ItemVaultBlock> ITEM_VAULT = REGISTRATE.block("item_vault", ItemVaultBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_BLUE))
.properties(p -> p.color(
MaterialColor.TERRACOTTA_BLUE))
.properties(p -> p.sound(SoundType.NETHERITE_BLOCK)
.explosionResistance(1200))
.transform(pickaxeOnly())

View file

@ -3,7 +3,7 @@ package com.simibubi.create;
import java.util.ArrayList;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import javax.annotation.Nullable;
import com.simibubi.create.content.contraptions.components.actors.BellMovementBehaviour;
import com.simibubi.create.content.contraptions.components.actors.CampfireMovementBehaviour;

View file

@ -41,6 +41,9 @@ public class AllShapes {
.add(2, 13, 2, 14, 16, 14)
.add(0, 0, 14, 16, 16, 16)
.forHorizontalAxis(),
ELEVATOR_PULLEY = shape(0, 0, 0, 16, 16, 2).add(0, 0, 14, 16, 16, 16)
.add(2, 0, 2, 14, 14, 14)
.forHorizontal(EAST),
SAIL_FRAME_COLLISION = shape(0, 5, 0, 16, 9, 16).erase(2, 0, 2, 14, 16, 14)
.forDirectional(),
SAIL_FRAME = shape(0, 5, 0, 16, 9, 16).forDirectional(), SAIL = shape(0, 5, 0, 16, 10, 16).forDirectional(),
@ -122,6 +125,10 @@ public class AllShapes {
.forHorizontalAxis(),
CONTROLS = shape(0, 0, 6, 16, 14, 16).forHorizontal(NORTH),
CONTRAPTION_CONTROLS = shape(0, 0, 6, 2, 14, 16).add(14, 0, 6, 16, 14, 16)
.add(0, 0, 14, 16, 14, 16)
.add(0, 0, 7, 16, 10, 16)
.forHorizontal(NORTH),
NIXIE_TUBE = shape(9, 0, 5, 15, 12, 11).add(1, 0, 5, 7, 12, 11)
.forHorizontalAxis(),
@ -181,8 +188,8 @@ public class AllShapes {
// Static Block Shapes
public static final VoxelShape
TRACK_CROSS = shape(TRACK_ORTHO.get(SOUTH)).add(TRACK_ORTHO.get(EAST))
.build(),
TRACK_CROSS = shape(TRACK_ORTHO.get(SOUTH)).add(TRACK_ORTHO.get(EAST))
.build(),
TRACK_CROSS_DIAG = shape(TRACK_DIAG.get(SOUTH)).add(TRACK_DIAG.get(EAST))
.build(),
@ -211,6 +218,7 @@ public class AllShapes {
HEATER_BLOCK_SPECIAL_COLLISION_SHAPE = shape(0, 0, 0, 16, 4, 16).build(),
CRUSHING_WHEEL_COLLISION_SHAPE = cuboid(0, 0, 0, 16, 16, 16), SEAT = cuboid(0, 0, 0, 16, 8, 16),
SEAT_COLLISION = cuboid(0, 0, 0, 16, 6, 16),
SEAT_COLLISION_PLAYERS = cuboid(0, 0, 0, 16, 3, 16),
MECHANICAL_PROCESSOR_SHAPE = shape(Shapes.block()).erase(4, 0, 4, 12, 16, 12)
.build(),
TURNTABLE_SHAPE = shape(1, 4, 1, 15, 8, 15).add(5, 0, 5, 11, 4, 11)

View file

@ -54,13 +54,18 @@ public class AllSpriteShifts {
CHASSIS_STICKY = omni("linear_chassis_end_sticky");
public static final CTSpriteShiftEntry BRASS_TUNNEL_TOP = vertical("brass_tunnel_top"),
FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "fluid_tank"), FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "fluid_tank_top"),
FLUID_TANK = getCT(AllCTTypes.RECTANGLE, "fluid_tank"),
FLUID_TANK_TOP = getCT(AllCTTypes.RECTANGLE, "fluid_tank_top"),
FLUID_TANK_INNER = getCT(AllCTTypes.RECTANGLE, "fluid_tank_inner"),
CREATIVE_FLUID_TANK = getCT(AllCTTypes.CROSS, "creative_fluid_tank");
public static final Couple<CTSpriteShiftEntry> VAULT_TOP = vault("top"), VAULT_FRONT = vault("front"),
VAULT_SIDE = vault("side"), VAULT_BOTTOM = vault("bottom");
public static final SpriteShiftEntry ELEVATOR_BELT =
get("block/elevator_pulley_belt", "block/elevator_pulley_belt_scroll"),
ELEVATOR_COIL = get("block/elevator_pulley_coil", "block/elevator_pulley_coil_scroll");
public static final SpriteShiftEntry BELT = get("block/belt", "block/belt_scroll"),
BELT_OFFSET = get("block/belt_offset", "block/belt_scroll"),
BELT_DIAGONAL = get("block/belt_diagonal", "block/belt_diagonal_scroll"),

View file

@ -17,6 +17,8 @@ import com.simibubi.create.content.contraptions.components.actors.PSIInstance;
import com.simibubi.create.content.contraptions.components.actors.PortableFluidInterfaceTileEntity;
import com.simibubi.create.content.contraptions.components.actors.PortableItemInterfaceTileEntity;
import com.simibubi.create.content.contraptions.components.actors.PortableStorageInterfaceRenderer;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsRenderer;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsTileEntity;
import com.simibubi.create.content.contraptions.components.clock.CuckooClockRenderer;
import com.simibubi.create.content.contraptions.components.clock.CuckooClockTileEntity;
import com.simibubi.create.content.contraptions.components.crafter.MechanicalCrafterInstance;
@ -65,6 +67,9 @@ import com.simibubi.create.content.contraptions.components.structureMovement.cha
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.chassis.StickerTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContactTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorPulleyRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorPulleyTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageInstance;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryCarriageTileEntity;
@ -476,6 +481,18 @@ public class AllTileEntities {
.renderer(() -> PulleyRenderer::new)
.register();
public static final BlockEntityEntry<ElevatorPulleyTileEntity> ELEVATOR_PULLEY = Create.registrate()
.tileEntity("elevator_pulley", ElevatorPulleyTileEntity::new)
// .instance(() -> ElevatorPulleyInstance::new, false)
.validBlocks(AllBlocks.ELEVATOR_PULLEY)
.renderer(() -> ElevatorPulleyRenderer::new)
.register();
public static final BlockEntityEntry<ElevatorContactTileEntity> ELEVATOR_CONTACT = Create.registrate()
.tileEntity("elevator_contact", ElevatorContactTileEntity::new)
.validBlocks(AllBlocks.ELEVATOR_CONTACT)
.register();
public static final BlockEntityEntry<ChassisTileEntity> CHASSIS = Create.registrate()
.tileEntity("chassis", ChassisTileEntity::new)
.validBlocks(AllBlocks.RADIAL_CHASSIS, AllBlocks.LINEAR_CHASSIS, AllBlocks.SECONDARY_LINEAR_CHASSIS)
@ -488,6 +505,12 @@ public class AllTileEntities {
.validBlocks(AllBlocks.STICKER)
.renderer(() -> StickerRenderer::new)
.register();
public static final BlockEntityEntry<ContraptionControlsTileEntity> CONTRAPTION_CONTROLS = Create.registrate()
.tileEntity("contraption_controls", ContraptionControlsTileEntity::new)
.validBlocks(AllBlocks.CONTRAPTION_CONTROLS)
.renderer(() -> ContraptionControlsRenderer::new)
.register();
public static final BlockEntityEntry<DrillTileEntity> DRILL = Create.registrate()
.tileEntity("drill", DrillTileEntity::new)
@ -653,7 +676,7 @@ public class AllTileEntities {
.validBlocks(AllBlocks.ANALOG_LEVER)
.renderer(() -> AnalogLeverRenderer::new)
.register();
public static final BlockEntityEntry<PlacardTileEntity> PLACARD = Create.registrate()
.tileEntity("placard", PlacardTileEntity::new)
.validBlocks(AllBlocks.PLACARD)
@ -780,7 +803,7 @@ public class AllTileEntities {
.renderer(() -> TrackRenderer::new)
.validBlocks(AllBlocks.TRACK)
.register();
public static final BlockEntityEntry<FakeTrackTileEntity> FAKE_TRACK = Create.registrate()
.tileEntity("fake_track", FakeTrackTileEntity::new)
.validBlocks(AllBlocks.FAKE_TRACK)
@ -797,7 +820,7 @@ public class AllTileEntities {
.renderer(() -> StationRenderer::new)
.validBlocks(AllBlocks.TRACK_STATION)
.register();
public static final BlockEntityEntry<SlidingDoorTileEntity> SLIDING_DOOR = Create.registrate()
.tileEntity("sliding_door", SlidingDoorTileEntity::new)
.renderer(() -> SlidingDoorRenderer::new)
@ -816,7 +839,7 @@ public class AllTileEntities {
.renderer(() -> SignalRenderer::new)
.validBlocks(AllBlocks.TRACK_SIGNAL)
.register();
public static final BlockEntityEntry<TrackObserverTileEntity> TRACK_OBSERVER = Create.registrate()
.tileEntity("track_observer", TrackObserverTileEntity::new)
.renderer(() -> TrackObserverRenderer::new)

View file

@ -24,8 +24,9 @@ public class DrillMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(DrillBlock.FACING)
.getOpposite());
return super.isActive(context)
&& !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(DrillBlock.FACING)
.getOpposite());
}
@Override

View file

@ -45,30 +45,31 @@ public class HarvesterActorInstance extends ActorInstance {
horizontalAngle = facing.toYRot() + ((facing.getAxis() == Direction.Axis.X) ? 180 : 0);
harvester.setBlockLight(localBlockLight());
}
harvester.setBlockLight(localBlockLight());
}
@Override
public void tick() {
super.tick();
@Override
public void tick() {
super.tick();
previousRotation = rotation;
previousRotation = rotation;
if (context.contraption.stalled || VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()))
return;
if (context.contraption.stalled || context.disabled
|| VecHelper.isVecPointingTowards(context.relativeMotion, facing.getOpposite()))
return;
double arcLength = context.motion.length();
double arcLength = context.motion.length();
double radians = arcLength * oneOverRadius;
double radians = arcLength * oneOverRadius;
float deg = AngleHelper.deg(radians);
float deg = AngleHelper.deg(radians);
deg = (float) (((int) (deg * 3000)) / 3000);
deg = (float) (((int) (deg * 3000)) / 3000);
rotation += deg * 1.25;
rotation += deg * 1.25;
rotation %= 360;
}
rotation %= 360;
}
@Override
public void beginFrame() {

View file

@ -39,8 +39,9 @@ public class HarvesterMovementBehaviour implements MovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(HarvesterBlock.FACING)
.getOpposite());
return MovementBehaviour.super.isActive(context)
&& !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(HarvesterBlock.FACING)
.getOpposite());
}
@Override

View file

@ -38,8 +38,9 @@ public class PloughMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(PloughBlock.FACING)
.getOpposite());
return super.isActive(context)
&& !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(PloughBlock.FACING)
.getOpposite());
}
@Override

View file

@ -30,8 +30,9 @@ public class SawMovementBehaviour extends BlockBreakingMovementBehaviour {
@Override
public boolean isActive(MovementContext context) {
return !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(SawBlock.FACING)
.getOpposite());
return super.isActive(context)
&& !VecHelper.isVecPointingTowards(context.relativeMotion, context.state.getValue(SawBlock.FACING)
.getOpposite());
}
@Override

View file

@ -40,6 +40,7 @@ import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
@ParametersAreNonnullByDefault
@ -127,7 +128,9 @@ public class SeatBlock extends Block implements ProperWaterloggedBlock {
@Override
public VoxelShape getCollisionShape(BlockState p_220071_1_, BlockGetter p_220071_2_, BlockPos p_220071_3_,
CollisionContext p_220071_4_) {
CollisionContext ctx) {
if (ctx instanceof EntityCollisionContext ecc && ecc.getEntity() instanceof Player)
return AllShapes.SEAT_COLLISION_PLAYERS;
return AllShapes.SEAT_COLLISION;
}

View file

@ -0,0 +1,65 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
import com.simibubi.create.foundation.block.ITE;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
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.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class ContraptionControlsBlock extends ControlsBlock implements ITE<ContraptionControlsTileEntity> {
public ContraptionControlsBlock(Properties pProperties) {
super(pProperties);
}
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
BlockHitResult pHit) {
return onTileEntityUse(pLevel, pPos, cte -> {
cte.pressButton();
cte.disabled = !cte.disabled;
cte.notifyUpdate();
if (!pLevel.isClientSide()) {
ContraptionControlsTileEntity.sendStatus(pPlayer, cte.filtering.getFilter(), !cte.disabled);
AllSoundEvents.CONTROLLER_CLICK.play(cte.getLevel(), null, cte.getBlockPos(), 1,
cte.disabled ? 0.8f : 1.5f);
}
return InteractionResult.SUCCESS;
});
}
@Override
public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos,
boolean pIsMoving) {
withTileEntityDo(pLevel, pPos, ContraptionControlsTileEntity::updatePoweredState);
}
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return AllShapes.CONTRAPTION_CONTROLS.get(pState.getValue(FACING));
}
@Override
public Class<ContraptionControlsTileEntity> getTileEntityClass() {
return ContraptionControlsTileEntity.class;
}
@Override
public BlockEntityType<? extends ContraptionControlsTileEntity> getTileEntityType() {
return AllTileEntities.CONTRAPTION_CONTROLS.get();
}
}

View file

@ -0,0 +1,239 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import java.util.Random;
import com.jozufozu.flywheel.core.virtual.VirtualRenderWorld;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionMatrices;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.AnimationTickHolder;
import com.simibubi.create.foundation.utility.Color;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.foundation.utility.IntAttached;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.items.ItemHandlerHelper;
public class ContraptionControlsMovement implements MovementBehaviour {
@Override
public ItemStack canBeDisabledVia(MovementContext context) {
return null;
}
@Override
public void startMoving(MovementContext context) {
if (context.contraption instanceof ElevatorContraption && context.tileData != null)
context.tileData.remove("Filter");
}
@Override
public void stopMoving(MovementContext context) {
ItemStack filter = getFilter(context);
if (filter != null)
context.tileData.putBoolean("Disabled", context.contraption.isActorTypeDisabled(filter)
|| context.contraption.isActorTypeDisabled(ItemStack.EMPTY));
}
public static boolean isSameFilter(ItemStack stack1, ItemStack stack2) {
if (stack1.isEmpty() && stack2.isEmpty())
return true;
return ItemHandlerHelper.canItemStacksStack(stack1, stack2);
}
private static Random r = new Random();
public static ItemStack getFilter(MovementContext ctx) {
CompoundTag tileData = ctx.tileData;
if (tileData == null)
return null;
return ItemStack.of(tileData.getCompound("Filter"));
}
public static boolean isDisabledInitially(MovementContext ctx) {
return ctx.tileData != null && ctx.tileData.getBoolean("Disabled");
}
@Override
public void tick(MovementContext ctx) {
if (!ctx.world.isClientSide())
return;
Contraption contraption = ctx.contraption;
if (!(contraption instanceof ElevatorContraption ec)) {
if (!(contraption.presentTileEntities.get(ctx.localPos)instanceof ContraptionControlsTileEntity cte))
return;
ItemStack filter = getFilter(ctx);
int value =
contraption.isActorTypeDisabled(filter) || contraption.isActorTypeDisabled(ItemStack.EMPTY) ? 4 * 45
: 0;
cte.indicator.setValue(value);
cte.indicator.updateChaseTarget(value);
cte.tickAnimations();
return;
}
if (!(ctx.temporaryData instanceof ElevatorFloorSelection))
ctx.temporaryData = new ElevatorFloorSelection();
ElevatorFloorSelection efs = (ElevatorFloorSelection) ctx.temporaryData;
tickFloorSelection(efs, ec);
if (!(contraption.presentTileEntities.get(ctx.localPos)instanceof ContraptionControlsTileEntity cte))
return;
cte.tickAnimations();
int currentY = (int) Math.round(contraption.entity.getY() + ec.getContactYOffset());
boolean atTargetY = ec.clientYTarget == currentY;
LerpedFloat indicator = cte.indicator;
float currentIndicator = indicator.getChaseTarget();
boolean below = atTargetY ? currentIndicator > 0 : ec.clientYTarget <= currentY;
if (currentIndicator == 0 && !atTargetY) {
int startingPoint = below ? 181 : -181;
indicator.setValue(startingPoint);
indicator.updateChaseTarget(startingPoint);
cte.tickAnimations();
return;
}
int currentStage = Mth.floor(((currentIndicator % 360) + 360) % 360);
if (!atTargetY || currentStage / 45 != 0) {
float increment = currentStage / 45 == (below ? 4 : 3) ? 2.25f : 33.75f;
indicator.chase(currentIndicator + (below ? increment : -increment), 45f, Chaser.LINEAR);
return;
}
indicator.setValue(0);
indicator.updateChaseTarget(0);
return;
}
public static void tickFloorSelection(ElevatorFloorSelection efs, ElevatorContraption ec) {
if (ec.namesList.isEmpty()) {
efs.currentShortName = "X";
efs.currentLongName = "No Floors";
efs.currentIndex = 0;
efs.targetYEqualsSelection = true;
return;
}
efs.currentIndex = Mth.clamp(efs.currentIndex, 0, ec.namesList.size() - 1);
IntAttached<Couple<String>> entry = ec.namesList.get(efs.currentIndex);
efs.currentTargetY = entry.getFirst();
efs.currentShortName = entry.getSecond()
.getFirst();
efs.currentLongName = entry.getSecond()
.getSecond();
efs.targetYEqualsSelection = efs.currentTargetY == ec.clientYTarget;
}
@Override
public boolean renderAsNormalTileEntity() {
return true;
}
@Override
@OnlyIn(Dist.CLIENT)
public void renderInContraption(MovementContext ctx, VirtualRenderWorld renderWorld, ContraptionMatrices matrices,
MultiBufferSource buffer) {
if (!(ctx.temporaryData instanceof ElevatorFloorSelection efs))
return;
if (!AllBlocks.CONTRAPTION_CONTROLS.has(ctx.state))
return;
Entity cameraEntity = Minecraft.getInstance()
.getCameraEntity();
float playerDistance = (float) (ctx.position == null || cameraEntity == null ? 0
: ctx.position.distanceToSqr(cameraEntity.getEyePosition()));
float flicker = r.nextFloat();
Couple<Integer> couple = DyeHelper.DYE_TABLE.get(efs.targetYEqualsSelection ? DyeColor.WHITE : DyeColor.ORANGE);
int brightColor = couple.getFirst();
int darkColor = couple.getSecond();
int flickeringBrightColor = Color.mixColors(brightColor, darkColor, flicker / 4);
Font fontRenderer = Minecraft.getInstance().font;
float shadowOffset = .5f;
String text = efs.currentShortName;
String description = efs.currentLongName;
PoseStack ms = matrices.getViewProjection();
TransformStack msr = TransformStack.cast(ms);
ms.pushPose();
msr.translate(ctx.localPos);
msr.rotateCentered(Direction.UP,
AngleHelper.rad(AngleHelper.horizontalAngle(ctx.state.getValue(ContraptionControlsBlock.FACING))));
ms.translate(0.275f + 0.125f, 1, 0.5f);
msr.rotate(Direction.WEST, AngleHelper.rad(67.5f));
float buttondepth = -.25f;
if (ctx.contraption.presentTileEntities.get(ctx.localPos)instanceof ContraptionControlsTileEntity cte)
buttondepth += -1 / 24f * cte.button.getValue(AnimationTickHolder.getPartialTicks(renderWorld));
if (!text.isBlank() && playerDistance < 100) {
int actualWidth = fontRenderer.width(text);
int width = Math.max(actualWidth, 12);
float scale = 1 / (5f * (width - .5f));
float heightCentering = (width - 8f) / 2;
ms.pushPose();
ms.translate(0, .15f, buttondepth);
ms.scale(scale, -scale, scale);
ms.translate(Math.max(0, width - actualWidth) / 2, heightCentering, 0);
NixieTubeRenderer.drawInWorldString(ms, buffer, text, flickeringBrightColor);
ms.translate(shadowOffset, shadowOffset, -1 / 16f);
NixieTubeRenderer.drawInWorldString(ms, buffer, text, Color.mixColors(darkColor, 0, .35f));
ms.popPose();
}
if (!description.isBlank() && playerDistance < 20) {
int actualWidth = fontRenderer.width(description);
int width = Math.max(actualWidth, 55);
float scale = 1 / (3f * (width - .5f));
float heightCentering = (width - 8f) / 2;
ms.pushPose();
ms.translate(-.0635f, 0.06f, buttondepth);
ms.scale(scale, -scale, scale);
ms.translate(Math.max(0, width - actualWidth) / 2, heightCentering, 0);
NixieTubeRenderer.drawInWorldString(ms, buffer, description, flickeringBrightColor);
ms.popPose();
}
ms.popPose();
}
public static class ElevatorFloorSelection {
public int currentIndex = 0;
public int currentTargetY = 0;
public boolean targetYEqualsSelection = true;
public String currentShortName = "";
public String currentLongName = "";
}
}

View file

@ -0,0 +1,127 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllMovementBehaviours;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement.ElevatorFloorSelection;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.MovingInteractionBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorTargetFloorPacket;
import com.simibubi.create.foundation.networking.AllPackets;
import net.minecraft.core.BlockPos;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.PacketDistributor;
public class ContraptionControlsMovingInteraction extends MovingInteractionBehaviour {
@Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) {
Contraption contraption = contraptionEntity.getContraption();
MutablePair<StructureBlockInfo, MovementContext> actor = contraption.getActorAt(localPos);
if (actor == null)
return false;
MovementContext ctx = actor.right;
if (ctx == null)
return false;
if (contraption instanceof ElevatorContraption ec)
return elevatorInteraction(localPos, contraptionEntity, ec, ctx);
if (contraptionEntity.level.isClientSide()) {
if (contraption.presentTileEntities.get(ctx.localPos)instanceof ContraptionControlsTileEntity cte)
cte.pressButton();
return true;
}
ItemStack filter = ContraptionControlsMovement.getFilter(ctx);
boolean disable = true;
boolean invert = false;
List<ItemStack> disabledActors = contraption.getDisabledActors();
for (Iterator<ItemStack> iterator = disabledActors.iterator(); iterator.hasNext();) {
ItemStack presentFilter = iterator.next();
boolean sameFilter = ContraptionControlsMovement.isSameFilter(presentFilter, filter);
if (presentFilter.isEmpty()) {
iterator.remove();
disable = false;
if (!sameFilter)
invert = true;
continue;
}
if (!sameFilter)
continue;
iterator.remove();
disable = false;
break;
}
if (invert) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state);
if (behaviour == null)
continue;
ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right);
if (behaviourStack == null)
continue;
if (ContraptionControlsMovement.isSameFilter(behaviourStack, filter))
continue;
if (contraption.isActorTypeDisabled(behaviourStack))
continue;
disabledActors.add(behaviourStack);
send(contraptionEntity, behaviourStack, true);
}
}
if (filter.isEmpty())
disabledActors.clear();
if (disable)
disabledActors.add(filter);
contraption.setActorsActive(filter, !disable);
ContraptionControlsTileEntity.sendStatus(player, filter, !disable);
send(contraptionEntity, filter, disable);
AllSoundEvents.CONTROLLER_CLICK.play(player.level, null,
new BlockPos(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 1)), 1, disable ? 0.8f : 1.5f);
return true;
}
private void send(AbstractContraptionEntity contraptionEntity, ItemStack filter, boolean disable) {
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> contraptionEntity),
new ContraptionDisableActorPacket(contraptionEntity.getId(), filter, !disable));
}
private boolean elevatorInteraction(BlockPos localPos, AbstractContraptionEntity contraptionEntity,
ElevatorContraption contraption, MovementContext ctx) {
if (!contraptionEntity.level.isClientSide()) {
BlockPos pos = new BlockPos(contraptionEntity.toGlobalVector(Vec3.atCenterOf(localPos), 1));
AllSoundEvents.CONTROLLER_CLICK.play(contraptionEntity.level, null, pos, 1, 1.5f);
AllSoundEvents.CONTRAPTION_ASSEMBLE.play(contraptionEntity.level, null, pos, 0.75f, 0.8f);
return true;
}
if (!(ctx.temporaryData instanceof ElevatorFloorSelection efs))
return false;
if (efs.currentTargetY == contraption.clientYTarget)
return false;
AllPackets.channel.sendToServer(new ElevatorTargetFloorPacket(contraptionEntity, efs.currentTargetY));
if (contraption.presentTileEntities.get(ctx.localPos)instanceof ContraptionControlsTileEntity cte)
cte.pressButton();
return true;
}
}

View file

@ -0,0 +1,52 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider.Context;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class ContraptionControlsRenderer extends SmartTileEntityRenderer<ContraptionControlsTileEntity> {
public ContraptionControlsRenderer(Context context) {
super(context);
}
@Override
protected void renderSafe(ContraptionControlsTileEntity tileEntityIn, float pt, PoseStack ms,
MultiBufferSource buffer, int light, int overlay) {
BlockState blockState = tileEntityIn.getBlockState();
Direction facing = blockState.getValue(ContraptionControlsBlock.FACING)
.getOpposite();
Vec3 buttonAxis = VecHelper.rotate(new Vec3(0, 1, -.325), AngleHelper.horizontalAngle(facing), Axis.Y)
.scale(-1 / 24f * tileEntityIn.button.getValue(pt));
ms.pushPose();
ms.translate(buttonAxis.x, buttonAxis.y, buttonAxis.z);
super.renderSafe(tileEntityIn, pt, ms, buffer, light, overlay);
VertexConsumer vc = buffer.getBuffer(RenderType.solid());
CachedBufferer.partialFacing(AllBlockPartials.CONTRAPTION_CONTROLS_BUTTON, blockState, facing)
.light(light)
.renderInto(ms, vc);
ms.popPose();
int i = (((int) tileEntityIn.indicator.getValue(pt) / 45) % 8) + 8;
CachedBufferer.partialFacing(AllBlockPartials.CONTRAPTION_CONTROLS_INDICATOR.get(i % 8), blockState, facing)
.light(light)
.renderInto(ms, vc);
}
}

View file

@ -0,0 +1,152 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import java.util.List;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.ControlsBlock;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.filtering.FilteringBehaviour;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.DyeHelper;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.VecHelper;
import com.simibubi.create.foundation.utility.animation.LerpedFloat;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;
public class ContraptionControlsTileEntity extends SmartTileEntity {
public FilteringBehaviour filtering;
public boolean disabled;
public boolean powered;
public LerpedFloat indicator;
public LerpedFloat button;
public ContraptionControlsTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
indicator = LerpedFloat.angular()
.startWithValue(0);
button = LerpedFloat.linear()
.startWithValue(0)
.chase(0, 0.125f, Chaser.EXP);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(filtering = new FilteringBehaviour(this, new ControlsSlot()).moveText(new Vec3(-30, 20, 10)));
}
public void pressButton() {
button.setValue(1);
}
public void updatePoweredState() {
if (level.isClientSide())
return;
boolean powered = level.hasNeighborSignal(worldPosition);
if (this.powered == powered)
return;
this.powered = powered;
this.disabled = powered;
notifyUpdate();
}
@Override
public void initialize() {
super.initialize();
updatePoweredState();
}
@Override
public void tick() {
super.tick();
if (!level.isClientSide())
return;
tickAnimations();
int value = disabled ? 4 * 45 : 0;
indicator.setValue(value);
indicator.updateChaseTarget(value);
}
public void tickAnimations() {
button.tickChaser();
indicator.tickChaser();
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
disabled = tag.getBoolean("Disabled");
powered = tag.getBoolean("Powered");
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
tag.putBoolean("Disabled", disabled);
tag.putBoolean("Powered", powered);
}
public static void sendStatus(Player player, ItemStack filter, boolean enabled) {
MutableComponent state = Lang.translate("contraption.controls.actor_toggle." + (enabled ? "on" : "off"))
.color(DyeHelper.DYE_TABLE.get(enabled ? DyeColor.LIME : DyeColor.ORANGE)
.getFirst())
.component();
if (filter.isEmpty()) {
Lang.translate("contraption.controls.all_actor_toggle", state)
.sendStatus(player);
return;
}
Lang.translate("contraption.controls.specific_actor_toggle", filter.getHoverName()
.getString(), state)
.sendStatus(player);
}
public static class ControlsSlot extends ValueBoxTransform.Sided {
@Override
protected Vec3 getLocalOffset(BlockState state) {
Direction facing = state.getValue(ControlsBlock.FACING);
float yRot = AngleHelper.horizontalAngle(facing);
return VecHelper.rotateCentered(VecHelper.voxelSpace(8, 10.875f, 5.1f), yRot, Axis.Y);
}
@Override
protected void rotate(BlockState state, PoseStack ms) {
Direction facing = state.getValue(ControlsBlock.FACING);
float yRot = AngleHelper.horizontalAngle(facing);
TransformStack.cast(ms)
.rotateY(yRot + 180)
.rotateX(67.5f);
}
@Override
protected float getScale() {
return .5f;
}
@Override
protected Vec3 getSouthLocation() {
return Vec3.ZERO;
}
}
}

View file

@ -0,0 +1,74 @@
package com.simibubi.create.content.contraptions.components.actors.controls;
import java.util.Iterator;
import java.util.List;
import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent.Context;
public class ContraptionDisableActorPacket extends SimplePacketBase {
private int entityID;
private ItemStack filter;
private boolean enable;
public ContraptionDisableActorPacket(int entityID, ItemStack filter, boolean enable) {
this.entityID = entityID;
this.filter = filter;
this.enable = enable;
}
public ContraptionDisableActorPacket(FriendlyByteBuf buffer) {
entityID = buffer.readInt();
enable = buffer.readBoolean();
filter = buffer.readItem();
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(entityID);
buffer.writeBoolean(enable);
buffer.writeItem(filter);
}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
Entity entityByID = Minecraft.getInstance().level.getEntity(entityID);
if (!(entityByID instanceof AbstractContraptionEntity ace))
return;
Contraption contraption = ace.getContraption();
List<ItemStack> disabledActors = contraption.getDisabledActors();
if (filter.isEmpty())
disabledActors.clear();
if (!enable) {
disabledActors.add(filter);
contraption.setActorsActive(filter, false);
return;
}
for (Iterator<ItemStack> iterator = disabledActors.iterator(); iterator.hasNext();) {
ItemStack next = iterator.next();
if (ContraptionControlsMovement.isSameFilter(next, filter) || next.isEmpty())
iterator.remove();
}
contraption.setActorsActive(filter, true);
});
context.get()
.setPacketHandled(true);
}
}

View file

@ -83,7 +83,9 @@ public class DeployerActorInstance extends ActorInstance {
@Override
public void beginFrame() {
double factor;
if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) {
if (context.disabled) {
factor = 0;
} else if (context.contraption.stalled || context.position == null || context.data.contains("StationaryTimer")) {
factor = Mth.sin(AnimationTickHolder.getRenderTime() * .5f) * .25f + .25f;
} else {
Vec3 center = VecHelper.getCenterOf(new BlockPos(context.position));

View file

@ -22,26 +22,12 @@ public class DeployerMovingInteraction extends MovingInteractionBehaviour {
@Override
public boolean handlePlayerInteraction(Player player, InteractionHand activeHand, BlockPos localPos,
AbstractContraptionEntity contraptionEntity) {
StructureBlockInfo info = contraptionEntity.getContraption()
.getBlocks()
.get(localPos);
if (info == null)
MutablePair<StructureBlockInfo, MovementContext> actor = contraptionEntity.getContraption()
.getActorAt(localPos);
if (actor == null || actor.right == null)
return false;
MovementContext ctx = null;
int index = -1;
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraptionEntity.getContraption()
.getActors()) {
if (info.equals(pair.left)) {
ctx = pair.right;
index = contraptionEntity.getContraption()
.getActors()
.indexOf(pair);
break;
}
}
if (ctx == null)
return false;
MovementContext ctx = actor.right;
ItemStack heldStack = player.getItemInHand(activeHand);
if (heldStack.getItem()
.equals(AllItems.WRENCH.get())) {
@ -73,8 +59,8 @@ public class DeployerMovingInteraction extends MovingInteractionBehaviour {
ctx.tileData.put("HeldItem", heldStack.serializeNBT());
ctx.data.put("HeldItem", heldStack.serializeNBT());
}
if (index >= 0)
setContraptionActorData(contraptionEntity, index, info, ctx);
// if (index >= 0)
// setContraptionActorData(contraptionEntity, index, info, ctx);
return true;
}
}

View file

@ -206,7 +206,8 @@ public class DeployerRenderer extends SafeTileEntityRenderer<DeployerTileEntity>
shaft.rotateCentered(Direction.get(AxisDirection.POSITIVE, Axis.Y), angle);
m.popPose();
m.translate(offset.x, offset.y, offset.z);
if (!context.disabled)
m.translate(offset.x, offset.y, offset.z);
pole.transform(m);
hand.transform(m);

View file

@ -448,7 +448,7 @@ public abstract class AbstractContraptionEntity extends Entity implements IEntit
context.rotation = v -> applyRotation(v, 1);
context.position = actorPosition;
if (!isActorActive(context, actor))
if (!isActorActive(context, actor) && !actor.mustTickWhileDisabled())
continue;
if (newPosVisited && !context.stall) {
actor.visitNewPosition(context, gridPosition);

View file

@ -21,8 +21,6 @@ import java.util.function.BiConsumer;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.DoorBlock;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
@ -36,6 +34,7 @@ import com.simibubi.create.content.contraptions.components.actors.BlockBreakingM
import com.simibubi.create.content.contraptions.components.actors.HarvesterMovementBehaviour;
import com.simibubi.create.content.contraptions.components.actors.SeatBlock;
import com.simibubi.create.content.contraptions.components.actors.SeatEntity;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.components.steam.PoweredShaftTileEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.MechanicalBearingBlock;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption;
@ -89,12 +88,14 @@ import net.minecraft.network.protocol.game.DebugPackets;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.village.poi.PoiType;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.ButtonBlock;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.DoorBlock;
import net.minecraft.world.level.block.PressurePlateBlock;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.SimpleWaterloggedBlock;
@ -138,6 +139,8 @@ public abstract class Contraption {
protected Map<BlockPos, StructureBlockInfo> blocks;
protected List<MutablePair<StructureBlockInfo, MovementContext>> actors;
protected Map<BlockPos, MovingInteractionBehaviour> interactors;
protected List<ItemStack> disabledActors;
protected List<AABB> superglue;
protected List<BlockPos> seats;
protected Map<UUID, Integer> seatMapping;
@ -163,6 +166,7 @@ public abstract class Contraption {
blocks = new HashMap<>();
seats = new ArrayList<>();
actors = new ArrayList<>();
disabledActors = new ArrayList<>();
modelData = new HashMap<>();
interactors = new HashMap<>();
superglue = new ArrayList<>();
@ -604,7 +608,7 @@ public abstract class Contraption {
blockstate = blockstate.setValue(RedstoneContactBlock.POWERED, true);
if (AllBlocks.POWERED_SHAFT.has(blockstate))
blockstate = BlockHelper.copyProperties(blockstate, AllBlocks.SHAFT.getDefaultState());
if (AllBlocks.CONTROLS.has(blockstate))
if (blockstate.getBlock() instanceof ControlsBlock)
blockstate = blockstate.setValue(ControlsBlock.OPEN, true);
if (blockstate.hasProperty(SlidingDoorBlock.VISIBLE))
blockstate = blockstate.setValue(SlidingDoorBlock.VISIBLE, false);
@ -701,6 +705,10 @@ public abstract class Contraption {
getActors().add(MutablePair.of(info, context));
});
disabledActors = NBTHelper.readItemList(nbt.getList("DisabledActors", Tag.TAG_COMPOUND));
for (ItemStack stack : disabledActors)
setActorsActive(stack, false);
superglue.clear();
NBTHelper.iterateCompoundList(nbt.getList("Superglue", Tag.TAG_COMPOUND),
c -> superglue.add(SuperGlueEntity.readBoundingBox(c)));
@ -753,6 +761,8 @@ public abstract class Contraption {
actorsNBT.add(compound);
}
ListTag disabledActorsNBT = NBTHelper.writeItemList(disabledActors);
ListTag superglueNBT = new ListTag();
if (!spawnPacket) {
for (AABB glueEntry : superglue) {
@ -789,6 +799,7 @@ public abstract class Contraption {
nbt.put("Blocks", blocksNBT);
nbt.put("Actors", actorsNBT);
nbt.put("DisabledActors", disabledActorsNBT);
nbt.put("Interactors", interactorNBT);
nbt.put("Superglue", superglueNBT);
nbt.put("Anchor", NbtUtils.writeBlockPos(anchor));
@ -1005,7 +1016,7 @@ public abstract class Contraption {
if (disassembled)
return;
disassembled = true;
for (boolean nonBrittles : Iterate.trueAndFalse) {
for (StructureBlockInfo block : blocks.values()) {
if (nonBrittles == BlockMovementChecks.isBrittle(block.state))
@ -1052,7 +1063,8 @@ public abstract class Contraption {
boolean verticalRotation = transform.rotationAxis == null || transform.rotationAxis.isHorizontal();
verticalRotation = verticalRotation && transform.rotation != Rotation.NONE;
if (verticalRotation) {
if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock || state.getBlock() instanceof DoorBlock)
if (state.getBlock() instanceof RopeBlock || state.getBlock() instanceof MagnetBlock
|| state.getBlock() instanceof DoorBlock)
world.destroyBlock(targetPos, true);
}
@ -1119,12 +1131,55 @@ public abstract class Contraption {
}
public void startMoving(Level world) {
disabledActors.clear();
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementContext context = new MovementContext(world, pair.left, this);
AllMovementBehaviours.getBehaviour(pair.left.state)
.startMoving(context);
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state);
behaviour.startMoving(context);
pair.setRight(context);
if (behaviour instanceof ContraptionControlsMovement)
disableActorOnStart(context);
}
for (ItemStack stack : disabledActors)
setActorsActive(stack, false);
}
protected void disableActorOnStart(MovementContext context) {
if (!ContraptionControlsMovement.isDisabledInitially(context))
return;
ItemStack filter = ContraptionControlsMovement.getFilter(context);
if (filter == null)
return;
if (isActorTypeDisabled(filter))
return;
disabledActors.add(filter);
}
public boolean isActorTypeDisabled(ItemStack filter) {
return disabledActors.stream()
.anyMatch(i -> ContraptionControlsMovement.isSameFilter(i, filter));
}
public void setActorsActive(ItemStack referenceStack, boolean enable) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors) {
MovementBehaviour behaviour = AllMovementBehaviours.getBehaviour(pair.left.state);
if (behaviour == null)
continue;
ItemStack behaviourStack = behaviour.canBeDisabledVia(pair.right);
if (behaviourStack == null)
continue;
if (!referenceStack.isEmpty() && !ContraptionControlsMovement.isSameFilter(referenceStack, behaviourStack))
continue;
pair.right.disabled = !enable;
if (!enable)
behaviour.onDisabledByControls(pair.right);
}
}
public List<ItemStack> getDisabledActors() {
return disabledActors;
}
public void stop(Level world) {
@ -1213,6 +1268,14 @@ public abstract class Contraption {
return actors;
}
@Nullable
public MutablePair<StructureBlockInfo, MovementContext> getActorAt(BlockPos localPos) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors)
if (localPos.equals(pair.left.pos))
return pair;
return null;
}
public Map<BlockPos, MovingInteractionBehaviour> getInteractors() {
return interactors;
}

View file

@ -2,12 +2,14 @@ package com.simibubi.create.content.contraptions.components.structureMovement;
import static net.minecraft.world.entity.Entity.collideBoundingBox;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.mutable.MutableBoolean;
import org.apache.commons.lang3.mutable.MutableFloat;
import org.apache.commons.lang3.mutable.MutableObject;
import org.apache.commons.lang3.tuple.MutablePair;
import com.google.common.base.Predicates;
import com.simibubi.create.AllBlocks;
@ -27,6 +29,7 @@ import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -48,6 +51,7 @@ import net.minecraft.world.level.block.CocoaBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
@ -60,6 +64,8 @@ public class ContraptionCollider {
NONE, CLIENT, REMOTE, SERVER
}
private static MutablePair<WeakReference<AbstractContraptionEntity>, Double> safetyLock = new MutablePair<>();
static void collideEntities(AbstractContraptionEntity contraptionEntity) {
Level world = contraptionEntity.getCommandSenderWorld();
Contraption contraption = contraptionEntity.getContraption();
@ -75,6 +81,10 @@ public class ContraptionCollider {
Vec3 anchorVec = contraptionEntity.getAnchorVec();
ContraptionRotationState rotation = null;
if (world.isClientSide() && safetyLock.left != null && safetyLock.left.get() == contraptionEntity)
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
() -> () -> saveClientPlayerFromClipping(contraptionEntity, contraptionMotion));
// After death, multiple refs to the client player may show up in the area
boolean skipClientPlayer = false;
@ -97,11 +107,12 @@ public class ContraptionCollider {
if (playerType == PlayerType.SERVER)
continue;
if (playerType == PlayerType.CLIENT)
if (playerType == PlayerType.CLIENT) {
if (skipClientPlayer)
continue;
else
skipClientPlayer = true;
}
// Init matrix
if (rotation == null)
@ -115,13 +126,15 @@ public class ContraptionCollider {
float yawOffset = rotation.getYawOffset();
Vec3 position = getWorldToLocalTranslation(entity, anchorVec, rotationMatrix, yawOffset);
motion = motion.subtract(contraptionMotion);
motion = rotationMatrix.transform(motion);
// Prepare entity bounds
AABB localBB = entityBounds.move(position)
.inflate(1.0E-7D);
OrientedBB obb = new OrientedBB(localBB);
obb.setRotation(rotationMatrix);
motion = motion.subtract(contraptionMotion);
motion = rotationMatrix.transform(motion);
// Use simplified bbs when present
final Vec3 motionCopy = motion;
@ -363,10 +376,67 @@ public class ContraptionCollider {
if (limbSwing > 1.0F)
limbSwing = 1.0F;
AllPackets.channel.sendToServer(new ClientMotionPacket(entityMotion, true, limbSwing));
if (entity.isOnGround() && contraption instanceof TranslatingContraption) {
safetyLock.setLeft(new WeakReference<>(contraptionEntity));
safetyLock.setRight(entity.getY() - contraptionEntity.getY());
}
}
}
@OnlyIn(Dist.CLIENT)
private static void saveClientPlayerFromClipping(AbstractContraptionEntity contraptionEntity,
Vec3 contraptionMotion) {
Player entity = Minecraft.getInstance().player;
if (entity.isPassenger())
return;
double prevDiff = safetyLock.right;
double currentDiff = entity.getY() - contraptionEntity.getY();
double motion = contraptionMotion.subtract(entity.getDeltaMovement()).y;
double trend = Math.signum(currentDiff - prevDiff);
if (trend == 0)
return;
if (trend == Math.signum(motion))
return;
double speed = contraptionMotion.multiply(0, 1, 0)
.lengthSqr();
if (trend > 0 && speed < 0.1)
return;
if (speed < 0.05)
return;
AABB bb = entity.getBoundingBox().deflate(1/4f, 0, 1/4f);
double shortestDistance = Double.MAX_VALUE;
double yStart = entity.getStepHeight() + contraptionEntity.getY() + prevDiff;
double rayLength = Math.max(5, Math.abs(entity.getY() - yStart));
for (int rayIndex = 0; rayIndex < 4; rayIndex++) {
Vec3 start = new Vec3(rayIndex / 2 == 0 ? bb.minX : bb.maxX, yStart, rayIndex % 2 == 0 ? bb.minZ : bb.maxZ);
Vec3 end = start.add(0, -rayLength, 0);
BlockHitResult hitResult = ContraptionHandlerClient.rayTraceContraption(start, end, contraptionEntity);
if (hitResult == null)
continue;
Vec3 hit = contraptionEntity.toGlobalVector(hitResult.getLocation(), 1);
double hitDiff = start.y - hit.y;
if (shortestDistance > hitDiff)
shortestDistance = hitDiff;
}
if (shortestDistance > rayLength) {
safetyLock.setLeft(null);
return;
}
entity.setPos(entity.getX(), yStart - shortestDistance, entity.getZ());
}
private static Vec3 handleDamageFromTrain(Level world, AbstractContraptionEntity contraptionEntity,
Vec3 contraptionMotion, Entity entity, Vec3 entityMotion, PlayerType playerType) {
@ -374,13 +444,13 @@ public class ContraptionCollider {
return entityMotion;
if (!entity.isOnGround())
return entityMotion;
CompoundTag persistentData = entity.getPersistentData();
if (persistentData.contains("ContraptionGrounded")) {
persistentData.remove("ContraptionGrounded");
return entityMotion;
}
if (cce.collidingEntities.containsKey(entity))
return entityMotion;
if (entity instanceof ItemEntity)
@ -612,7 +682,7 @@ public class ContraptionCollider {
.intersects(otherBounds.move(otherMotion)))
continue;
for (BlockPos colliderPos : contraption.getColliders(world, movementDirection)) {
for (BlockPos colliderPos : contraption.getOrCreateColliders(world, movementDirection)) {
colliderPos = colliderPos.offset(gridPos)
.subtract(new BlockPos(otherPosition));
if (!otherContraption.getBlocks()
@ -627,7 +697,7 @@ public class ContraptionCollider {
public static boolean isCollidingWithWorld(Level world, TranslatingContraption contraption, BlockPos anchor,
Direction movementDirection) {
for (BlockPos pos : contraption.getColliders(world, movementDirection)) {
for (BlockPos pos : contraption.getOrCreateColliders(world, movementDirection)) {
BlockPos colliderPos = pos.offset(anchor);
if (!world.isLoaded(colliderPos))

View file

@ -8,6 +8,7 @@ import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.BearingContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.ClockworkContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.bearing.StabilizedContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.mounted.MountedContraption;
import com.simibubi.create.content.contraptions.components.structureMovement.piston.PistonContraption;
@ -25,7 +26,8 @@ public class ContraptionType {
MOUNTED = register("mounted", MountedContraption::new),
STABILIZED = register("stabilized", StabilizedContraption::new),
GANTRY = register("gantry", GantryContraption::new),
CARRIAGE = register("carriage", CarriageContraption::new);
CARRIAGE = register("carriage", CarriageContraption::new),
ELEVATOR = register("elevator", ElevatorContraption::new);
Supplier<? extends Contraption> factory;
String id;

View file

@ -14,6 +14,7 @@ import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
@ -48,6 +49,15 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity {
entity.setContraption(contraption);
return entity;
}
@Override
public void setPos(double x, double y, double z) {
super.setPos(x, y, z);
if (!level.isClientSide())
return;
for (Entity entity : getPassengers())
positionRider(entity);
}
@Override
public Vec3 getContactPointMotion(Vec3 globalContactPoint) {
@ -62,7 +72,6 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity {
if (contraption instanceof BearingContraption)
rotationAxis = ((BearingContraption) contraption).getFacing()
.getAxis();
}
@Override
@ -113,6 +122,11 @@ public class ControlledContraptionEntity extends AbstractContraptionEntity {
public void setAngle(float angle) {
this.angle = angle;
if (!level.isClientSide())
return;
for (Entity entity : getPassengers())
positionRider(entity);
}
public float getAngle(float partialTicks) {

View file

@ -12,6 +12,7 @@ import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.core.BlockPos;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -20,7 +21,7 @@ import net.minecraftforge.items.ItemHandlerHelper;
public interface MovementBehaviour {
default boolean isActive(MovementContext context) {
return true;
return !context.disabled;
}
default void tick(MovementContext context) {}
@ -33,6 +34,22 @@ public interface MovementBehaviour {
return Vec3.ZERO;
}
@Nullable
default ItemStack canBeDisabledVia(MovementContext context) {
Block block = context.state.getBlock();
if (block == null)
return null;
return new ItemStack(block);
}
default void onDisabledByControls(MovementContext context) {
cancelStall(context);
}
default boolean mustTickWhileDisabled() {
return false;
}
default void dropItem(MovementContext context, ItemStack stack) {
ItemStack remainder;
if (AllConfigs.SERVER.kinetics.moveItemsToStorage.get())

View file

@ -25,6 +25,7 @@ public class MovementContext {
public CompoundTag tileData;
public boolean stall;
public boolean disabled;
public boolean firstMovement;
public CompoundTag data;
public Contraption contraption;
@ -37,6 +38,7 @@ public class MovementContext {
this.contraption = contraption;
localPos = info.pos;
disabled = false;
firstMovement = true;
motion = Vec3.ZERO;
relativeMotion = Vec3.ZERO;
@ -49,6 +51,8 @@ public class MovementContext {
public float getAnimationSpeed() {
int modifier = 1000;
double length = -motion.length();
if (disabled)
return 0;
if (world.isClientSide && contraption.stalled)
return 700;
if (Math.abs(length) < 1 / 512f)

View file

@ -14,29 +14,32 @@ public abstract class TranslatingContraption extends Contraption {
protected Set<BlockPos> cachedColliders;
protected Direction cachedColliderDirection;
public Set<BlockPos> getColliders(Level world, Direction movementDirection) {
public Set<BlockPos> getOrCreateColliders(Level world, Direction movementDirection) {
if (getBlocks() == null)
return Collections.emptySet();
if (cachedColliders == null || cachedColliderDirection != movementDirection) {
cachedColliders = new HashSet<>();
cachedColliderDirection = movementDirection;
for (StructureBlockInfo info : getBlocks().values()) {
BlockPos offsetPos = info.pos.relative(movementDirection);
if (info.state.getCollisionShape(world, offsetPos)
.isEmpty())
continue;
if (getBlocks().containsKey(offsetPos)
&& !getBlocks().get(offsetPos).state.getCollisionShape(world, offsetPos)
.isEmpty())
continue;
cachedColliders.add(info.pos);
}
cachedColliders= createColliders(world, movementDirection);
}
return cachedColliders;
}
public Set<BlockPos> createColliders(Level world, Direction movementDirection) {
Set<BlockPos> colliders = new HashSet<>();
for (StructureBlockInfo info : getBlocks().values()) {
BlockPos offsetPos = info.pos.relative(movementDirection);
if (info.state.getCollisionShape(world, offsetPos)
.isEmpty())
continue;
if (getBlocks().containsKey(offsetPos)
&& !getBlocks().get(offsetPos).state.getCollisionShape(world, offsetPos)
.isEmpty())
continue;
colliders.add(info.pos);
}
return colliders;
}
@Override
public void removeBlocksFromWorld(Level world, BlockPos offset) {
int count = blocks.size();

View file

@ -23,12 +23,18 @@ import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class StabilizedBearingMovementBehaviour implements MovementBehaviour {
@Override
public ItemStack canBeDisabledVia(MovementContext context) {
return null;
}
@Override
@OnlyIn(Dist.CLIENT)
public void renderInContraption(MovementContext context, VirtualRenderWorld renderWorld,

View file

@ -0,0 +1,226 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.utility.BlockHelper;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.IntAttached;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.WorldAttached;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.entity.BlockEntity;
public class ElevatorColumn {
public static WorldAttached<Map<ColumnCoords, ElevatorColumn>> LOADED_COLUMNS =
new WorldAttached<>($ -> new HashMap<>());
protected LevelAccessor level;
protected ColumnCoords coords;
protected List<Integer> contacts;
protected int targetedYLevel;
protected boolean isActive;
@Nullable
public static ElevatorColumn get(LevelAccessor level, ColumnCoords coords) {
return LOADED_COLUMNS.get(level)
.get(coords);
}
public static ElevatorColumn getOrCreate(LevelAccessor level, ColumnCoords coords) {
return LOADED_COLUMNS.get(level)
.computeIfAbsent(coords, c -> new ElevatorColumn(level, c));
}
public ElevatorColumn(LevelAccessor level, ColumnCoords coords) {
this.level = level;
this.coords = coords;
contacts = new ArrayList<>();
}
public void markDirty() {
for (BlockPos pos : getContacts()) {
BlockEntity blockEntity = level.getBlockEntity(pos);
if (blockEntity instanceof ElevatorContactTileEntity ecte)
ecte.setChanged();
}
}
public void floorReached(LevelAccessor level, String name) {
getContacts().stream()
.forEach(p -> {
if (level.getBlockEntity(p)instanceof ElevatorContactTileEntity ecte)
ecte.updateDisplayedFloor(name);
});
}
public int namesListVersion;
public List<IntAttached<Couple<String>>> compileNamesList() {
return getContacts().stream()
.map(p -> {
if (level.getBlockEntity(p)instanceof ElevatorContactTileEntity ecte)
return IntAttached.with(p.getY(), ecte.getNames());
return null;
})
.filter(Objects::nonNull)
.toList();
}
public void namesChanged() {
namesListVersion++;
}
public Collection<BlockPos> getContacts() {
return contacts.stream()
.map(this::contactAt)
.toList();
}
public void gatherAll() {
BlockPos.betweenClosedStream(contactAt(level.getMinBuildHeight()), contactAt(level.getMaxBuildHeight()))
.filter(p -> coords.equals(ElevatorContactBlock.getColumnCoords(level, p)))
.forEach(p -> level.setBlock(p,
BlockHelper.copyProperties(level.getBlockState(p), AllBlocks.ELEVATOR_CONTACT.getDefaultState()), 3));
}
public BlockPos contactAt(int y) {
return new BlockPos(coords.x, y, coords.z);
}
public void setActive(boolean isActive) {
this.isActive = isActive;
markDirty();
checkEmpty();
}
public boolean isActive() {
return isActive;
}
public void target(int yLevel) {
targetedYLevel = yLevel;
}
public int getTargetedYLevel() {
return targetedYLevel;
}
public void initNames(Level level) {
Integer prevLevel = null;
for (int i = 0; i < contacts.size(); i++) {
Integer y = contacts.get(i);
BlockPos pos = contactAt(y);
if (!(level.getBlockEntity(pos)instanceof ElevatorContactTileEntity ecte))
continue;
Integer currentLevel = null;
if (!ecte.shortName.isBlank()) {
Integer tryValueOf = tryValueOf(ecte.shortName);
if (tryValueOf != null)
currentLevel = tryValueOf;
if (currentLevel == null)
continue;
}
if (prevLevel != null)
currentLevel = prevLevel + 1;
Integer nextLevel = null;
for (int peekI = i + 1; peekI < contacts.size(); peekI++) {
BlockPos peekPos = contactAt(contacts.get(peekI));
if (!(level.getBlockEntity(peekPos)instanceof ElevatorContactTileEntity peekEcte))
continue;
Integer tryValueOf = tryValueOf(peekEcte.shortName);
if (tryValueOf == null)
continue;
if (currentLevel != null && currentLevel >= tryValueOf) {
peekEcte.shortName = "";
break;
}
nextLevel = tryValueOf;
break;
}
if (currentLevel == null)
currentLevel = nextLevel != null ? nextLevel - 1 : 0;
ecte.updateName(String.valueOf(currentLevel), ecte.longName);
prevLevel = currentLevel;
}
}
private static Integer tryValueOf(String floorName) {
try {
return Integer.valueOf(floorName, 10);
} catch (NumberFormatException nfe) {
return null;
}
}
public void add(BlockPos contactPos) {
int coord = contactPos.getY();
if (contacts.contains(coord))
return;
int index = 0;
for (; index < contacts.size(); index++)
if (contacts.get(index) > coord)
break;
contacts.add(index, coord);
namesChanged();
}
public void remove(BlockPos contactPos) {
contacts.remove((Object) contactPos.getY());
checkEmpty();
namesChanged();
}
private void checkEmpty() {
if (contacts.isEmpty() && !isActive())
LOADED_COLUMNS.get(level)
.remove(coords);
}
public static record ColumnCoords(int x, int z, Direction side) {
public ColumnCoords relative(BlockPos anchor) {
return new ColumnCoords(x + anchor.getX(), z + anchor.getZ(), side);
}
public CompoundTag write() {
CompoundTag tag = new CompoundTag();
tag.putInt("X", x);
tag.putInt("Z", z);
NBTHelper.writeEnum(tag, "Side", side);
return tag;
}
public static ColumnCoords read(CompoundTag tag) {
int x = tag.getInt("X");
int z = tag.getInt("Z");
Direction side = NBTHelper.readEnum(tag, "Side", Direction.class);
return new ColumnCoords(x, z, side);
}
}
}

View file

@ -0,0 +1,217 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.Optional;
import java.util.Random;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.content.logistics.block.diodes.BrassDiodeBlock;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
import com.simibubi.create.content.schematics.ISpecialBlockItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.foundation.block.ITE;
import com.simibubi.create.foundation.block.WrenchableDirectionalBlock;
import com.simibubi.create.foundation.gui.ScreenOpener;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
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.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.fml.DistExecutor;
public class ElevatorContactBlock extends WrenchableDirectionalBlock
implements ITE<ElevatorContactTileEntity>, ISpecialBlockItemRequirement {
public static final BooleanProperty POWERED = BlockStateProperties.POWERED;
public static final BooleanProperty CALLING = BooleanProperty.create("calling");
public static final BooleanProperty POWERING = BrassDiodeBlock.POWERING;
public ElevatorContactBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(defaultBlockState().setValue(CALLING, false)
.setValue(POWERING, false)
.setValue(POWERED, false)
.setValue(FACING, Direction.SOUTH));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> builder) {
super.createBlockStateDefinition(builder.add(CALLING, POWERING, POWERED));
}
@Nullable
public static ColumnCoords getColumnCoords(LevelAccessor level, BlockPos pos) {
BlockState blockState = level.getBlockState(pos);
if (!AllBlocks.ELEVATOR_CONTACT.has(blockState) && !AllBlocks.REDSTONE_CONTACT.has(blockState))
return null;
Direction facing = blockState.getValue(FACING);
BlockPos target = pos;
return new ColumnCoords(target.getX(), target.getZ(), facing);
}
@Override
public void neighborChanged(BlockState pState, Level pLevel, BlockPos pPos, Block pBlock, BlockPos pFromPos,
boolean pIsMoving) {
if (pLevel.isClientSide)
return;
boolean isPowered = pState.getValue(POWERED);
if (isPowered == pLevel.hasNeighborSignal(pPos))
return;
pLevel.setBlock(pPos, pState.cycle(POWERED), 2);
if (isPowered)
return;
if (pState.getValue(CALLING))
return;
pLevel.setBlock(pPos, pState.cycle(CALLING), 2);
ElevatorColumn elevatorColumn = ElevatorColumn.getOrCreate(pLevel, getColumnCoords(pLevel, pPos));
for (BlockPos otherPos : elevatorColumn.getContacts()) {
if (otherPos.equals(pPos))
continue;
BlockState otherState = pLevel.getBlockState(otherPos);
if (!AllBlocks.ELEVATOR_CONTACT.has(otherState))
continue;
pLevel.setBlock(otherPos, otherState.setValue(CALLING, false), 2);
scheduleActivation(pLevel, otherPos);
}
pLevel.setBlock(pPos, pState.setValue(POWERED, true)
.setValue(CALLING, true), 2);
pLevel.updateNeighborsAt(pPos, this);
elevatorColumn.target(pPos.getY());
elevatorColumn.markDirty();
}
public void scheduleActivation(LevelAccessor pLevel, BlockPos pPos) {
if (!pLevel.getBlockTicks()
.hasScheduledTick(pPos, this))
pLevel.scheduleTick(pPos, this, 1);
}
@Override
public void tick(BlockState pState, ServerLevel pLevel, BlockPos pPos, Random pRand) {
boolean wasPowering = pState.getValue(POWERING);
Optional<ElevatorContactTileEntity> optionalTE = getTileEntityOptional(pLevel, pPos);
boolean shouldBePowering = optionalTE.map(te -> {
boolean activateBlock = te.activateBlock;
te.activateBlock = false;
te.setChanged();
return activateBlock;
})
.orElse(false);
shouldBePowering |= RedstoneContactBlock.hasValidContact(pLevel, pPos, pState.getValue(FACING));
if (wasPowering || shouldBePowering)
pLevel.setBlock(pPos, pState.setValue(POWERING, shouldBePowering), 2);
pLevel.updateNeighborsAt(pPos, this);
}
@Override
public BlockState updateShape(BlockState stateIn, Direction facing, BlockState facingState, LevelAccessor worldIn,
BlockPos currentPos, BlockPos facingPos) {
if (facing != stateIn.getValue(FACING))
return stateIn;
boolean hasValidContact = RedstoneContactBlock.hasValidContact(worldIn, currentPos, facing);
if (stateIn.getValue(POWERING) != hasValidContact)
scheduleActivation(worldIn, currentPos);
return stateIn;
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader level, BlockPos pos, Direction side) {
return false;
}
@Override
public boolean isSignalSource(BlockState state) {
return state.getValue(POWERING);
}
@Override
public ItemStack getCloneItemStack(BlockGetter pLevel, BlockPos pPos, BlockState pState) {
return AllBlocks.REDSTONE_CONTACT.asStack();
}
@Override
public boolean canConnectRedstone(BlockState state, BlockGetter world, BlockPos pos, @Nullable Direction side) {
if (side == null)
return true;
return state.getValue(FACING) != side.getOpposite();
}
@Override
public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) {
return state.getValue(POWERING) ? 15 : 0;
}
@Override
public Class<ElevatorContactTileEntity> getTileEntityClass() {
return ElevatorContactTileEntity.class;
}
@Override
public BlockEntityType<? extends ElevatorContactTileEntity> getTileEntityType() {
return AllTileEntities.ELEVATOR_CONTACT.get();
}
@Override
public void fillItemCategory(CreativeModeTab pTab, NonNullList<ItemStack> pItems) {}
@Override
public ItemRequirement getRequiredItems(BlockState state, BlockEntity te) {
return ItemRequirement.of(AllBlocks.REDSTONE_CONTACT.getDefaultState(), te);
}
@Override
public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn,
BlockHitResult hit) {
if (player != null && AllItems.WRENCH.isIn(player.getItemInHand(handIn)))
return InteractionResult.PASS;
DistExecutor.unsafeRunWhenOn(Dist.CLIENT,
() -> () -> withTileEntityDo(worldIn, pos, te -> this.displayScreen(te, player)));
return InteractionResult.SUCCESS;
}
@OnlyIn(value = Dist.CLIENT)
protected void displayScreen(ElevatorContactTileEntity te, Player player) {
if (player instanceof LocalPlayer)
ScreenOpener.open(new ElevatorContactScreen(te.getBlockPos(), te.shortName, te.longName));
}
public static int getLight(BlockState state) {
return state.getValue(POWERING) ? 10 : state.getValue(CALLING) ? 5 : 0;
}
}

View file

@ -0,0 +1,40 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import com.simibubi.create.foundation.networking.TileEntityConfigurationPacket;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
public class ElevatorContactEditPacket extends TileEntityConfigurationPacket<ElevatorContactTileEntity> {
private String shortName;
private String longName;
public ElevatorContactEditPacket(BlockPos pos, String shortName, String longName) {
super(pos);
this.shortName = shortName;
this.longName = longName;
}
public ElevatorContactEditPacket(FriendlyByteBuf buffer) {
super(buffer);
}
@Override
protected void writeSettings(FriendlyByteBuf buffer) {
buffer.writeUtf(shortName, 4);
buffer.writeUtf(longName, 30);
}
@Override
protected void readSettings(FriendlyByteBuf buffer) {
shortName = buffer.readUtf(4);
longName = buffer.readUtf(30);
}
@Override
protected void applySettings(ElevatorContactTileEntity te) {
te.updateName(shortName, longName);
}
}

View file

@ -0,0 +1,171 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import org.lwjgl.glfw.GLFW;
import com.google.common.collect.ImmutableList;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.gui.AbstractSimiScreen;
import com.simibubi.create.foundation.gui.AllGuiTextures;
import com.simibubi.create.foundation.gui.AllIcons;
import com.simibubi.create.foundation.gui.element.GuiGameElement;
import com.simibubi.create.foundation.gui.widget.IconButton;
import com.simibubi.create.foundation.gui.widget.TooltipArea;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Components;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.components.EditBox;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.util.FormattedCharSequence;
public class ElevatorContactScreen extends AbstractSimiScreen {
private AllGuiTextures background;
private EditBox shortNameInput;
private EditBox longNameInput;
private IconButton confirm;
private String shortName;
private String longName;
private BlockPos pos;
public ElevatorContactScreen(BlockPos pos, String prevShortName, String prevLongName) {
super(Lang.translateDirect("elevator_contact.title"));
this.pos = pos;
background = AllGuiTextures.ELEVATOR_CONTACT;
this.shortName = prevShortName;
this.longName = prevLongName;
}
@Override
public void init() {
setWindowSize(background.width + 30, background.height);
super.init();
int x = guiLeft;
int y = guiTop;
confirm = new IconButton(x + 200, y + 58, AllIcons.I_CONFIRM);
confirm.withCallback(this::confirm);
addRenderableWidget(confirm);
shortNameInput = editBox(33, 30, 4);
shortNameInput.setValue(shortName);
centerInput(x);
shortNameInput.setResponder(s -> {
shortName = s;
centerInput(x);
});
shortNameInput.changeFocus(true);
setFocused(shortNameInput);
shortNameInput.setHighlightPos(0);
longNameInput = editBox(63, 140, 30);
longNameInput.setValue(longName);
longNameInput.setResponder(s -> longName = s);
MutableComponent rmbToEdit = Lang.translate("gui.schedule.lmb_edit")
.style(ChatFormatting.DARK_GRAY)
.style(ChatFormatting.ITALIC)
.component();
addRenderableOnly(new TooltipArea(x + 21, y + 23, 30, 18)
.withTooltip(ImmutableList.of(Lang.translate("elevator_contact.floor_identifier")
.color(0x5391E1)
.component(), rmbToEdit)));
addRenderableOnly(new TooltipArea(x + 57, y + 23, 147, 18).withTooltip(ImmutableList.of(
Lang.translate("elevator_contact.floor_description")
.color(0x5391E1)
.component(),
Lang.translate("crafting_blueprint.optional")
.style(ChatFormatting.GRAY)
.component(),
rmbToEdit)));
}
private int centerInput(int x) {
return shortNameInput.x = x + (shortName.isEmpty() ? 34 : 36 - font.width(shortName) / 2);
}
private EditBox editBox(int x, int width, int chars) {
EditBox editBox = new EditBox(font, guiLeft + x, guiTop + 30, width, 10, Components.immutableEmpty());
editBox.setTextColor(-1);
editBox.setTextColorUneditable(-1);
editBox.setBordered(false);
editBox.setMaxLength(chars);
editBox.changeFocus(false);
editBox.mouseClicked(0, 0, 0);
addRenderableWidget(editBox);
return editBox;
}
@Override
protected void renderWindow(PoseStack ms, int mouseX, int mouseY, float partialTicks) {
int x = guiLeft;
int y = guiTop;
background.render(ms, x, y, this);
FormattedCharSequence formattedcharsequence = title.getVisualOrderText();
font.draw(ms, formattedcharsequence,
(float) (x + (background.width - 8) / 2 - font.width(formattedcharsequence) / 2), (float) y + 6, 0x2F3738);
GuiGameElement.of(AllBlocks.ELEVATOR_CONTACT.asStack()).<GuiGameElement
.GuiRenderBuilder>at(x + background.width + 6, y + background.height - 56, -200)
.scale(5)
.render(ms);
}
@Override
public boolean mouseClicked(double pMouseX, double pMouseY, int pButton) {
boolean consumed = super.mouseClicked(pMouseX, pMouseY, pButton);
if (!shortNameInput.isFocused()) {
int length = shortNameInput.getValue()
.length();
shortNameInput.setHighlightPos(length);
shortNameInput.setCursorPosition(length);
}
if (shortNameInput.isHoveredOrFocused())
longNameInput.mouseClicked(0, 0, 0);
if (!consumed && pMouseX > guiLeft + 22 && pMouseY > guiTop + 24 && pMouseX < guiLeft + 50
&& pMouseY < guiTop + 40) {
setFocused(shortNameInput);
shortNameInput.changeFocus(true);
return true;
}
return consumed;
}
@Override
public boolean keyPressed(int keyCode, int p_keyPressed_2_, int p_keyPressed_3_) {
if (super.keyPressed(keyCode, p_keyPressed_2_, p_keyPressed_3_))
return true;
if (keyCode == GLFW.GLFW_KEY_ENTER) {
confirm();
return true;
}
if (keyCode == 256 && this.shouldCloseOnEsc()) {
this.onClose();
return true;
}
return false;
}
private void confirm() {
AllPackets.channel.sendToServer(new ElevatorContactEditPacket(pos, shortName, longName));
onClose();
}
}

View file

@ -0,0 +1,154 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.List;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.content.logistics.block.display.DisplayLinkBlock;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class ElevatorContactTileEntity extends SmartTileEntity {
public ColumnCoords columnCoords;
public boolean activateBlock;
public String shortName;
public String longName;
public String lastReportedCurrentFloor;
private int yTargetFromNBT = Integer.MIN_VALUE;
private boolean deferNameGenerator;
public ElevatorContactTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
shortName = "";
longName = "";
deferNameGenerator = false;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
tag.putString("ShortName", shortName);
tag.putString("LongName", longName);
if (lastReportedCurrentFloor != null)
tag.putString("LastReportedCurrentFloor", lastReportedCurrentFloor);
if (clientPacket)
return;
tag.putBoolean("Activate", activateBlock);
if (columnCoords == null)
return;
ElevatorColumn column = ElevatorColumn.get(level, columnCoords);
if (column == null)
return;
tag.putInt("ColumnTarget", column.getTargetedYLevel());
if (column.isActive())
NBTHelper.putMarker(tag, "ColumnActive");
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
shortName = tag.getString("ShortName");
longName = tag.getString("LongName");
if (tag.contains("LastReportedCurrentFloor"))
lastReportedCurrentFloor = tag.getString("LastReportedCurrentFloor");
if (clientPacket)
return;
activateBlock = tag.getBoolean("Activate");
if (!tag.contains("ColumnTarget"))
return;
int target = tag.getInt("ColumnTarget");
boolean active = tag.contains("ColumnActive");
if (columnCoords == null) {
yTargetFromNBT = target;
return;
}
ElevatorColumn column = ElevatorColumn.getOrCreate(level, columnCoords);
column.target(target);
column.setActive(active);
}
public void updateDisplayedFloor(String floor) {
if (floor.equals(lastReportedCurrentFloor))
return;
lastReportedCurrentFloor = floor;
DisplayLinkBlock.notifyGatherers(level, worldPosition);
}
@Override
public void initialize() {
super.initialize();
if (level.isClientSide())
return;
columnCoords = ElevatorContactBlock.getColumnCoords(level, worldPosition);
if (columnCoords == null)
return;
ElevatorColumn column = ElevatorColumn.getOrCreate(level, columnCoords);
column.add(worldPosition);
if (shortName.isBlank())
deferNameGenerator = true;
if (yTargetFromNBT == Integer.MIN_VALUE)
return;
column.target(yTargetFromNBT);
yTargetFromNBT = Integer.MIN_VALUE;
}
@Override
public void tick() {
super.tick();
if (!deferNameGenerator)
return;
if (columnCoords != null)
ElevatorColumn.getOrCreate(level, columnCoords)
.initNames(level);
deferNameGenerator = false;
}
@Override
public void setRemoved() {
if (columnCoords != null) {
ElevatorColumn column = ElevatorColumn.get(level, columnCoords);
if (column != null)
column.remove(worldPosition);
}
super.setRemoved();
}
public void updateName(String shortName, String longName) {
this.shortName = shortName;
this.longName = longName;
this.deferNameGenerator = false;
notifyUpdate();
ElevatorColumn column = ElevatorColumn.get(level, columnCoords);
if (column != null)
column.namesChanged();
}
public Couple<String> getNames() {
return Couple.create(shortName, longName);
}
}

View file

@ -0,0 +1,180 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.List;
import org.apache.commons.lang3.tuple.MutablePair;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement.ElevatorFloorSelection;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyContraption;
import com.simibubi.create.content.logistics.block.redstone.RedstoneContactBlock;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.IntAttached;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraftforge.network.PacketDistributor;
public class ElevatorContraption extends PulleyContraption {
protected ColumnCoords column;
protected int contactYOffset;
public boolean arrived;
private int namesListVersion = -1;
public List<IntAttached<Couple<String>>> namesList = ImmutableList.of();
public int clientYTarget;
// during assembly only
private int contacts;
public ElevatorContraption() {
super();
}
public ElevatorContraption(int initialOffset) {
super(initialOffset);
}
@Override
public void tickStorage(AbstractContraptionEntity entity) {
super.tickStorage(entity);
if (entity.tickCount % 10 != 0)
return;
ColumnCoords coords = getGlobalColumn();
ElevatorColumn column = ElevatorColumn.get(entity.level, coords);
if (column == null)
return;
if (column.namesListVersion == namesListVersion)
return;
namesList = column.compileNamesList();
namesListVersion = column.namesListVersion;
AllPackets.channel.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity),
new ElevatorFloorListPacket(entity, namesList));
}
@Override
protected void disableActorOnStart(MovementContext context) {}
public ColumnCoords getGlobalColumn() {
return column.relative(anchor);
}
public Integer getCurrentTargetY(Level level) {
ColumnCoords coords = getGlobalColumn();
ElevatorColumn column = ElevatorColumn.get(level, coords);
if (column == null)
return null;
return column.targetedYLevel;
}
@Override
public boolean assemble(Level world, BlockPos pos) throws AssemblyException {
if (!searchMovedStructure(world, pos, null))
return false;
if (blocks.size() <= 0)
return false;
if (contacts == 0)
throw new AssemblyException(Lang.translateDirect("elevator_assembly.no_contacts"));
if (contacts > 1)
throw new AssemblyException(Lang.translateDirect("train_assembly.too_many_contacts"));
startMoving(world);
return true;
}
@Override
protected Pair<StructureBlockInfo, BlockEntity> capture(Level world, BlockPos pos) {
BlockState blockState = world.getBlockState(pos);
if (!AllBlocks.REDSTONE_CONTACT.has(blockState))
return super.capture(world, pos);
Direction facing = blockState.getValue(RedstoneContactBlock.FACING);
if (facing.getAxis() == Axis.Y)
return super.capture(world, pos);
contacts++;
BlockPos local = toLocalPos(pos.relative(facing));
column = new ColumnCoords(local.getX(), local.getZ(), facing.getOpposite());
contactYOffset = local.getY();
return super.capture(world, pos);
}
public int getContactYOffset() {
return contactYOffset;
}
public void broadcastFloorData(Level level, BlockPos contactPos) {
ElevatorColumn column = ElevatorColumn.get(level, getGlobalColumn());
if (!(world.getBlockEntity(contactPos)instanceof ElevatorContactTileEntity ecte))
return;
if (column != null)
column.floorReached(level, ecte.shortName);
}
@Override
public CompoundTag writeNBT(boolean spawnPacket) {
CompoundTag tag = super.writeNBT(spawnPacket);
tag.putBoolean("Arrived", arrived);
tag.put("Column", column.write());
tag.putInt("ContactY", contactYOffset);
return tag;
}
@Override
public void readNBT(Level world, CompoundTag nbt, boolean spawnData) {
arrived = nbt.getBoolean("Arrived");
column = ColumnCoords.read(nbt.getCompound("Column"));
contactYOffset = nbt.getInt("ContactY");
super.readNBT(world, nbt, spawnData);
}
@Override
protected ContraptionType getType() {
return ContraptionType.ELEVATOR;
}
public void setClientYTarget(int clientYTarget) {
if (this.clientYTarget == clientYTarget)
return;
this.clientYTarget = clientYTarget;
syncControlDisplays();
}
public void syncControlDisplays() {
if (namesList.isEmpty())
return;
for (int i = 0; i < namesList.size(); i++)
if (namesList.get(i)
.getFirst() == clientYTarget)
setAllControlsToFloor(i);
}
public void setAllControlsToFloor(int floorIndex) {
for (MutablePair<StructureBlockInfo, MovementContext> pair : actors)
if (pair.right != null && pair.right.temporaryData instanceof ElevatorFloorSelection efs)
efs.currentIndex = floorIndex;
}
}

View file

@ -0,0 +1,117 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.lang.ref.WeakReference;
import java.util.Collection;
import org.apache.commons.lang3.tuple.MutablePair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsMovement.ElevatorFloorSelection;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsTileEntity;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionControlsTileEntity.ControlsSlot;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandler;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionHandlerClient;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.foundation.utility.Couple;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public class ElevatorControlsHandler {
private static ControlsSlot slot = new ContraptionControlsTileEntity.ControlsSlot();
@OnlyIn(Dist.CLIENT)
public static boolean onScroll(double delta) {
Minecraft mc = Minecraft.getInstance();
LocalPlayer player = mc.player;
if (player == null)
return false;
if (player.isSpectator())
return false;
if (mc.level == null)
return false;
Couple<Vec3> rayInputs = ContraptionHandlerClient.getRayInputs(player);
Vec3 origin = rayInputs.getFirst();
Vec3 target = rayInputs.getSecond();
AABB aabb = new AABB(origin, target).inflate(16);
Collection<WeakReference<AbstractContraptionEntity>> contraptions =
ContraptionHandler.loadedContraptions.get(mc.level)
.values();
for (WeakReference<AbstractContraptionEntity> ref : contraptions) {
AbstractContraptionEntity contraptionEntity = ref.get();
if (contraptionEntity == null)
continue;
Contraption contraption = contraptionEntity.getContraption();
if (!(contraption instanceof ElevatorContraption ec))
continue;
if (!contraptionEntity.getBoundingBox()
.intersects(aabb))
continue;
BlockHitResult rayTraceResult =
ContraptionHandlerClient.rayTraceContraption(origin, target, contraptionEntity);
if (rayTraceResult == null)
continue;
BlockPos pos = rayTraceResult.getBlockPos();
StructureBlockInfo info = contraption.getBlocks()
.get(pos);
if (info == null)
continue;
if (!AllBlocks.CONTRAPTION_CONTROLS.has(info.state))
continue;
if (!slot.testHit(info.state, rayTraceResult.getLocation()
.subtract(Vec3.atLowerCornerOf(pos))))
continue;
MovementContext ctx = null;
for (MutablePair<StructureBlockInfo, MovementContext> pair : contraption.getActors()) {
if (info.equals(pair.left)) {
ctx = pair.right;
break;
}
}
if (!(ctx.temporaryData instanceof ElevatorFloorSelection))
ctx.temporaryData = new ElevatorFloorSelection();
ElevatorFloorSelection efs = (ElevatorFloorSelection) ctx.temporaryData;
int prev = efs.currentIndex;
efs.currentIndex += delta;
ContraptionControlsMovement.tickFloorSelection(efs, ec);
if (prev != efs.currentIndex && !ec.namesList.isEmpty()) {
float pitch = (efs.currentIndex) / (float) (ec.namesList.size());
pitch = Mth.lerp(pitch, 1f, 1.5f);
AllSoundEvents.SCROLL_VALUE.play(mc.player.level, mc.player,
new BlockPos(contraptionEntity.toGlobalVector(rayTraceResult.getLocation(), 1)), 1, pitch);
}
return true;
}
return false;
}
}

View file

@ -0,0 +1,103 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.IntAttached;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraftforge.network.NetworkEvent.Context;
import net.minecraftforge.network.PacketDistributor;
public class ElevatorFloorListPacket extends SimplePacketBase {
private int entityId;
private List<IntAttached<Couple<String>>> floorsList;
public ElevatorFloorListPacket(AbstractContraptionEntity entity, List<IntAttached<Couple<String>>> floorsList) {
this.entityId = entity.getId();
this.floorsList = floorsList;
}
public ElevatorFloorListPacket(FriendlyByteBuf buffer) {
entityId = buffer.readInt();
int size = buffer.readInt();
floorsList = new ArrayList<>();
for (int i = 0; i < size; i++)
floorsList.add(IntAttached.with(buffer.readInt(), Couple.create(buffer.readUtf(), buffer.readUtf())));
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(entityId);
buffer.writeInt(floorsList.size());
for (IntAttached<Couple<String>> entry : floorsList) {
buffer.writeInt(entry.getFirst());
entry.getSecond()
.forEach(buffer::writeUtf);
}
}
@Override
public void handle(Supplier<Context> context) {
context.get()
.enqueueWork(() -> {
Entity entityByID = Minecraft.getInstance().level.getEntity(entityId);
if (!(entityByID instanceof AbstractContraptionEntity ace))
return;
if (!(ace.getContraption()instanceof ElevatorContraption ec))
return;
ec.namesList = floorsList;
ec.syncControlDisplays();
});
context.get()
.setPacketHandled(true);
}
public static class RequestFloorList extends SimplePacketBase {
private int entityId;
public RequestFloorList(AbstractContraptionEntity entity) {
this.entityId = entity.getId();
}
public RequestFloorList(FriendlyByteBuf buffer) {
entityId = buffer.readInt();
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(entityId);
}
@Override
public void handle(Supplier<Context> context) {
Context ctx = context.get();
ctx.enqueueWork(() -> {
ServerPlayer sender = ctx.getSender();
Entity entityByID = sender.getLevel()
.getEntity(entityId);
if (!(entityByID instanceof AbstractContraptionEntity ace))
return;
if (!(ace.getContraption()instanceof ElevatorContraption ec))
return;
AllPackets.channel.send(PacketDistributor.PLAYER.with(() -> sender),
new ElevatorFloorListPacket(ace, ec.namesList));
});
ctx.setPacketHandled(true);
}
}
}

View file

@ -0,0 +1,74 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.HorizontalKineticBlock;
import com.simibubi.create.foundation.block.ITE;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class ElevatorPulleyBlock extends HorizontalKineticBlock implements ITE<ElevatorPulleyTileEntity> {
public ElevatorPulleyBlock(Properties properties) {
super(properties);
}
@Override
public InteractionResult use(BlockState state, Level worldIn, BlockPos pos, Player player, InteractionHand handIn,
BlockHitResult hit) {
if (!player.mayBuild())
return InteractionResult.FAIL;
if (player.isShiftKeyDown())
return InteractionResult.FAIL;
if (!player.getItemInHand(handIn)
.isEmpty())
return InteractionResult.PASS;
if (worldIn.isClientSide)
return InteractionResult.SUCCESS;
return onTileEntityUse(worldIn, pos, te -> {
te.clicked();
return InteractionResult.SUCCESS;
});
}
@Override
public BlockEntityType<? extends ElevatorPulleyTileEntity> getTileEntityType() {
return AllTileEntities.ELEVATOR_PULLEY.get();
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.getValue(HORIZONTAL_FACING)
.getClockWise()
.getAxis();
}
@Override
public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) {
return AllShapes.ELEVATOR_PULLEY.get(state.getValue(HORIZONTAL_FACING));
}
@Override
public boolean hasShaftTowards(LevelReader world, BlockPos pos, BlockState state, Direction face) {
return getRotationAxis(state) == face.getAxis();
}
@Override
public Class<ElevatorPulleyTileEntity> getTileEntityClass() {
return ElevatorPulleyTileEntity.class;
}
}

View file

@ -0,0 +1,25 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import com.jozufozu.flywheel.api.MaterialManager;
import com.jozufozu.flywheel.api.instance.DynamicInstance;
import com.jozufozu.flywheel.light.TickingLightListener;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.ShaftInstance;
// TODO
public class ElevatorPulleyInstance extends ShaftInstance implements DynamicInstance, TickingLightListener {
public ElevatorPulleyInstance(MaterialManager dispatcher, KineticTileEntity tile) {
super(dispatcher, tile);
}
@Override
public boolean tickLightListener() {
return false;
}
@Override
public void beginFrame() {
}
}

View file

@ -0,0 +1,123 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.AllSpriteShifts;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.base.KineticTileEntityRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.AbstractPulleyRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyRenderer;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.foundation.block.render.SpriteShiftEntry;
import com.simibubi.create.foundation.render.CachedBufferer;
import com.simibubi.create.foundation.render.SuperByteBuffer;
import com.simibubi.create.foundation.utility.AngleHelper;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
public class ElevatorPulleyRenderer extends KineticTileEntityRenderer {
public ElevatorPulleyRenderer(BlockEntityRendererProvider.Context context) {
super(context);
}
@Override
protected void renderSafe(KineticTileEntity te, float partialTicks, PoseStack ms, MultiBufferSource buffer,
int light, int overlay) {
// if (Backend.canUseInstancing(te.getLevel()))
// return;
// from KTE. replace with super call when flw instance is implemented
BlockState state = getRenderedBlockState(te);
RenderType type = getRenderType(te, state);
if (type != null)
renderRotatingBuffer(te, getRotatedModel(te, state), ms, buffer.getBuffer(type), light);
//
float offset = PulleyRenderer.getTileOffset(partialTicks, (PulleyTileEntity) te);
boolean running = PulleyRenderer.isPulleyRunning(te);
SpriteShiftEntry beltShift = AllSpriteShifts.ELEVATOR_BELT;
SpriteShiftEntry coilShift = AllSpriteShifts.ELEVATOR_COIL;
VertexConsumer vb = buffer.getBuffer(RenderType.solid());
Level world = te.getLevel();
BlockState blockState = te.getBlockState();
BlockPos pos = te.getBlockPos();
SuperByteBuffer magnet = CachedBufferer.partial(AllBlockPartials.ELEVATOR_MAGNET, blockState);
if (running || offset == 0)
AbstractPulleyRenderer.renderAt(world, magnet, offset, pos, ms, vb);
SuperByteBuffer rotatedCoil = getRotatedCoil(te);
if (offset == 0) {
rotatedCoil.light(light)
.renderInto(ms, vb);
return;
}
float spriteSize = beltShift.getTarget()
.getV1()
- beltShift.getTarget()
.getV0();
double coilScroll = -(offset + 3 / 16f) - Math.floor((offset + 3 / 16f) * -2) / 2;
double beltScroll = (-(offset + .5) - Math.floor(-(offset + .5))) / 2;
rotatedCoil.shiftUVScrolling(coilShift, (float) coilScroll * spriteSize)
.light(light)
.renderInto(ms, vb);
SuperByteBuffer halfRope = CachedBufferer.partial(AllBlockPartials.ELEVATOR_BELT_HALF, blockState);
SuperByteBuffer rope = CachedBufferer.partial(AllBlockPartials.ELEVATOR_BELT, blockState);
float f = offset % 1;
if (f < .25f || f > .75f) {
halfRope.centre()
.rotateY(180 + AngleHelper.horizontalAngle(blockState.getValue(ElevatorPulleyBlock.HORIZONTAL_FACING)))
.unCentre();
AbstractPulleyRenderer.renderAt(world,
halfRope.shiftUVScrolling(beltShift, (float) beltScroll * spriteSize), f > .75f ? f - 1 : f, pos, ms,
vb);
}
if (!running)
return;
for (int i = 0; i < offset - .25f; i++) {
rope.centre()
.rotateY(180 + AngleHelper.horizontalAngle(blockState.getValue(ElevatorPulleyBlock.HORIZONTAL_FACING)))
.unCentre();
AbstractPulleyRenderer.renderAt(world, rope.shiftUVScrolling(beltShift, (float) beltScroll * spriteSize),
offset - i, pos, ms, vb);
}
}
@Override
protected BlockState getRenderedBlockState(KineticTileEntity te) {
return shaft(getRotationAxisOf(te));
}
protected SuperByteBuffer getRotatedCoil(KineticTileEntity te) {
BlockState blockState = te.getBlockState();
return CachedBufferer.partialFacing(AllBlockPartials.ELEVATOR_COIL, blockState,
blockState.getValue(ElevatorPulleyBlock.HORIZONTAL_FACING));
}
@Override
public int getViewDistance() {
return 128;
}
@Override
public boolean shouldRenderOffScreen(KineticTileEntity p_188185_1_) {
return true;
}
}

View file

@ -0,0 +1,316 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.List;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSoundEvents;
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
import com.simibubi.create.content.contraptions.components.structureMovement.ControlledContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.foundation.advancement.AllAdvancements;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
public class ElevatorPulleyTileEntity extends PulleyTileEntity {
private float prevSpeed;
private boolean arrived;
private int clientOffsetTarget;
private boolean initialOffsetReceived;
public ElevatorPulleyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
prevSpeed = 0;
arrived = true;
initialOffsetReceived = false;
}
private int getTargetOffset() {
if (level.isClientSide)
return clientOffsetTarget;
if (movedContraption == null || !(movedContraption.getContraption()instanceof ElevatorContraption ec))
return (int) offset;
Integer target = ec.getCurrentTargetY(level);
if (target == null)
return (int) offset;
return worldPosition.getY() - target + ec.contactYOffset - 1;
}
@Override
public void attach(ControlledContraptionEntity contraption) {
super.attach(contraption);
if (offset >= 0)
resetContraptionToOffset();
if (level.isClientSide) {
AllPackets.channel.sendToServer(new ElevatorFloorListPacket.RequestFloorList(contraption));
return;
}
if (contraption.getContraption()instanceof ElevatorContraption ec)
ElevatorColumn.getOrCreate(level, ec.getGlobalColumn())
.setActive(true);
}
@Override
public void tick() {
boolean wasArrived = arrived;
super.tick();
if (movedContraption == null)
return;
if (!(movedContraption.getContraption()instanceof ElevatorContraption ec))
return;
if (level.isClientSide())
ec.setClientYTarget(worldPosition.getY() - clientOffsetTarget + ec.contactYOffset - 1);
ec.arrived = wasArrived;
if (!arrived)
return;
double y = movedContraption.getY();
int targetLevel = Mth.floor(0.5f + y);
if (!wasArrived && !level.isClientSide()) {
triggerContact(ec, targetLevel);
AllSoundEvents.CONTRAPTION_DISASSEMBLE.play(level, null, worldPosition.below((int) offset), 0.75f, 0.8f);
}
double diff = targetLevel - y;
if (Math.abs(diff) > 1f / 128)
diff *= 0.25f;
movedContraption.setPos(movedContraption.position()
.add(0, diff, 0));
}
@Override
public void lazyTick() {
super.lazyTick();
if (level.isClientSide() || !arrived)
return;
if (movedContraption == null || !movedContraption.isAlive())
return;
if (!(movedContraption.getContraption()instanceof ElevatorContraption ec))
return;
if (getTargetOffset() != (int) offset)
return;
double y = movedContraption.getY();
int targetLevel = Mth.floor(0.5f + y);
triggerContact(ec, targetLevel);
}
private void triggerContact(ElevatorContraption ec, int targetLevel) {
ColumnCoords coords = ec.getGlobalColumn();
ElevatorColumn column = ElevatorColumn.get(level, coords);
if (column == null)
return;
BlockPos contactPos = column.contactAt(targetLevel + ec.contactYOffset);
if (!level.isLoaded(contactPos))
return;
BlockState contactState = level.getBlockState(contactPos);
if (!AllBlocks.ELEVATOR_CONTACT.has(contactState))
return;
if (contactState.getValue(ElevatorContactBlock.POWERING))
return;
ElevatorContactBlock ecb = AllBlocks.ELEVATOR_CONTACT.get();
ecb.withTileEntityDo(level, contactPos, te -> te.activateBlock = true);
ecb.scheduleActivation(level, contactPos);
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
super.write(compound, clientPacket);
if (clientPacket)
compound.putInt("ClientTarget", clientOffsetTarget);
}
@Override
protected void read(CompoundTag compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (!clientPacket)
return;
clientOffsetTarget = compound.getInt("ClientTarget");
if (initialOffsetReceived)
return;
offset = compound.getFloat("Offset");
initialOffsetReceived = true;
resetContraptionToOffset();
}
@Override
public float getMovementSpeed() {
int currentTarget = getTargetOffset();
if (!level.isClientSide() && currentTarget != clientOffsetTarget) {
clientOffsetTarget = currentTarget;
sendData();
}
float diff = currentTarget - offset;
float movementSpeed = Mth.clamp(convertToLinear(getSpeed() * 2), -1.99f, 1.99f);
float rpmLimit = Math.abs(movementSpeed);
float configacc = Mth.lerp(Math.abs(movementSpeed), 0.0075f, 0.0175f);
float decelleration = (float) Math.sqrt(2 * Math.abs(diff) * configacc);
float speed = diff;
speed = Mth.clamp(speed, -rpmLimit, rpmLimit);
speed = Mth.clamp(speed, prevSpeed - configacc, prevSpeed + configacc);
speed = Mth.clamp(speed, -decelleration, decelleration);
arrived = Math.abs(diff) < 0.5f;
if (speed > 1 / 1024f && !level.isClientSide())
setChanged();
return prevSpeed = speed;
}
@Override
protected boolean shouldCreateRopes() {
return false;
}
@Override
public void disassemble() {
if (movedContraption != null && movedContraption.getContraption()instanceof ElevatorContraption ec) {
ElevatorColumn column = ElevatorColumn.get(level, ec.getGlobalColumn());
if (column != null)
column.setActive(false);
}
super.disassemble();
offset = -1;
sendData();
}
public void clicked() {
if (isPassive() && level.getBlockEntity(mirrorParent)instanceof ElevatorPulleyTileEntity parent) {
parent.clicked();
return;
}
if (running)
disassemble();
else
assembleNextTick = true;
}
@Override
protected boolean moveAndCollideContraption() {
if (arrived)
return false;
super.moveAndCollideContraption();
return false;
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
registerAwardables(behaviours, AllAdvancements.CONTRAPTION_ACTORS);
}
@Override
protected void assemble() throws AssemblyException {
if (!(level.getBlockState(worldPosition)
.getBlock() instanceof ElevatorPulleyBlock))
return;
if (getSpeed() == 0)
return;
int maxLength = AllConfigs.SERVER.kinetics.maxRopeLength.get();
int i = 1;
while (i <= maxLength) {
BlockPos ropePos = worldPosition.below(i);
BlockState ropeState = level.getBlockState(ropePos);
if (!ropeState.getCollisionShape(level, ropePos)
.isEmpty()
&& !ropeState.getMaterial()
.isReplaceable()) {
break;
}
++i;
}
offset = i - 1;
forceMove = true;
// Collect Construct
if (!level.isClientSide && mirrorParent == null) {
needsContraption = false;
BlockPos anchor = worldPosition.below(Mth.floor(offset + 1));
offset = Mth.floor(offset);
ElevatorContraption contraption = new ElevatorContraption((int) offset);
float offsetOnSucess = offset;
offset = 0;
boolean canAssembleStructure = contraption.assemble(level, anchor);
if (!canAssembleStructure && getSpeed() > 0)
return;
if (!contraption.getBlocks()
.isEmpty()) {
offset = offsetOnSucess;
contraption.removeBlocksFromWorld(level, BlockPos.ZERO);
movedContraption = ControlledContraptionEntity.create(level, this, contraption);
movedContraption.setPos(anchor.getX(), anchor.getY(), anchor.getZ());
level.addFreshEntity(movedContraption);
forceMove = true;
needsContraption = true;
if (contraption.containsBlockBreakers())
award(AllAdvancements.CONTRAPTION_ACTORS);
for (BlockPos pos : contraption.createColliders(level, Direction.UP)) {
if (pos.getY() != 0)
continue;
pos = pos.offset(anchor);
if (level.getBlockEntity(new BlockPos(pos.getX(), worldPosition.getY(),
pos.getZ()))instanceof ElevatorPulleyTileEntity pte)
pte.startMirroringOther(worldPosition);
}
ElevatorColumn column = ElevatorColumn.getOrCreate(level, contraption.getGlobalColumn());
int target = (int) (worldPosition.getY() + contraption.contactYOffset - 1 - offset);
column.target(target);
column.gatherAll();
column.setActive(true);
column.markDirty();
contraption.broadcastFloorData(level, column.contactAt(target));
clientOffsetTarget = column.getTargetedYLevel();
arrived = true;
}
}
clientOffsetDiff = 0;
running = true;
sendData();
}
@Override
public void onSpeedChanged(float previousSpeed) {
setChanged();
}
@Override
protected MovementMode getMovementMode() {
return MovementMode.MOVE_NEVER_PLACE;
}
}

View file

@ -0,0 +1,73 @@
package com.simibubi.create.content.contraptions.components.structureMovement.elevator;
import java.util.function.Supplier;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.foundation.networking.SimplePacketBase;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraftforge.network.NetworkEvent.Context;
public class ElevatorTargetFloorPacket extends SimplePacketBase {
private int entityId;
private int targetY;
public ElevatorTargetFloorPacket(AbstractContraptionEntity entity, int targetY) {
this.targetY = targetY;
this.entityId = entity.getId();
}
public ElevatorTargetFloorPacket(FriendlyByteBuf buffer) {
entityId = buffer.readInt();
targetY = buffer.readInt();
}
@Override
public void write(FriendlyByteBuf buffer) {
buffer.writeInt(entityId);
buffer.writeInt(targetY);
}
@Override
public void handle(Supplier<Context> context) {
Context ctx = context.get();
ctx.enqueueWork(() -> {
ServerPlayer sender = ctx.getSender();
Entity entityByID = sender.getLevel()
.getEntity(entityId);
if (!(entityByID instanceof AbstractContraptionEntity ace))
return;
if (!(ace.getContraption()instanceof ElevatorContraption ec))
return;
if (ace.distanceToSqr(sender) > 50 * 50)
return;
Level level = sender.level;
ElevatorColumn elevatorColumn = ElevatorColumn.get(level, ec.getGlobalColumn());
if (!elevatorColumn.contacts.contains(targetY))
return;
for (BlockPos otherPos : elevatorColumn.getContacts()) {
BlockState otherState = level.getBlockState(otherPos);
if (!AllBlocks.ELEVATOR_CONTACT.has(otherState))
continue;
level.setBlock(otherPos, otherState.setValue(ElevatorContactBlock.CALLING, otherPos.getY() == targetY),
2);
AllBlocks.ELEVATOR_CONTACT.get()
.scheduleActivation(level, otherPos);
}
elevatorColumn.target(targetY);
elevatorColumn.markDirty();
});
ctx.setPacketHandled(true);
}
}

View file

@ -61,14 +61,17 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity
public void tick() {
super.tick();
if (movedContraption != null) {
if (movedContraption != null)
if (!movedContraption.isAlive())
movedContraption = null;
}
if (isPassive())
return;
if (level.isClientSide)
clientOffsetDiff *= .75f;
waitingForSpeedChange = false;//TODO
if (waitingForSpeedChange) {
if (movedContraption != null) {
if (level.isClientSide) {
@ -144,6 +147,10 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity
}
}
protected boolean isPassive() {
return false;
}
@Override
public void lazyTick() {
super.lazyTick();
@ -164,6 +171,10 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity
@Override
public void onSpeedChanged(float prevSpeed) {
super.onSpeedChanged(prevSpeed);
if (isPassive())
return;
assembleNextTick = true;
waitingForSpeedChange = false;
@ -249,18 +260,22 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity
disassemble();
return;
}
if (movementMode.get() == MovementMode.MOVE_NEVER_PLACE) {
if (getMovementMode() == MovementMode.MOVE_NEVER_PLACE) {
waitingForSpeedChange = true;
return;
}
int initial = getInitialOffset();
if ((int) (offset + .5f) != initial && movementMode.get() == MovementMode.MOVE_PLACE_RETURNED) {
if ((int) (offset + .5f) != initial && getMovementMode() == MovementMode.MOVE_PLACE_RETURNED) {
waitingForSpeedChange = true;
return;
}
disassemble();
}
protected MovementMode getMovementMode() {
return movementMode.get();
}
protected boolean moveAndCollideContraption() {
if (movedContraption == null)
return false;
@ -288,6 +303,8 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity
protected void resetContraptionToOffset() {
if (movedContraption == null)
return;
if (!movedContraption.isAlive())
return;
Vec3 vec = toPosition(offset);
movedContraption.setPos(vec.x, vec.y, vec.z);
if (getSpeed() == 0 || waitingForSpeedChange)

View file

@ -80,8 +80,8 @@ public abstract class AbstractPulleyRenderer extends KineticTileEntityRenderer {
renderAt(world, rope, offset - i - 1, pos, ms, vb);
}
private void renderAt(LevelAccessor world, SuperByteBuffer partial, float offset, BlockPos pulleyPos, PoseStack ms,
VertexConsumer buffer) {
public static void renderAt(LevelAccessor world, SuperByteBuffer partial, float offset, BlockPos pulleyPos,
PoseStack ms, VertexConsumer buffer) {
BlockPos actualPos = pulleyPos.below((int) offset);
int light = LevelRenderer.getLightColor(world, world.getBlockState(actualPos), actualPos);
partial.translate(0, -offset, 0)

View file

@ -14,7 +14,7 @@ import net.minecraftforge.api.distmarker.OnlyIn;
public class PulleyContraption extends TranslatingContraption {
int initialOffset;
@Override
protected ContraptionType getType() {
return ContraptionType.PULLEY;
@ -62,4 +62,8 @@ public class PulleyContraption extends TranslatingContraption {
public ContraptionLighter<?> makeLighter() {
return new PulleyLighter(this);
}
public int getInitialOffset() {
return initialOffset;
}
}

View file

@ -47,18 +47,22 @@ public class PulleyRenderer extends AbstractPulleyRenderer {
@Override
protected boolean isRunning(KineticTileEntity te) {
return ((PulleyTileEntity) te).running || te.isVirtual();
return isPulleyRunning(te);
}
public static boolean isPulleyRunning(KineticTileEntity te) {
PulleyTileEntity pte = (PulleyTileEntity) te;
return pte.running || pte.mirrorParent != null || te.isVirtual();
}
static float getTileOffset(float partialTicks, PulleyTileEntity tile) {
public static float getTileOffset(float partialTicks, PulleyTileEntity tile) {
float offset = tile.getInterpolatedOffset(partialTicks);
if (tile.movedContraption != null) {
AbstractContraptionEntity e = tile.movedContraption;
PulleyContraption c = (PulleyContraption) tile.movedContraption.getContraption();
double entityPos = Mth.lerp(partialTicks, e.yOld, e.getY());
offset = (float) -(entityPos - c.anchor.getY() - c.initialOffset);
AbstractContraptionEntity attachedContraption = tile.getAttachedContraption();
if (attachedContraption != null) {
PulleyContraption c = (PulleyContraption) attachedContraption.getContraption();
double entityPos = Mth.lerp(partialTicks, attachedContraption.yOld, attachedContraption.getY());
offset = (float) -(entityPos - c.anchor.getY() - c.getInitialOffset());
}
return offset;

View file

@ -1,8 +1,13 @@
package com.simibubi.create.content.contraptions.components.structureMovement.pulley;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.AbstractContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
import com.simibubi.create.content.contraptions.components.structureMovement.BlockMovementChecks;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionCollider;
@ -14,13 +19,14 @@ import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.nbt.Tag;
import net.minecraft.util.Mth;
import net.minecraft.world.level.block.Blocks;
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.properties.BlockStateProperties;
@ -34,13 +40,23 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
protected int initialOffset;
private float prevAnimatedOffset;
protected BlockPos mirrorParent;
protected List<BlockPos> mirrorChildren;
public WeakReference<AbstractContraptionEntity> sharedMirrorContraption;
public PulleyTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
}
@Override
protected AABB createRenderBoundingBox() {
return super.createRenderBoundingBox().expandTowards(0, -offset, 0);
double expandY = -offset;
if (sharedMirrorContraption != null) {
AbstractContraptionEntity ace = sharedMirrorContraption.get();
if (ace != null)
expandY = ace.getY() - worldPosition.getY();
}
return super.createRenderBoundingBox().expandTowards(0, expandY, 0);
}
@Override
@ -48,25 +64,46 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
super.addBehaviours(behaviours);
registerAwardables(behaviours, AllAdvancements.PULLEY_MAXED);
}
@Override
public void tick() {
float prevOffset = offset;
super.tick();
if (level.isClientSide() && mirrorParent != null)
if (sharedMirrorContraption == null || sharedMirrorContraption.get() == null
|| !sharedMirrorContraption.get()
.isAlive()) {
sharedMirrorContraption = null;
if (level.getBlockEntity(mirrorParent)instanceof PulleyTileEntity pte && pte.movedContraption != null)
sharedMirrorContraption = new WeakReference<>(pte.movedContraption);
}
if (isVirtual())
prevAnimatedOffset = offset;
invalidateRenderBoundingBox();
if (prevOffset < 200 && offset >= 200)
award(AllAdvancements.PULLEY_MAXED);
}
@Override
protected boolean isPassive() {
return mirrorParent != null;
}
@Nullable
public AbstractContraptionEntity getAttachedContraption() {
return mirrorParent != null && sharedMirrorContraption != null ? sharedMirrorContraption.get()
: movedContraption;
}
@Override
protected void assemble() throws AssemblyException {
if (!(level.getBlockState(worldPosition)
.getBlock() instanceof PulleyBlock))
return;
if (speed == 0)
if (speed == 0 && mirrorParent == null)
return;
int maxLength = AllConfigs.SERVER.kinetics.maxRopeLength.get();
int i = 1;
@ -85,7 +122,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
return;
// Collect Construct
if (!level.isClientSide) {
if (!level.isClientSide && mirrorParent == null) {
needsContraption = false;
BlockPos anchor = worldPosition.below(Mth.floor(offset + 1));
initialOffset = Mth.floor(offset);
@ -102,17 +139,7 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
if (!canAssembleStructure && getSpeed() > 0)
return;
for (i = ((int) offset); i > 0; i--) {
BlockPos offset = worldPosition.below(i);
BlockState oldState = level.getBlockState(offset);
if (oldState.getBlock() instanceof SimpleWaterloggedBlock
&& oldState.hasProperty(BlockStateProperties.WATERLOGGED)
&& oldState.getValue(BlockStateProperties.WATERLOGGED)) {
level.setBlock(offset, Blocks.WATER.defaultBlockState(), 66);
continue;
}
level.setBlock(offset, Blocks.AIR.defaultBlockState(), 66);
}
removeRopes();
if (!contraption.getBlocks()
.isEmpty()) {
@ -122,27 +149,48 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
level.addFreshEntity(movedContraption);
forceMove = true;
needsContraption = true;
if (contraption.containsBlockBreakers())
award(AllAdvancements.CONTRAPTION_ACTORS);
for (BlockPos pos : contraption.createColliders(level, Direction.UP)) {
if (pos.getY() != 0)
continue;
pos = pos.offset(anchor);
if (level.getBlockEntity(
new BlockPos(pos.getX(), worldPosition.getY(), pos.getZ()))instanceof PulleyTileEntity pte)
pte.startMirroringOther(worldPosition);
}
}
}
if (mirrorParent != null)
removeRopes();
clientOffsetDiff = 0;
running = true;
sendData();
}
private void removeRopes() {
for (int i = ((int) offset); i > 0; i--) {
BlockPos offset = worldPosition.below(i);
BlockState oldState = level.getBlockState(offset);
level.setBlock(offset, oldState.getFluidState()
.createLegacyBlock(), 66);
}
}
@Override
public void disassemble() {
if (!running && movedContraption == null)
if (!running && movedContraption == null && mirrorParent == null)
return;
offset = getGridOffset(offset);
if (movedContraption != null)
resetContraptionToOffset();
if (!level.isClientSide) {
if (!remove) {
if (shouldCreateRopes()) {
if (offset > 0) {
BlockPos magnetPos = worldPosition.below((int) offset);
FluidState ifluidstate = level.getFluidState(magnetPos);
@ -170,24 +218,30 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
.setValue(BlockStateProperties.WATERLOGGED, waterlog[i]), 66);
}
if (movedContraption != null)
if (movedContraption != null && mirrorParent == null)
movedContraption.disassemble();
notifyMirrorsOfDisassembly();
}
if (movedContraption != null)
movedContraption.discard();
movedContraption = null;
initialOffset = 0;
running = false;
sendData();
}
protected boolean shouldCreateRopes() {
return !remove;
}
@Override
protected Vec3 toPosition(float offset) {
if (movedContraption.getContraption() instanceof PulleyContraption) {
PulleyContraption contraption = (PulleyContraption) movedContraption.getContraption();
return Vec3.atLowerCornerOf(contraption.anchor)
.add(0, contraption.initialOffset - offset, 0);
.add(0, contraption.getInitialOffset() - offset, 0);
}
return Vec3.ZERO;
@ -219,12 +273,70 @@ public class PulleyTileEntity extends LinearActuatorTileEntity implements Stockp
initialOffset = compound.getInt("InitialOffset");
needsContraption = compound.getBoolean("NeedsContraption");
super.read(compound, clientPacket);
BlockPos prevMirrorParent = mirrorParent;
mirrorParent = null;
mirrorChildren = null;
if (compound.contains("MirrorParent")) {
mirrorParent = NbtUtils.readBlockPos(compound.getCompound("MirrorParent"));
offset = 0;
if (prevMirrorParent == null || !prevMirrorParent.equals(mirrorParent))
sharedMirrorContraption = null;
}
if (compound.contains("MirrorChildren"))
mirrorChildren = NBTHelper.readCompoundList(compound.getList("MirrorChildren", Tag.TAG_COMPOUND),
NbtUtils::readBlockPos);
if (mirrorParent == null)
sharedMirrorContraption = null;
}
@Override
public void write(CompoundTag compound, boolean clientPacket) {
compound.putInt("InitialOffset", initialOffset);
super.write(compound, clientPacket);
if (mirrorParent != null)
compound.put("MirrorParent", NbtUtils.writeBlockPos(mirrorParent));
if (mirrorChildren != null)
compound.put("MirrorChildren", NBTHelper.writeCompoundList(mirrorChildren, NbtUtils::writeBlockPos));
}
public void startMirroringOther(BlockPos parent) {
if (parent.equals(worldPosition))
return;
if (!(level.getBlockEntity(parent)instanceof PulleyTileEntity pte))
return;
if (pte.getType() != getType())
return;
if (pte.mirrorChildren == null)
pte.mirrorChildren = new ArrayList<>();
pte.mirrorChildren.add(worldPosition);
pte.notifyUpdate();
mirrorParent = parent;
try {
assemble();
} catch (AssemblyException e) {
}
notifyUpdate();
}
public void notifyMirrorsOfDisassembly() {
if (mirrorChildren == null)
return;
for (BlockPos blockPos : mirrorChildren) {
if (!(level.getBlockEntity(blockPos)instanceof PulleyTileEntity pte))
continue;
pte.offset = offset;
pte.disassemble();
pte.mirrorParent = null;
pte.notifyUpdate();
}
mirrorChildren.clear();
notifyUpdate();
}
@Override

View file

@ -39,6 +39,6 @@ public class RopePulleyInstance extends AbstractPulleyInstance {
}
protected boolean isRunning() {
return ((PulleyTileEntity) blockEntity).running || blockEntity.isVirtual();
return PulleyRenderer.isPulleyRunning(blockEntity);
}
}

View file

@ -24,6 +24,7 @@ import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -34,6 +35,11 @@ public class BlazeBurnerMovementBehaviour implements MovementBehaviour {
public boolean renderAsNormalTileEntity() {
return false;
}
@Override
public ItemStack canBeDisabledVia(MovementContext context) {
return null;
}
@Override
public void tick(MovementContext context) {

View file

@ -5,6 +5,7 @@ import java.util.Map;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption;
import com.simibubi.create.content.logistics.trains.entity.CarriageContraptionEntity;
import com.simibubi.create.content.logistics.trains.entity.CarriageSyncData;
import com.simibubi.create.foundation.utility.animation.LerpedFloat.Chaser;
@ -24,7 +25,12 @@ public class SlidingDoorMovementBehaviour implements MovementBehaviour {
public boolean renderAsNormalTileEntity() {
return true;
}
@Override
public boolean mustTickWhileDisabled() {
return true;
}
@Override
public void tick(MovementContext context) {
StructureBlockInfo structureBlockInfo = context.contraption.getBlocks()
@ -97,6 +103,10 @@ public class SlidingDoorMovementBehaviour implements MovementBehaviour {
}
protected boolean shouldOpen(MovementContext context) {
if (context.disabled)
return false;
if (context.contraption instanceof ElevatorContraption ec && ec.arrived)
return true;
if (context.contraption.entity instanceof CarriageContraptionEntity cce) {
CarriageSyncData carriageData = cce.getCarriageData();
if (Math.abs(carriageData.distanceToDestination) > 1)

View file

@ -0,0 +1,29 @@
package com.simibubi.create.content.logistics.block.display.source;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContactTileEntity;
import com.simibubi.create.content.logistics.block.display.DisplayLinkContext;
import com.simibubi.create.content.logistics.block.display.target.DisplayTargetStats;
import com.simibubi.create.foundation.utility.Components;
import net.minecraft.network.chat.MutableComponent;
public class CurrentFloorDisplaySource extends SingleLineDisplaySource {
@Override
protected MutableComponent provideLine(DisplayLinkContext context, DisplayTargetStats stats) {
if (!(context.getSourceTE() instanceof ElevatorContactTileEntity ecte))
return EMPTY_LINE;
return Components.literal(ecte.lastReportedCurrentFloor);
}
@Override
protected String getTranslationKey() {
return "current_floor";
}
@Override
protected boolean allowsLabeling(DisplayLinkContext context) {
return false;
}
}

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.logistics.block.redstone;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementContext;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContraption;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -16,7 +17,9 @@ public class ContactMovementBehaviour implements MovementBehaviour {
@Override
public Vec3 getActiveAreaOffset(MovementContext context) {
return Vec3.atLowerCornerOf(context.state.getValue(RedstoneContactBlock.FACING).getNormal()).scale(.65f);
return Vec3.atLowerCornerOf(context.state.getValue(RedstoneContactBlock.FACING)
.getNormal())
.scale(.65f);
}
@Override
@ -31,16 +34,22 @@ public class ContactMovementBehaviour implements MovementBehaviour {
deactivateLastVisitedContact(context);
BlockState visitedState = world.getBlockState(pos);
if (!AllBlocks.REDSTONE_CONTACT.has(visitedState))
if (!AllBlocks.REDSTONE_CONTACT.has(visitedState) && !AllBlocks.ELEVATOR_CONTACT.has(visitedState))
return;
Vec3 contact = Vec3.atLowerCornerOf(block.getValue(RedstoneContactBlock.FACING).getNormal());
Vec3 contact = Vec3.atLowerCornerOf(block.getValue(RedstoneContactBlock.FACING)
.getNormal());
contact = context.rotation.apply(contact);
Direction direction = Direction.getNearest(contact.x, contact.y, contact.z);
if (!RedstoneContactBlock.hasValidContact(world, pos.relative(direction.getOpposite()), direction))
if (visitedState.getValue(RedstoneContactBlock.FACING) != direction.getOpposite())
return;
world.setBlockAndUpdate(pos, visitedState.setValue(RedstoneContactBlock.POWERED, true));
if (AllBlocks.REDSTONE_CONTACT.has(visitedState))
world.setBlockAndUpdate(pos, visitedState.setValue(RedstoneContactBlock.POWERED, true));
if (AllBlocks.ELEVATOR_CONTACT.has(visitedState) && context.contraption instanceof ElevatorContraption ec)
ec.broadcastFloorData(world, pos);
context.data.put("lastContact", NbtUtils.writeBlockPos(pos));
return;
}
@ -49,7 +58,7 @@ public class ContactMovementBehaviour implements MovementBehaviour {
public void stopMoving(MovementContext context) {
deactivateLastVisitedContact(context);
}
@Override
public void cancelStall(MovementContext context) {
MovementBehaviour.super.cancelStall(context);
@ -57,11 +66,15 @@ public class ContactMovementBehaviour implements MovementBehaviour {
}
public void deactivateLastVisitedContact(MovementContext context) {
if (context.data.contains("lastContact")) {
BlockPos last = NbtUtils.readBlockPos(context.data.getCompound("lastContact"));
if (!context.data.contains("lastContact"))
return;
BlockPos last = NbtUtils.readBlockPos(context.data.getCompound("lastContact"));
context.data.remove("lastContact");
BlockState blockState = context.world.getBlockState(last);
if (AllBlocks.REDSTONE_CONTACT.has(blockState))
context.world.scheduleTick(last, AllBlocks.REDSTONE_CONTACT.get(), 1, TickPriority.NORMAL);
context.data.remove("lastContact");
}
}
}

View file

@ -93,25 +93,25 @@ public class NixieTubeRenderer extends SafeTileEntityRenderer<NixieTubeTileEntit
ms.pushPose();
ms.translate((charWidth - shadowOffset) / -2f, -height, 0);
drawChar(ms, buffer, c, flickeringBrightColor);
drawInWorldString(ms, buffer, c, flickeringBrightColor);
ms.pushPose();
ms.translate(shadowOffset, shadowOffset, -1 / 16f);
drawChar(ms, buffer, c, darkColor);
drawInWorldString(ms, buffer, c, darkColor);
ms.popPose();
ms.popPose();
ms.pushPose();
ms.scale(-1, 1, 1);
ms.translate((charWidth - shadowOffset) / -2f, -height, 0);
drawChar(ms, buffer, c, darkColor);
drawInWorldString(ms, buffer, c, darkColor);
ms.pushPose();
ms.translate(-shadowOffset, shadowOffset, -1 / 16f);
drawChar(ms, buffer, c, Color.mixColors(darkColor, 0, .35f));
drawInWorldString(ms, buffer, c, Color.mixColors(darkColor, 0, .35f));
ms.popPose();
ms.popPose();
}
private static void drawChar(PoseStack ms, MultiBufferSource buffer, String c, int color) {
public static void drawInWorldString(PoseStack ms, MultiBufferSource buffer, String c, int color) {
Font fontRenderer = Minecraft.getInstance().font;
fontRenderer.drawInBatch(c, 0, 0, color, false, ms.last()
.pose(), buffer, false, 0, LightTexture.FULL_BRIGHT);

View file

@ -16,6 +16,7 @@ import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
@ -62,19 +63,17 @@ public class RedstoneContactBlock extends WrenchableDirectionalBlock {
if (facing != stateIn.getValue(FACING))
return stateIn;
boolean hasValidContact = hasValidContact(worldIn, currentPos, facing);
if (stateIn.getValue(POWERED) != hasValidContact) {
if (stateIn.getValue(POWERED) != hasValidContact)
return stateIn.setValue(POWERED, hasValidContact);
}
return stateIn;
}
@SuppressWarnings("deprecation")
@Override
public void onRemove(BlockState state, Level worldIn, BlockPos pos, BlockState newState, boolean isMoving) {
if (state.getBlock() == this && newState.getBlock() == this) {
if (state.getBlock() == this && newState.getBlock() == this)
if (state == newState.cycle(POWERED))
worldIn.updateNeighborsAt(pos, this);
}
super.onRemove(state, worldIn, pos, newState, isMoving);
}
@ -87,7 +86,13 @@ public class RedstoneContactBlock extends WrenchableDirectionalBlock {
public static boolean hasValidContact(LevelAccessor world, BlockPos pos, Direction direction) {
BlockState blockState = world.getBlockState(pos.relative(direction));
return AllBlocks.REDSTONE_CONTACT.has(blockState) && blockState.getValue(FACING) == direction.getOpposite();
return (AllBlocks.REDSTONE_CONTACT.has(blockState) || AllBlocks.ELEVATOR_CONTACT.has(blockState))
&& blockState.getValue(FACING) == direction.getOpposite();
}
@Override
public boolean shouldCheckWeakPower(BlockState state, LevelReader level, BlockPos pos, Direction side) {
return false;
}
@Override
@ -104,7 +109,8 @@ public class RedstoneContactBlock extends WrenchableDirectionalBlock {
@Override
public int getSignal(BlockState state, BlockGetter blockAccess, BlockPos pos, Direction side) {
return state.getValue(POWERED) ? 15 : 0;
return state.getValue(POWERED) && side != state.getValue(FACING)
.getOpposite() ? 15 : 0;
}
}

View file

@ -0,0 +1,43 @@
package com.simibubi.create.content.logistics.block.redstone;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorColumn.ColumnCoords;
import com.simibubi.create.foundation.utility.BlockHelper;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
public class RedstoneContactItem extends BlockItem {
public RedstoneContactItem(Block pBlock, Properties pProperties) {
super(pBlock, pProperties);
}
@Override
protected BlockState getPlacementState(BlockPlaceContext ctx) {
Level world = ctx.getLevel();
BlockPos pos = ctx.getClickedPos();
BlockState state = super.getPlacementState(ctx);
if (state == null)
return state;
if (!(state.getBlock() instanceof RedstoneContactBlock))
return state;
Direction facing = state.getValue(RedstoneContactBlock.FACING);
if (facing.getAxis() == Axis.Y)
return state;
if (ElevatorColumn.get(world, new ColumnCoords(pos.getX(), pos.getZ(), facing)) == null)
return state;
return BlockHelper.copyProperties(state, AllBlocks.ELEVATOR_CONTACT.getDefaultState());
}
}

View file

@ -126,7 +126,7 @@ public class CarriageContraption extends Contraption {
if (!blocks.containsKey(controlsPos))
return false;
StructureBlockInfo info = blocks.get(controlsPos);
if (!AllBlocks.CONTROLS.has(info.state))
if (!AllBlocks.TRAIN_CONTROLS.has(info.state))
return false;
return info.state.getValue(ControlsBlock.FACING) == direction.getOpposite();
}
@ -173,7 +173,7 @@ public class CarriageContraption extends Contraption {
&& blockState.getValue(BlazeBurnerBlock.HEAT_LEVEL) != HeatLevel.NONE)
assembledBlazeBurners.add(toLocalPos(pos));
if (AllBlocks.CONTROLS.has(blockState)) {
if (AllBlocks.TRAIN_CONTROLS.has(blockState)) {
Direction facing = blockState.getValue(ControlsBlock.FACING);
if (facing.getAxis() != assemblyDirection.getAxis())
sidewaysControls = true;

View file

@ -3,9 +3,9 @@ package com.simibubi.create.content.logistics.trains.management.display;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Random;
import com.google.common.base.Strings;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.NBTHelper;
@ -16,6 +16,7 @@ import net.minecraft.util.Mth;
public class FlapDisplaySection {
static final Map<String, String[]> LOADED_FLAP_CYCLES = new HashMap<>();
static Random r = new Random();
public static final float MONOSPACE = 7;
public static final float WIDE_MONOSPACE = 9;
@ -83,7 +84,7 @@ public class FlapDisplaySection {
spinningTicks = 0;
}
public int tick() {
public int tick(boolean instant) {
if (cyclingOptions == null)
return 0;
int max = Math.max(4, (int) (cyclingOptions.length * 1.75f));
@ -97,13 +98,13 @@ public class FlapDisplaySection {
int spinningFlaps = 0;
for (int i = 0; i < spinning.length; i++) {
int increasingChance = Mth.clamp(8 - spinningTicks, 1, 10);
boolean continueSpin = Create.RANDOM.nextInt(increasingChance * max / 4) != 0;
boolean continueSpin = !instant && r.nextInt(increasingChance * max / 4) != 0;
continueSpin &= max > 5 || spinningTicks < 2;
spinning[i] &= continueSpin;
if (i > 0 && Create.RANDOM.nextInt(3) > 0)
if (i > 0 && r.nextInt(3) > 0)
spinning[i - 1] &= continueSpin;
if (i < spinning.length - 1 && Create.RANDOM.nextInt(3) > 0)
if (i < spinning.length - 1 && r.nextInt(3) > 0)
spinning[i + 1] &= continueSpin;
if (spinningTicks > max)
spinning[i] = false;

View file

@ -111,9 +111,10 @@ public class FlapDisplayTileEntity extends KineticTileEntity {
if ((!level.isClientSide || !isRunning) && !isVirtual())
return;
int activeFlaps = 0;
boolean instant = getSpeed() > 128;
for (FlapDisplayLayout line : lines)
for (FlapDisplaySection section : line.getSections())
activeFlaps += section.tick();
activeFlaps += section.tick(instant);
if (activeFlaps == 0)
return;

View file

@ -73,7 +73,7 @@ public class ChangeThrottleInstruction extends ScheduleInstruction {
}
private ItemStack icon() {
return AllBlocks.CONTROLS.asStack();
return AllBlocks.TRAIN_CONTROLS.asStack();
}
@Override

View file

@ -1,6 +1,7 @@
package com.simibubi.create.events;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorControlsHandler;
import com.simibubi.create.content.contraptions.components.structureMovement.interaction.controls.TrainHUD;
import com.simibubi.create.content.curiosities.toolbox.ToolboxHandlerClient;
import com.simibubi.create.content.logistics.item.LinkedControllerClientHandler;
@ -43,7 +44,8 @@ public class InputEvents {
// CollisionDebugger.onScroll(delta);
boolean cancelled = CreateClient.SCHEMATIC_HANDLER.mouseScrolled(delta)
|| CreateClient.SCHEMATIC_AND_QUILL_HANDLER.mouseScrolled(delta) || FilteringHandler.onScroll(delta)
|| ScrollValueHandler.onScroll(delta) || TrainHUD.onScroll(delta);
|| ScrollValueHandler.onScroll(delta) || TrainHUD.onScroll(delta)
|| ElevatorControlsHandler.onScroll(delta);
event.setCanceled(cancelled);
}

View file

@ -60,7 +60,7 @@ public class AllCommands {
.then(CameraDistanceCommand.register())
.then(CameraAngleCommand.register())
.then(FlySpeedCommand.register())
//.then(KillTPSCommand.register())
.then(KillTPSCommand.register())
.build();
}

View file

@ -593,7 +593,7 @@ public class StandardRecipeGen extends CreateRecipeProvider {
.viaShapeless(b -> b.requires(I.railwayCasing())
.requires(Items.COMPASS)),
TRAIN_CONTROLS = create(AllBlocks.CONTROLS).unlockedBy(I::railwayCasing)
TRAIN_CONTROLS = create(AllBlocks.TRAIN_CONTROLS).unlockedBy(I::railwayCasing)
.viaShaped(b -> b.define('I', I.precisionMechanism())
.define('B', Items.LEVER)
.define('C', I.railwayCasing())

View file

@ -131,6 +131,8 @@ public enum AllGuiTextures implements ScreenElement {
I_NEW_TRAIN("schedule_2", 14, 239, 24, 16),
I_DISASSEMBLE_TRAIN("schedule_2", 39, 239, 24, 16),
I_ASSEMBLE_TRAIN("schedule_2", 64, 239, 24, 16),
ELEVATOR_CONTACT("display_link", 20, 172, 233, 82),
// JEI
JEI_SLOT("jei/widgets", 18, 18),

View file

@ -8,11 +8,15 @@ import java.util.function.Function;
import java.util.function.Supplier;
import com.simibubi.create.Create;
import com.simibubi.create.content.contraptions.components.actors.controls.ContraptionDisableActorPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionBlockChangedPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionDisassemblyPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionRelocationPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionStallPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.TrainCollisionPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorContactEditPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorFloorListPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.elevator.ElevatorTargetFloorPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.gantry.GantryContraptionUpdatePacket;
import com.simibubi.create.content.contraptions.components.structureMovement.glue.GlueEffectPacket;
import com.simibubi.create.content.contraptions.components.structureMovement.glue.SuperGlueRemovalPacket;
@ -148,6 +152,10 @@ public enum AllPackets {
OBSERVER_STRESSOMETER(GaugeObservedPacket.class, GaugeObservedPacket::new, PLAY_TO_SERVER),
EJECTOR_AWARD(EjectorAwardPacket.class, EjectorAwardPacket::new, PLAY_TO_SERVER),
TRACK_GRAPH_REQUEST(TrackGraphRequestPacket.class, TrackGraphRequestPacket::new, PLAY_TO_SERVER),
CONFIGURE_ELEVATOR_CONTACT(ElevatorContactEditPacket.class, ElevatorContactEditPacket::new, PLAY_TO_SERVER),
REQUEST_FLOOR_LIST(ElevatorFloorListPacket.RequestFloorList.class, ElevatorFloorListPacket.RequestFloorList::new,
PLAY_TO_SERVER),
ELEVATOR_SET_FLOOR(ElevatorTargetFloorPacket.class, ElevatorTargetFloorPacket::new, PLAY_TO_SERVER),
// Server to Client
SYMMETRY_EFFECT(SymmetryEffectPacket.class, SymmetryEffectPacket::new, PLAY_TO_CLIENT),
@ -184,6 +192,8 @@ public enum AllPackets {
S_TRAIN_PROMPT(TrainPromptPacket.class, TrainPromptPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_RELOCATION(ContraptionRelocationPacket.class, ContraptionRelocationPacket::new, PLAY_TO_CLIENT),
TRACK_GRAPH_ROLL_CALL(TrackGraphRollCallPacket.class, TrackGraphRollCallPacket::new, PLAY_TO_CLIENT),
UPDATE_ELEVATOR_FLOORS(ElevatorFloorListPacket.class, ElevatorFloorListPacket::new, PLAY_TO_CLIENT),
CONTRAPTION_ACTOR_TOGGLE(ContraptionDisableActorPacket.class, ContraptionDisableActorPacket::new, PLAY_TO_CLIENT),
;

View file

@ -320,7 +320,7 @@ public class PonderIndex {
HELPER.forComponents(AllItems.SCHEDULE)
.addStoryBoard("train_schedule", TrainScenes::schedule);
HELPER.forComponents(AllBlocks.CONTROLS)
HELPER.forComponents(AllBlocks.TRAIN_CONTROLS)
.addStoryBoard("train_controls", TrainScenes::controls);
HELPER.forComponents(AllBlocks.TRACK_OBSERVER)
@ -377,7 +377,7 @@ public class PonderIndex {
.add(AllBlocks.TRACK_STATION)
.add(AllBlocks.TRACK_SIGNAL)
.add(AllBlocks.TRACK_OBSERVER)
.add(AllBlocks.CONTROLS)
.add(AllBlocks.TRAIN_CONTROLS)
.add(AllItems.SCHEDULE)
.add(AllBlocks.TRAIN_DOOR)
.add(AllBlocks.TRAIN_TRAPDOOR)
@ -522,7 +522,7 @@ public class PonderIndex {
.add(AllBlocks.ANDESITE_FUNNEL)
.add(AllBlocks.BRASS_FUNNEL)
.add(AllBlocks.SEATS.get(DyeColor.WHITE))
.add(AllBlocks.CONTROLS)
.add(AllBlocks.TRAIN_CONTROLS)
.add(AllBlocks.REDSTONE_CONTACT)
.add(Blocks.BELL)
.add(Blocks.DISPENSER)

View file

@ -38,10 +38,14 @@ public class ValueBox extends ChasingAABBOutline {
protected BlockState blockState;
public ValueBox(Component label, AABB bb, BlockPos pos) {
this(label, bb, pos, Minecraft.getInstance().level.getBlockState(pos));
}
public ValueBox(Component label, AABB bb, BlockPos pos, BlockState state) {
super(bb);
this.label = label;
this.pos = pos;
this.blockState = Minecraft.getInstance().level.getBlockState(pos);
this.blockState = state;
}
public ValueBox transform(ValueBoxTransform transform) {
@ -169,6 +173,11 @@ public class ValueBox extends ChasingAABBOutline {
super(label, bb, pos);
this.text = text;
}
public TextValueBox(Component label, AABB bb, BlockPos pos, BlockState state, Component text) {
super(label, bb, pos, state);
this.text = text;
}
@Override
public void renderContents(PoseStack ms, MultiBufferSource buffer) {

View file

@ -1,6 +1,8 @@
package com.simibubi.create.foundation.tileEntity.behaviour;
import com.jozufozu.flywheel.util.transform.TransformStack;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Matrix3f;
import com.simibubi.create.content.contraptions.relays.elementary.AbstractSimpleShaftBlock;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
@ -8,8 +10,10 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.block.model.ItemTransforms.TransformType;
import net.minecraft.client.renderer.entity.ItemRenderer;
import net.minecraft.client.renderer.texture.OverlayTexture;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -33,6 +37,45 @@ public class ValueBoxRenderer {
itemRenderer.renderStatic(filter, TransformType.FIXED, light, overlay, ms, buffer, 0);
}
public static void renderFlatItemIntoValueBox(ItemStack filter, PoseStack ms, MultiBufferSource buffer, int light,
int overlay) {
if (filter.isEmpty())
return;
int bl = light >> 4 & 0xf;
int sl = light >> 20 & 0xf;
int itemLight = Mth.floor(sl + .5) << 20 | (Mth.floor(bl + .5) & 0xf) << 4;
ms.pushPose();
TransformStack.cast(ms)
.rotateX(230);
Matrix3f copy = ms.last()
.normal()
.copy();
ms.popPose();
ms.pushPose();
TransformStack.cast(ms)
.translate(0, 0, -1 / 4f)
.translate(0, 0, 1 / 32f + .001)
.rotateY(180);
PoseStack squashedMS = new PoseStack();
squashedMS.last()
.pose()
.multiply(ms.last()
.pose());
squashedMS.scale(.5f, .5f, 1 / 1024f);
squashedMS.last()
.normal()
.load(copy);
Minecraft.getInstance()
.getItemRenderer()
.renderStatic(filter, TransformType.GUI, itemLight, OverlayTexture.NO_OVERLAY, squashedMS, buffer, 0);
ms.popPose();
}
@SuppressWarnings("deprecation")
private static float customZOffset(Item item) {
float nudge = -.1f;
@ -44,7 +87,8 @@ public class ValueBoxRenderer {
return nudge;
if (block instanceof FenceBlock)
return nudge;
if (block.builtInRegistryHolder().is(BlockTags.BUTTONS))
if (block.builtInRegistryHolder()
.is(BlockTags.BUTTONS))
return nudge;
if (block == Blocks.END_ROD)
return nudge;

View file

@ -1,6 +1,7 @@
package com.simibubi.create.foundation.tileEntity.behaviour.filtering;
import com.mojang.blaze3d.vertex.PoseStack;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.logistics.item.filter.FilterItem;
@ -131,7 +132,10 @@ public class FilteringRenderer {
ms.pushPose();
slotPositioning.transform(blockState, ms);
ValueBoxRenderer.renderItemIntoValueBox(filter, ms, buffer, light, overlay);
if (AllBlocks.CONTRAPTION_CONTROLS.has(blockState))
ValueBoxRenderer.renderFlatItemIntoValueBox(filter, ms, buffer, light, overlay);
else
ValueBoxRenderer.renderItemIntoValueBox(filter, ms, buffer, light, overlay);
ms.popPose();
}
sided.fromSide(side);

Some files were not shown because too many files have changed in this diff Show more