Merge pull request #1 from Creators-of-Create/mc1.15/dev

sync 1.15/dev progress
This commit is contained in:
YukkuriC 2020-08-28 12:22:21 +08:00 committed by GitHub
commit bb21a5f96d
Failed to generate hash of commit
216 changed files with 5856 additions and 2024 deletions

View file

@ -41,7 +41,7 @@ e81608346d43406ee72cae0f78b8bcfb37ba2d75 assets/create/blockstates/brown_seat.js
2ca82a3c4bf7ba1a9cf3bb674e786d9b23b020a4 assets/create/blockstates/chiseled_limestone.json
cbcdab42d01f8085db9e5f8db884f8adf7f17625 assets/create/blockstates/chiseled_scoria.json
291952556c52fba2af5bbd793c71af81abd27e71 assets/create/blockstates/chiseled_weathered_limestone.json
99def0a786714a337e2b1b17db844e4d1aee6234 assets/create/blockstates/chute.json
b59324f051f21d8ce1a48a08f4721a61a3c414d6 assets/create/blockstates/chute.json
4947c261310445fa55b92038326ac82967d192dd assets/create/blockstates/clockwork_bearing.json
1f33834c685e3243882acfe20183fe64dfa872be assets/create/blockstates/clutch.json
e5e3757e99c139d67b2a70288466d8a74d818841 assets/create/blockstates/cogwheel.json
@ -91,6 +91,7 @@ f63a5816d4bfe643aa098d03c3b54462dd06fe19 assets/create/blockstates/dolomite_cobb
f179202e59e449157f89efc37229b03bbfd391d7 assets/create/blockstates/dolomite_pillar.json
7b1c40891b07c8f3238537625d9e25c8627e7333 assets/create/blockstates/encased_belt.json
7b2b836649e729feafa60972bf95e3afb2143131 assets/create/blockstates/encased_fan.json
656813b75dd3b901bf34f24df785e4b0fbe11aa6 assets/create/blockstates/encased_fluid_pipe.json
e157d7f67b08493b71d7ffea8d622f4a64dbc155 assets/create/blockstates/encased_shaft.json
1442ff1a0e404f99263ba99d734da1dfed03d4e3 assets/create/blockstates/extractor.json
a774e815376a67e2a2de44e39af0a1a0b4406932 assets/create/blockstates/fancy_andesite_bricks.json
@ -129,7 +130,7 @@ de8a40b7daf1497d5aecee47a43b3e0b1d030b00 assets/create/blockstates/fancy_scoria_
fc9ac0a7e7191b93516719455a17177fa6524ecc assets/create/blockstates/fancy_weathered_limestone_bricks_slab.json
b2a7c321b1795f20e7433f81a55ce4683de081b8 assets/create/blockstates/fancy_weathered_limestone_bricks_stairs.json
6372fe02ba0065acb0758121c45a15a1a8fdc5de assets/create/blockstates/fancy_weathered_limestone_bricks_wall.json
3d97226b5e8d8f70ed08e45e78db1faf78d5e28b assets/create/blockstates/fluid_pipe.json
fe9169716dd21a81a3710a89f0a9b7ea4dcd4d51 assets/create/blockstates/fluid_pipe.json
f0eaab18e16c4f3f65ebf3b55b08f0dc445720fe assets/create/blockstates/fluid_tank.json
e9da1794b6ece7f9aa8bcb43d42c23a55446133b assets/create/blockstates/flywheel.json
ac00d40e1ef50a37041c0481afa1a23a14dea78e assets/create/blockstates/framed_glass.json
@ -147,6 +148,7 @@ a64d8d0924c0b5b192f355343dd9b3a440875f6a assets/create/blockstates/gabbro_cobble
a6b44e8a1c4ce0c7442b2384b41ad36dd133f19b assets/create/blockstates/gabbro_pillar.json
9c48e311be8b959bfb98e16ffaa358210ac8b9dd assets/create/blockstates/gearbox.json
f34814b17cde3231a1dfb271f3dabf8d6de4fbf6 assets/create/blockstates/gearshift.json
93f8bdc22d9a5e04268964e35e4285c8cbf2b89d assets/create/blockstates/glass_fluid_pipe.json
87661d61e1645ef5ad4ea34f1c0fa31f139ea431 assets/create/blockstates/granite_bricks.json
d7f4cf7be7e9a3895840d9288245c52cbe25f0bd assets/create/blockstates/granite_bricks_slab.json
ec51efc72eb6b16c5f99399b4cb6284665d5be99 assets/create/blockstates/granite_bricks_stairs.json
@ -357,17 +359,17 @@ c77b46d8b459e5c7cc495393546f3fcca8a1fa1d assets/create/blockstates/weathered_lim
a3a11524cd3515fc01d905767b4b7ea782adaf03 assets/create/blockstates/yellow_seat.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
a9bcfd546e95865633a97e4b29e39c4aec940338 assets/create/lang/en_ud.json
aa14daef8d31ca69ace4e643ffdc5cc9aba22818 assets/create/lang/en_us.json
b4435a02a94ae72032f3ffb8f9282e41b1dca953 assets/create/lang/unfinished/de_de.json
4f9cc39db1e0de14e9aeabea93676b8fa8ba58ec assets/create/lang/unfinished/fr_fr.json
a5a1d2d2e6154c07be187dfe2e33c203db1dd678 assets/create/lang/unfinished/it_it.json
022fee71a855d3cd206c2c1d5c36c38f089f8120 assets/create/lang/unfinished/ja_jp.json
07da262b3005fd53abd22b5da558e3494bbefa90 assets/create/lang/unfinished/ko_kr.json
f1a7c021d2a48a56141ffe70ddec7128c5ad7261 assets/create/lang/unfinished/nl_nl.json
5e10814eb0606a6bd20097067394a93842ef7957 assets/create/lang/unfinished/pt_br.json
f1367be00730002ee0f233dfebb5e920eed56900 assets/create/lang/unfinished/ru_ru.json
76928b7d9f7f41f4fa622824a872bec8e5635cea assets/create/lang/unfinished/zh_cn.json
15f8e8f779c6ce41a9e42d87796df14d1415ab5a assets/create/lang/en_ud.json
3c6d8906ded9a78050003f8b029407ef2078da87 assets/create/lang/en_us.json
1abcbe5404e82eb9b944c9075eb39ff3b20512e5 assets/create/lang/unfinished/de_de.json
e9f885ab2cee12075ec10a85e95e2f0a7fc49d9b assets/create/lang/unfinished/fr_fr.json
44331773068529facc64870b0762609567fec8b6 assets/create/lang/unfinished/it_it.json
e3c2ef988da795fc84ea8a9bff8b8557ac6c370a assets/create/lang/unfinished/ja_jp.json
a5c17249f0b2575c372c658bfd958fe4244fb5d6 assets/create/lang/unfinished/ko_kr.json
abcfc0ab1bf1b077f0aeaf54e00c2aceef78d253 assets/create/lang/unfinished/nl_nl.json
899ebaa95bf6d3140bf6bbcf6f8a5fab2ab5111e assets/create/lang/unfinished/pt_br.json
bba218b9d488faf4406d975eba81996f621b2200 assets/create/lang/unfinished/ru_ru.json
b87385232b0be35079736a3a32ff88f252721cf3 assets/create/lang/unfinished/zh_cn.json
846200eb548d3bfa2e77b41039de159b4b6cfb45 assets/create/models/block/acacia_window.json
1930fa3a3c98d53dd19e4ee7f55bc27fd47aa281 assets/create/models/block/acacia_window_pane_noside.json
1763ea2c9b981d187f5031ba608f3d5d3be3986a assets/create/models/block/acacia_window_pane_noside_alt.json
@ -544,6 +546,7 @@ cc6d9300cd26f2323c653dbcc61b7a885be8fa3b assets/create/models/block/dolomite_cob
a101974d906487326dc38916f828d12a278a49ae assets/create/models/block/dolomite_cobblestone_wall_post.json
9c497140dfe73abe1964479eaf1af8f1892de290 assets/create/models/block/dolomite_cobblestone_wall_side.json
999a7cd79a9dc80c47fd6103b65f006b55187402 assets/create/models/block/dolomite_pillar.json
1a8bac1e97a2a6c3cc362081568d2a7fce815ad5 assets/create/models/block/encased_fluid_pipe.json
17dae5fdc1a551d8ab1ab8a68cabf7a8c3848d86 assets/create/models/block/fancy_andesite_bricks.json
cfb2cd84a1cbd9226a77ebc1f6c29e8eaa9c577f assets/create/models/block/fancy_andesite_bricks_slab.json
8ee27601996ab577991b6a0f7e9df27db0282cad assets/create/models/block/fancy_andesite_bricks_slab_top.json
@ -1441,6 +1444,14 @@ a135eec618e448f440d9f42cc7a3e6c63fc45a71 data/create/advancements/overstressed.j
1e3cd82e36fd4bcd053d652a0eead4458ed7f315 data/create/advancements/press.json
b2782692d27ffb105e3167174cebe1ebdd4a9867 data/create/advancements/recipes/create.base/brass_block.json
df6f220e693f5256bb3df8d6c7769bc931820ae5 data/create/advancements/recipes/create.base/copper_block.json
dbe67196168805a5903aa29de7631d33329060d1 data/create/advancements/recipes/create.base/crafting_shaped/schematics/schematic_table.json
0c5badff77b751b086b0da5943bea186256668cb data/create/advancements/recipes/create.base/crafting_shaped/schematics/schematicannon.json
c2ff86e360002e714877060540378940b8d72c4b data/create/advancements/recipes/create.base/crafting_shapeless/appliances/dough.json
b77cfa58f80d92299ea628b361bd42d462517d13 data/create/advancements/recipes/create.base/crafting_shapeless/materials/red_sand_paper.json
cbbd15261cbb270237347cf00246a6b4045e5ce0 data/create/advancements/recipes/create.base/crafting_shapeless/materials/rose_quartz.json
aaea2ee62bb7888e83fcc282c87bc6cb970d30ec data/create/advancements/recipes/create.base/crafting_shapeless/materials/sand_paper.json
f6b8aa96169d3857c31d8a087ca1dd6b5077defc data/create/advancements/recipes/create.base/crafting_shapeless/schematics/empty_schematic.json
e53989fa8a2742b55226e4af040ae3a98cc07994 data/create/advancements/recipes/create.base/crafting_shapeless/schematics/schematic_and_quill.json
82280c50b78dd7e8c179cb8e8f0c074b26ec9586 data/create/advancements/recipes/create.base/zinc_block.json
909345eb2f5541a2be592a52800319a8765ca345 data/create/advancements/recipes/create.palettes/acacia_window.json
73f99cd857b056da5e19ff8304a4f5eeacc4f8cd data/create/advancements/recipes/create.palettes/acacia_window_pane.json
@ -1815,6 +1826,8 @@ b77c5aecd0b6dd37a0c69431ab7a4a40fe0770eb data/create/advancements/recipes/create
e548127075559307b767b802f4809ed52eedd543 data/create/advancements/recipes/create.palettes/weathered_limestone_cobblestone_wall_from_weathered_limestone_cobblestone_stonecutting.json
23ba836640a4d543db6f1cb72cc86a6543fe2fbe data/create/advancements/recipes/create.palettes/weathered_limestone_pillar.json
9790a16fd56e47cb5abbfad4062672303c224d9f data/create/advancements/recipes/create.palettes/weathered_limestone_pillar_from_weathered_limestone_stonecutting.json
731da8361ecf00e2280a269e15cee00195d70bd7 data/create/advancements/recipes/food/crafting_shaped/appliances/cake.json
fc2411c0f4a4da43f6f213fc3bfffd35e6ad3775 data/create/advancements/recipes/misc/crafting_shapeless/appliances/slime_ball.json
e0b9edc5e59647e7dd99be17369b263dadf407d4 data/create/advancements/refined_radiance.json
fc12b590ab8f5ac901db21c67ba3850f157e1421 data/create/advancements/root.json
8529fc7919b6a3240ede2bb8043906bb72fb7f9e data/create/advancements/shadow_end.json
@ -1920,6 +1933,7 @@ d5fc5b3dc612cd748117e9d8b0ecda76e73f4514 data/create/loot_tables/blocks/dolomite
6121c99e6e037dda9022af3a414aee444467ac1b data/create/loot_tables/blocks/dolomite_pillar.json
503a93787537b46f462d32b0382c3396f42bb1f6 data/create/loot_tables/blocks/encased_belt.json
9055d82b983b673e1638d17b712b9fcd1f5a52e6 data/create/loot_tables/blocks/encased_fan.json
c8aa9bbed8fd703eb1853de0b7c9e04dffb7a511 data/create/loot_tables/blocks/encased_fluid_pipe.json
b127cb6920e6d7d9c8b2402cb186402a9a8dd3fc data/create/loot_tables/blocks/encased_shaft.json
5a47c1535c866184b4ffca65763f5676f319e0aa data/create/loot_tables/blocks/extractor.json
ddfc4764a6039d771e03af815ac4493da80d2e6b data/create/loot_tables/blocks/fancy_andesite_bricks.json
@ -1976,6 +1990,7 @@ ae19749df10663efc51b8b27af310164f250ed38 data/create/loot_tables/blocks/gabbro_c
e8d09c919e3b8125d7da0f38383c01bcfc61c7a8 data/create/loot_tables/blocks/gabbro_pillar.json
b0109b4a4f0f738cbbe6b5911e8c3c0310b76f99 data/create/loot_tables/blocks/gearbox.json
5f39461c5c9d3ad8d84195b06b9468fe2b0fb269 data/create/loot_tables/blocks/gearshift.json
c8aa9bbed8fd703eb1853de0b7c9e04dffb7a511 data/create/loot_tables/blocks/glass_fluid_pipe.json
74371bc2b516ad9742ca081d82dc1b7f642e25b4 data/create/loot_tables/blocks/granite_bricks.json
29f2cbc04f898bb8ff48055a7e43ded85e635bf9 data/create/loot_tables/blocks/granite_bricks_slab.json
6b2c74992f261df4f539ff65919e2f4a58b146ec data/create/loot_tables/blocks/granite_bricks_stairs.json
@ -2214,6 +2229,16 @@ c323b106e88b7de77fea71ff12494abdbb818d15 data/create/recipes/chiseled_limestone_
da9a919b476954c1de34826aa7706bf6056a8f12 data/create/recipes/chiseled_scoria_from_scoria_stonecutting.json
09faa4ddcf9f3907dcdb3ab3e8b68c1deb2486e5 data/create/recipes/chiseled_weathered_limestone_from_weathered_limestone_stonecutting.json
386c52f0aad6e2239f31dc85f7e745b47230846b data/create/recipes/copper_block.json
d19b3fa4bedacedf0c57aecba5a7e025e5a6b032 data/create/recipes/crafting_shaped/appliances/cake.json
5a7ee5951c15db03a4e38f5cbc1833f3d889e2b1 data/create/recipes/crafting_shaped/schematics/schematic_table.json
50cffa44fb016b856629538cb0be52c162139ec5 data/create/recipes/crafting_shaped/schematics/schematicannon.json
19526da3a59fc136654ff1bc93c0251581f397a9 data/create/recipes/crafting_shapeless/appliances/dough.json
7b5f863dda3d05a79cb85943a178eba0bd8a7dc7 data/create/recipes/crafting_shapeless/appliances/slime_ball.json
9c9e40ffd41ce46c65113080a92ff9b4f27e5fab data/create/recipes/crafting_shapeless/materials/red_sand_paper.json
7eb292bc564de70227f4bf947050bcdbfc5a8d67 data/create/recipes/crafting_shapeless/materials/rose_quartz.json
5ca47ec1bca9a5ce28aabd9868b74b71c829ca07 data/create/recipes/crafting_shapeless/materials/sand_paper.json
0b7acc249bed992387aa9702a2c05836ecf584df data/create/recipes/crafting_shapeless/schematics/empty_schematic.json
5c47ac2e2b596439a684126fef7265f13de2379b data/create/recipes/crafting_shapeless/schematics/schematic_and_quill.json
f2c317e03ac4d42fb631e1625607061e10c480fe data/create/recipes/dark_oak_window.json
d9dbae6e237eb38e53a619a0f1b339fca7c59b4d data/create/recipes/dark_oak_window_pane.json
55596a590962e3ddd40949917661f0bd94408274 data/create/recipes/dark_scoria_bricks_from_dark_scoria_stonecutting.json

View file

@ -1,39 +1,39 @@
{
"variants": {
"facing=down,shape=start": {
"model": "create:block/chute/block_windowed"
"facing=down,shape=intersection": {
"model": "create:block/chute/block_intersection"
},
"facing=north,shape=start": {
"model": "create:block/chute/block_diagonal_start",
"facing=north,shape=intersection": {
"model": "create:block/chute/block_diagonal_intersection",
"y": 180
},
"facing=south,shape=start": {
"model": "create:block/chute/block_diagonal_start"
"facing=south,shape=intersection": {
"model": "create:block/chute/block_diagonal_intersection"
},
"facing=west,shape=start": {
"model": "create:block/chute/block_diagonal_start",
"facing=west,shape=intersection": {
"model": "create:block/chute/block_diagonal_intersection",
"y": 90
},
"facing=east,shape=start": {
"model": "create:block/chute/block_diagonal_start",
"facing=east,shape=intersection": {
"model": "create:block/chute/block_diagonal_intersection",
"y": 270
},
"facing=down,shape=window_straight": {
"facing=down,shape=window": {
"model": "create:block/chute/block_windowed"
},
"facing=north,shape=window_straight": {
"model": "create:block/chute/block_diagonal_straight",
"facing=north,shape=window": {
"model": "create:block/chute/block_diagonal",
"y": 180
},
"facing=south,shape=window_straight": {
"model": "create:block/chute/block_diagonal_straight"
"facing=south,shape=window": {
"model": "create:block/chute/block_diagonal"
},
"facing=west,shape=window_straight": {
"model": "create:block/chute/block_diagonal_straight",
"facing=west,shape=window": {
"model": "create:block/chute/block_diagonal",
"y": 90
},
"facing=east,shape=window_straight": {
"model": "create:block/chute/block_diagonal_straight",
"facing=east,shape=window": {
"model": "create:block/chute/block_diagonal",
"y": 270
},
"facing=down,shape=normal": {

View file

@ -0,0 +1,17 @@
{
"variants": {
"axis=x": {
"model": "create:block/encased_fluid_pipe",
"x": 90,
"y": 90
},
"axis=y": {
"model": "create:block/encased_fluid_pipe"
},
"axis=z": {
"model": "create:block/encased_fluid_pipe",
"x": 90,
"y": 180
}
}
}

View file

@ -303,8 +303,8 @@
{
"when": {
"west": "false",
"down": "false",
"east": "true",
"down": "false",
"up": "true"
},
"apply": {
@ -314,8 +314,8 @@
{
"when": {
"west": "true",
"down": "false",
"east": "false",
"down": "false",
"up": "true"
},
"apply": {
@ -325,8 +325,8 @@
{
"when": {
"west": "false",
"down": "true",
"east": "true",
"down": "true",
"up": "false"
},
"apply": {
@ -336,8 +336,8 @@
{
"when": {
"west": "true",
"down": "true",
"east": "false",
"down": "true",
"up": "false"
},
"apply": {
@ -347,8 +347,8 @@
{
"when": {
"west": "false",
"down": "true",
"east": "false",
"down": "true",
"up": "true"
},
"apply": {
@ -358,8 +358,8 @@
{
"when": {
"west": "false",
"down": "false",
"east": "false",
"down": "false",
"up": "true"
},
"apply": {
@ -369,8 +369,8 @@
{
"when": {
"west": "false",
"down": "true",
"east": "false",
"down": "true",
"up": "false"
},
"apply": {
@ -380,8 +380,8 @@
{
"when": {
"west": "true",
"down": "false",
"east": "true",
"down": "false",
"up": "false"
},
"apply": {
@ -391,8 +391,8 @@
{
"when": {
"west": "false",
"down": "false",
"east": "true",
"down": "false",
"up": "false"
},
"apply": {
@ -402,8 +402,8 @@
{
"when": {
"west": "true",
"down": "false",
"east": "false",
"down": "false",
"up": "false"
},
"apply": {
@ -413,8 +413,8 @@
{
"when": {
"west": "false",
"down": "false",
"east": "false",
"down": "false",
"up": "false"
},
"apply": {

View file

@ -0,0 +1,30 @@
{
"variants": {
"alt=false,axis=x": {
"model": "create:block/fluid_pipe/window",
"x": 90,
"y": 90
},
"alt=true,axis=x": {
"model": "create:block/fluid_pipe/window_alt",
"x": 90,
"y": 90
},
"alt=false,axis=y": {
"model": "create:block/fluid_pipe/window"
},
"alt=true,axis=y": {
"model": "create:block/fluid_pipe/window_alt"
},
"alt=false,axis=z": {
"model": "create:block/fluid_pipe/window",
"x": 90,
"y": 180
},
"alt=true,axis=z": {
"model": "create:block/fluid_pipe/window_alt",
"x": 90,
"y": 180
}
}
}

View file

@ -92,6 +92,7 @@
"block.create.dolomite_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 \u01DD\u0287\u0131\u026Fo\u05DFo\u15E1",
"block.create.encased_belt": "\u0287\u05DF\u01DD\u15FA 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",
"block.create.encased_shaft": "\u0287\u025F\u0250\u0265S p\u01DDs\u0250\u0254u\u018E",
"block.create.extractor": "\u0279o\u0287\u0254\u0250\u0279\u0287x\u018E",
"block.create.fancy_andesite_bricks": "s\u029E\u0254\u0131\u0279\u15FA \u01DD\u0287\u0131s\u01DDpu\u2C6F \u028E\u0254u\u0250\u2132",
@ -148,6 +149,7 @@
"block.create.gabbro_pillar": "\u0279\u0250\u05DF\u05DF\u0131\u0500 o\u0279qq\u0250\u2141",
"block.create.gearbox": "xoq\u0279\u0250\u01DD\u2141",
"block.create.gearshift": "\u0287\u025F\u0131\u0265s\u0279\u0250\u01DD\u2141",
"block.create.glass_fluid_pipe": "\u01DDd\u0131\u0500 p\u0131n\u05DF\u2132 ss\u0250\u05DF\u2141",
"block.create.granite_bricks": "s\u029E\u0254\u0131\u0279\u15FA \u01DD\u0287\u0131u\u0250\u0279\u2141",
"block.create.granite_bricks_slab": "q\u0250\u05DFS s\u029E\u0254\u0131\u0279\u15FA \u01DD\u0287\u0131u\u0250\u0279\u2141",
"block.create.granite_bricks_stairs": "s\u0279\u0131\u0250\u0287S s\u029E\u0254\u0131\u0279\u15FA \u01DD\u0287\u0131u\u0250\u0279\u2141",

View file

@ -95,6 +95,7 @@
"block.create.dolomite_pillar": "Dolomite Pillar",
"block.create.encased_belt": "Encased Belt",
"block.create.encased_fan": "Encased Fan",
"block.create.encased_fluid_pipe": "Encased Fluid Pipe",
"block.create.encased_shaft": "Encased Shaft",
"block.create.extractor": "Extractor",
"block.create.fancy_andesite_bricks": "Fancy Andesite Bricks",
@ -151,6 +152,7 @@
"block.create.gabbro_pillar": "Gabbro Pillar",
"block.create.gearbox": "Gearbox",
"block.create.gearshift": "Gearshift",
"block.create.glass_fluid_pipe": "Glass Fluid Pipe",
"block.create.granite_bricks": "Granite Bricks",
"block.create.granite_bricks_slab": "Granite Bricks Slab",
"block.create.granite_bricks_stairs": "Granite Bricks Stairs",
@ -462,7 +464,7 @@
"advancement.create.electron_tube": "Beep boop",
"advancement.create.electron_tube.desc": "Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "Stationary Chopping",
"advancement.create.mechanical_saw.desc": "Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "Place and power a Mechanical Saw",
"advancement.create.basin": "Basin Operation",
"advancement.create.basin.desc": "Place a basin and try throwing items into it.",
"advancement.create.mixer": "Mixin' it Up",
@ -520,7 +522,7 @@
"death.attack.create.fan_fire": "%1$s was burned to death by hot air",
"death.attack.create.fan_lava": "%1$s was burned to death by lava fan",
"death.attack.create.mechanical_drill": "%1$s was impaled by Mechanical mechanical_drill",
"death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical mechanical_saw",
"death.attack.create.mechanical_saw": "%1$s got cut in half by Mechanical Saw",
"death.attack.create.cuckoo_clock_explosion": "%1$s was blown up by tampered cuckoo clock",
"create.block.deployer.damage_source_name": "a rogue Deployer",
@ -537,7 +539,7 @@
"create.recipe.pressing": "Pressing",
"create.recipe.mixing": "Mixing",
"create.recipe.packing": "Compacting",
"create.recipe.mechanical_sawing": "mechanical_sawing",
"create.recipe.mechanical_sawing": "Sawing",
"create.recipe.mechanical_crafting": "Mechanical Crafting",
"create.recipe.block_cutting": "Block Cutting",
"create.recipe.blockzapper_upgrade": "Handheld Blockzapper",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 814",
"_": "Missing Localizations: 816",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Dolomitsäule",
"block.create.encased_belt": "Eingeschlossener Riemen",
"block.create.encased_fan": "Eingeschlossener Propeller",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Eingeschlossene Welle",
"block.create.extractor": "Auswerfer",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Getriebe",
"block.create.gearshift": "Gangschaltung",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Granitziegel",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",
@ -521,7 +523,7 @@
"death.attack.create.fan_fire": "%1$s hat heiße Luft eingeatmet",
"death.attack.create.fan_lava": "%1$s wurde von Lava verweht",
"death.attack.create.mechanical_drill": "%1$s wurde von einem Bohrer durchlöchert",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical mechanical_saw",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical Saw",
"death.attack.create.cuckoo_clock_explosion": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock",
"create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer",
@ -538,7 +540,7 @@
"create.recipe.pressing": "Mechanische Presse",
"create.recipe.mixing": "UNLOCALIZED: Mixing",
"create.recipe.packing": "UNLOCALIZED: Compacting",
"create.recipe.mechanical_sawing": "UNLOCALIZED: mechanical_sawing",
"create.recipe.mechanical_sawing": "UNLOCALIZED: Sawing",
"create.recipe.mechanical_crafting": "UNLOCALIZED: Mechanical Crafting",
"create.recipe.block_cutting": "UNLOCALIZED: Block Cutting",
"create.recipe.blockzapper_upgrade": "Blockpistole",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 417",
"_": "Missing Localizations: 419",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Pillier de dolomie",
"block.create.encased_belt": "Tapis roulant enfermé",
"block.create.encased_fan": "Ventilateur enfermé",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Arbre mécanique enfermé",
"block.create.extractor": "Extracteur",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Boîte à roue dentée",
"block.create.gearshift": "Décaleur de rotation",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Briques de granite",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 401",
"_": "Missing Localizations: 403",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Pilastro di Dolomite",
"block.create.encased_belt": "Nastro Incassato",
"block.create.encased_fan": "Ventilatore incassato",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Albero Incassato",
"block.create.extractor": "Estrattore",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Riduttore",
"block.create.gearshift": "Cambio",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Mattoni di Granito",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 396",
"_": "Missing Localizations: 398",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "苦灰石の柱",
"block.create.encased_belt": "ケース入りベルト",
"block.create.encased_fan": "ケース入りファン",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "ケース入りシャフト",
"block.create.extractor": "エクストラクター",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "ギアボックス",
"block.create.gearshift": "ギアシフト",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "花崗岩レンガ",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 401",
"_": "Missing Localizations: 403",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "백운암 기둥",
"block.create.encased_belt": "덮힌 벨트",
"block.create.encased_fan": "덮힌 환풍기",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "덮힌 축",
"block.create.extractor": "추출기",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "기어박스",
"block.create.gearshift": "기어쉬프트",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "화강암 벽돌",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 751",
"_": "Missing Localizations: 753",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Dolomiet Pilaar",
"block.create.encased_belt": "Omhulsde Transportband",
"block.create.encased_fan": "Omhulsde Ventilator",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Omhulsde Drijfas",
"block.create.extractor": "Extractor",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Versnellingsbak",
"block.create.gearshift": "Versnellingspook",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Granietstenen",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",
@ -521,7 +523,7 @@
"death.attack.create.fan_fire": "%1$s is verbrand door hete lucht",
"death.attack.create.fan_lava": "%1$s is verbrand door een lava ventilator",
"death.attack.create.mechanical_drill": "%1$s is gespietst door een mechanische boor",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical mechanical_saw",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical Saw",
"death.attack.create.cuckoo_clock_explosion": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock",
"create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 821",
"_": "Missing Localizations: 823",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Pilar de Dolomite",
"block.create.encased_belt": "Esteira Revestida",
"block.create.encased_fan": "Ventilador Revestida",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Eixo Revestido",
"block.create.extractor": "Extrator",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Caixa de Transmissão",
"block.create.gearshift": "Câmbio",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Tijolos de Granito",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",
@ -521,7 +523,7 @@
"death.attack.create.fan_fire": "%1$s foi queimado por ar quente",
"death.attack.create.fan_lava": "%1$s foi queimado pelo ventilador de lava",
"death.attack.create.mechanical_drill": "%1$s foi empalado pela Furadeira Mecânica",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical mechanical_saw",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical Saw",
"death.attack.create.cuckoo_clock_explosion": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock",
"create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer",
@ -538,7 +540,7 @@
"create.recipe.pressing": "Prensa Mecânica",
"create.recipe.mixing": "UNLOCALIZED: Mixing",
"create.recipe.packing": "UNLOCALIZED: Compacting",
"create.recipe.mechanical_sawing": "UNLOCALIZED: mechanical_sawing",
"create.recipe.mechanical_sawing": "UNLOCALIZED: Sawing",
"create.recipe.mechanical_crafting": "UNLOCALIZED: Mechanical Crafting",
"create.recipe.block_cutting": "UNLOCALIZED: Block Cutting",
"create.recipe.blockzapper_upgrade": "Blockzapper Portátil",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 815",
"_": "Missing Localizations: 817",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "Доломитовая колонна",
"block.create.encased_belt": "Ленточный привод",
"block.create.encased_fan": "Вентилятор",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "Вальный привод",
"block.create.extractor": "Экстрактор",
"block.create.fancy_andesite_bricks": "UNLOCALIZED: Fancy Andesite Bricks",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "UNLOCALIZED: Gabbro Pillar",
"block.create.gearbox": "Муфта",
"block.create.gearshift": "Реверсивная муфта",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "Гранитные кирпичи",
"block.create.granite_bricks_slab": "UNLOCALIZED: Granite Bricks Slab",
"block.create.granite_bricks_stairs": "UNLOCALIZED: Granite Bricks Stairs",
@ -463,7 +465,7 @@
"advancement.create.electron_tube": "UNLOCALIZED: Beep boop",
"advancement.create.electron_tube.desc": "UNLOCALIZED: Make some Electron Tubes, useful in crafting less primitive machinery.",
"advancement.create.mechanical_saw": "UNLOCALIZED: Stationary Chopping",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical mechanical_saw",
"advancement.create.mechanical_saw.desc": "UNLOCALIZED: Place and power a Mechanical Saw",
"advancement.create.basin": "UNLOCALIZED: Basin Operation",
"advancement.create.basin.desc": "UNLOCALIZED: Place a basin and try throwing items into it.",
"advancement.create.mixer": "UNLOCALIZED: Mixin' it Up",
@ -521,7 +523,7 @@
"death.attack.create.fan_fire": "%1$s сгорел заживо от горячего воздуха.",
"death.attack.create.fan_lava": "%1$s сгорел заживо от лавового вентилятора",
"death.attack.create.mechanical_drill": "%1$s был проколот механическим буром",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical mechanical_saw",
"death.attack.create.mechanical_saw": "UNLOCALIZED: %1$s got cut in half by Mechanical Saw",
"death.attack.create.cuckoo_clock_explosion": "UNLOCALIZED: %1$s was blown up by tampered cuckoo clock",
"create.block.deployer.damage_source_name": "UNLOCALIZED: a rogue Deployer",
@ -538,7 +540,7 @@
"create.recipe.pressing": "Механический пресс",
"create.recipe.mixing": "UNLOCALIZED: Mixing",
"create.recipe.packing": "UNLOCALIZED: Compacting",
"create.recipe.mechanical_sawing": "UNLOCALIZED: mechanical_sawing",
"create.recipe.mechanical_sawing": "UNLOCALIZED: Sawing",
"create.recipe.mechanical_crafting": "UNLOCALIZED: Mechanical Crafting",
"create.recipe.block_cutting": "UNLOCALIZED: Block Cutting",
"create.recipe.blockzapper_upgrade": "Портативный размещатель блоков",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 77",
"_": "Missing Localizations: 79",
"_": "->------------------------] Game Elements [------------------------<-",
@ -96,6 +96,7 @@
"block.create.dolomite_pillar": "竖纹白云岩",
"block.create.encased_belt": "连携齿轮箱",
"block.create.encased_fan": "鼓风机",
"block.create.encased_fluid_pipe": "UNLOCALIZED: Encased Fluid Pipe",
"block.create.encased_shaft": "齿轮箱",
"block.create.extractor": "提取器",
"block.create.fancy_andesite_bricks": "方纹安山岩砖",
@ -152,6 +153,7 @@
"block.create.gabbro_pillar": "竖纹辉长岩",
"block.create.gearbox": "十字齿轮箱",
"block.create.gearshift": "红石齿轮箱",
"block.create.glass_fluid_pipe": "UNLOCALIZED: Glass Fluid Pipe",
"block.create.granite_bricks": "花岗岩砖",
"block.create.granite_bricks_slab": "花岗岩砖台阶",
"block.create.granite_bricks_stairs": "花岗岩砖楼梯",

View file

@ -0,0 +1,7 @@
{
"parent": "block/cube_column",
"textures": {
"side": "create:block/copper_casing",
"end": "create:block/encased_pipe"
}
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shaped/schematics/schematic_table"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "create:empty_schematic"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shaped/schematics/schematic_table"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shaped/schematics/schematicannon"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "create:empty_schematic"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shaped/schematics/schematicannon"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/appliances/dough"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "create:wheat_flour"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/appliances/dough"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/materials/red_sand_paper"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "minecraft:paper"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/materials/red_sand_paper"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/materials/rose_quartz"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "minecraft:redstone"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/materials/rose_quartz"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/materials/sand_paper"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "minecraft:paper"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/materials/sand_paper"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/schematics/empty_schematic"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "minecraft:paper"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/schematics/empty_schematic"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/schematics/schematic_and_quill"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "minecraft:paper"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/schematics/schematic_and_quill"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shaped/appliances/cake"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "create:dough"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shaped/appliances/cake"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,32 @@
{
"parent": "minecraft:recipes/root",
"rewards": {
"recipes": [
"create:crafting_shapeless/appliances/slime_ball"
]
},
"criteria": {
"has_item": {
"trigger": "minecraft:inventory_changed",
"conditions": {
"items": [
{
"item": "create:dough"
}
]
}
},
"has_the_recipe": {
"trigger": "minecraft:recipe_unlocked",
"conditions": {
"recipe": "create:crafting_shapeless/appliances/slime_ball"
}
}
},
"requirements": [
[
"has_item",
"has_the_recipe"
]
]
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "create:fluid_pipe"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"entries": [
{
"type": "minecraft:item",
"name": "create:fluid_pipe"
}
],
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
]
}
]
}

View file

@ -0,0 +1,25 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
" . ",
"#+#",
" - "
],
"key": {
"#": {
"item": "minecraft:sugar"
},
"+": {
"tag": "forge:eggs"
},
".": {
"item": "minecraft:milk_bucket"
},
"-": {
"item": "create:dough"
}
},
"result": {
"item": "minecraft:cake"
}
}

View file

@ -0,0 +1,19 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
"###",
" + ",
" + "
],
"key": {
"#": {
"tag": "minecraft:wooden_slabs"
},
"+": {
"item": "minecraft:smooth_stone"
}
},
"result": {
"item": "create:schematic_table"
}
}

View file

@ -0,0 +1,28 @@
{
"type": "minecraft:crafting_shaped",
"pattern": [
" . ",
"#+#",
"_-_"
],
"key": {
"#": {
"tag": "minecraft:logs"
},
"+": {
"item": "minecraft:dispenser"
},
".": {
"item": "minecraft:cauldron"
},
"_": {
"item": "minecraft:smooth_stone"
},
"-": {
"item": "minecraft:iron_block"
}
},
"result": {
"item": "create:schematicannon"
}
}

View file

@ -9,7 +9,6 @@
}
],
"result": {
"item": "create:dough",
"count": 1
"item": "create:dough"
}
}

View file

@ -0,0 +1,14 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "create:dough"
},
{
"tag": "forge:dyes/lime"
}
],
"result": {
"item": "minecraft:slime_ball"
}
}

View file

@ -2,14 +2,13 @@
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"tag": "forge:sand/red"
"item": "minecraft:paper"
},
{
"item": "minecraft:paper"
"tag": "forge:sand/red"
}
],
"result": {
"item": "create:red_sand_paper",
"count": 1
"item": "create:red_sand_paper"
}
}

View file

@ -0,0 +1,35 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"tag": "forge:gems/quartz"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
},
{
"tag": "forge:dusts/redstone"
}
],
"result": {
"item": "create:rose_quartz"
}
}

View file

@ -2,14 +2,13 @@
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"tag": "forge:sand/colorless"
"item": "minecraft:paper"
},
{
"item": "minecraft:paper"
"tag": "forge:sand/colorless"
}
],
"result": {
"item": "create:sand_paper",
"count": 1
"item": "create:sand_paper"
}
}

View file

@ -0,0 +1,14 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "minecraft:paper"
},
{
"tag": "forge:dyes/light_blue"
}
],
"result": {
"item": "create:empty_schematic"
}
}

View file

@ -0,0 +1,14 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "create:empty_schematic"
},
{
"tag": "forge:feathers"
}
],
"result": {
"item": "create:schematic_and_quill"
}
}

View file

@ -9,9 +9,11 @@ import java.util.List;
import java.util.Map;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour.AttachmentTypes;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock.HeatLevel;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Lang;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.SuperByteBuffer;
@ -30,46 +32,28 @@ public class AllBlockPartials {
public static final AllBlockPartials SCHEMATICANNON_CONNECTOR = get("schematicannon/connector"),
SCHEMATICANNON_PIPE = get("schematicannon/pipe"),
SHAFTLESS_COGWHEEL = get("cogwheel_shaftless"),
SHAFT_HALF = get("shaft_half"),
BELT_PULLEY = get("belt_pulley"),
BELT_START = get("belt/start"),
BELT_MIDDLE = get("belt/middle"),
BELT_END = get("belt/end"),
BELT_START_BOTTOM = get("belt/start_bottom"),
BELT_MIDDLE_BOTTOM = get("belt/middle_bottom"),
BELT_END_BOTTOM = get("belt/end_bottom"),
BELT_DIAGONAL_START = get("belt/diagonal_start"),
BELT_DIAGONAL_MIDDLE = get("belt/diagonal_middle"),
SHAFTLESS_COGWHEEL = get("cogwheel_shaftless"), SHAFT_HALF = get("shaft_half"),
BELT_PULLEY = get("belt_pulley"), BELT_START = get("belt/start"), BELT_MIDDLE = get("belt/middle"),
BELT_END = get("belt/end"), BELT_START_BOTTOM = get("belt/start_bottom"),
BELT_MIDDLE_BOTTOM = get("belt/middle_bottom"), BELT_END_BOTTOM = get("belt/end_bottom"),
BELT_DIAGONAL_START = get("belt/diagonal_start"), BELT_DIAGONAL_MIDDLE = get("belt/diagonal_middle"),
BELT_DIAGONAL_END = get("belt/diagonal_end"),
ENCASED_FAN_INNER = get("encased_fan/propeller"),
HAND_CRANK_HANDLE = get("hand_crank/handle"),
MECHANICAL_PRESS_HEAD = get("mechanical_press/head"),
MECHANICAL_MIXER_POLE = get("mechanical_mixer/pole"),
MECHANICAL_MIXER_HEAD = get("mechanical_mixer/head"),
MECHANICAL_CRAFTER_LID = get("mechanical_crafter/lid"),
ENCASED_FAN_INNER = get("encased_fan/propeller"), HAND_CRANK_HANDLE = get("hand_crank/handle"),
MECHANICAL_PRESS_HEAD = get("mechanical_press/head"), MECHANICAL_MIXER_POLE = get("mechanical_mixer/pole"),
MECHANICAL_MIXER_HEAD = get("mechanical_mixer/head"), MECHANICAL_CRAFTER_LID = get("mechanical_crafter/lid"),
MECHANICAL_CRAFTER_ARROW = get("mechanical_crafter/arrow"),
MECHANICAL_CRAFTER_BELT_FRAME = get("mechanical_crafter/belt"),
MECHANICAL_CRAFTER_BELT = get("mechanical_crafter/belt_animated"),
GAUGE_DIAL = get("gauge/dial"),
GAUGE_INDICATOR = get("gauge/indicator"),
GAUGE_HEAD_SPEED = get("gauge/speedometer/head"),
GAUGE_HEAD_STRESS = get("gauge/stressometer/head"),
BEARING_TOP = get("bearing/top"),
DRILL_HEAD = get("mechanical_drill/head"),
HARVESTER_BLADE = get("mechanical_harvester/blade"),
DEPLOYER_POLE = get("deployer/pole"),
DEPLOYER_HAND_POINTING = get("deployer/hand_pointing"),
DEPLOYER_HAND_PUNCHING = get("deployer/hand_punching"),
DEPLOYER_HAND_HOLDING = get("deployer/hand_holding"),
ANALOG_LEVER_HANDLE = get("analog_lever/handle"),
ANALOG_LEVER_INDICATOR = get("analog_lever/indicator"),
BELT_FUNNEL_FLAP = get("belt_funnel/flap"),
BELT_TUNNEL_FLAP = get("belt_tunnel/flap"),
FLEXPEATER_INDICATOR = get("diodes/indicator"),
FLYWHEEL = get("flywheel/wheel"),
MECHANICAL_CRAFTER_BELT = get("mechanical_crafter/belt_animated"), GAUGE_DIAL = get("gauge/dial"),
GAUGE_INDICATOR = get("gauge/indicator"), GAUGE_HEAD_SPEED = get("gauge/speedometer/head"),
GAUGE_HEAD_STRESS = get("gauge/stressometer/head"), BEARING_TOP = get("bearing/top"),
DRILL_HEAD = get("mechanical_drill/head"), HARVESTER_BLADE = get("mechanical_harvester/blade"),
DEPLOYER_POLE = get("deployer/pole"), DEPLOYER_HAND_POINTING = get("deployer/hand_pointing"),
DEPLOYER_HAND_PUNCHING = get("deployer/hand_punching"), DEPLOYER_HAND_HOLDING = get("deployer/hand_holding"),
ANALOG_LEVER_HANDLE = get("analog_lever/handle"), ANALOG_LEVER_INDICATOR = get("analog_lever/indicator"),
BELT_FUNNEL_FLAP = get("belt_funnel/flap"), BELT_TUNNEL_FLAP = get("belt_tunnel/flap"),
FLEXPEATER_INDICATOR = get("diodes/indicator"), FLYWHEEL = get("flywheel/wheel"),
FLYWHEEL_UPPER_ROTATING = get("flywheel/upper_rotating_connector"),
FLYWHEEL_LOWER_ROTATING = get("flywheel/lower_rotating_connector"),
@ -95,14 +79,14 @@ public class AllBlockPartials {
MECHANICAL_PUMP_ARROW = get("mechanical_pump/arrow"), MECHANICAL_PUMP_COG = get("mechanical_pump/cog"),
FLUID_PIPE_CASING = get("fluid_pipe/casing"),
COUPLING_ATTACHMENT = getEntity("minecart_coupling/attachment"),
COUPLING_RING = getEntity("minecart_coupling/ring"),
COUPLING_CONNECTOR = getEntity("minecart_coupling/connector")
;
public static final Map<Direction, AllBlockPartials> PIPE_RIMS = map();
;
public static final Map<AttachmentTypes, Map<Direction, AllBlockPartials>> PIPE_ATTACHMENTS = map();
public static final Map<HeatLevel, AllBlockPartials> BLAZES = map();
static {
@ -117,8 +101,16 @@ public class AllBlockPartials {
private AllBlockPartials() {}
private static void populateMaps() {
for (Direction d : Iterate.directions)
PIPE_RIMS.put(d, get("fluid_pipe/rim/" + d.getName()));
for (AttachmentTypes type : AttachmentTypes.values()) {
if (!type.hasModel())
continue;
Map<Direction, AllBlockPartials> map = map();
for (Direction d : Iterate.directions) {
String asId = Lang.asId(type.name());
map.put(d, get("fluid_pipe/" + asId + "/" + Lang.asId(d.getName())));
}
PIPE_ATTACHMENTS.put(type, map);
}
for (HeatLevel heat : HeatLevel.values()) {
if (heat == HeatLevel.NONE)
continue;
@ -136,7 +128,7 @@ public class AllBlockPartials {
all.add(partials);
return partials;
}
private static AllBlockPartials get(String path) {
AllBlockPartials partials = new AllBlockPartials();
partials.modelLocation = new ResourceLocation(Create.ID, "block/" + path);

View file

@ -59,13 +59,15 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul
import com.simibubi.create.content.contraptions.components.tracks.ReinforcedRailBlock;
import com.simibubi.create.content.contraptions.components.turntable.TurntableBlock;
import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelBlock;
import com.simibubi.create.content.contraptions.fluids.FluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.FluidPipeModel;
import com.simibubi.create.content.contraptions.fluids.FluidTankBlock;
import com.simibubi.create.content.contraptions.fluids.FluidTankGenerator;
import com.simibubi.create.content.contraptions.fluids.FluidTankItem;
import com.simibubi.create.content.contraptions.fluids.FluidTankModel;
import com.simibubi.create.content.contraptions.fluids.PipeAttachmentModel;
import com.simibubi.create.content.contraptions.fluids.PumpBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.EncasedPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.GlassFluidPipeBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankGenerator;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankItem;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankModel;
import com.simibubi.create.content.contraptions.processing.BasinBlock;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlock;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlockItem;
@ -219,12 +221,14 @@ public class AllBlocks {
.build()
.register();
public static final BlockEntry<EncasedShaftBlock> ENCASED_SHAFT = REGISTRATE.block("encased_shaft", EncasedShaftBlock::new)
public static final BlockEntry<EncasedShaftBlock> ENCASED_SHAFT =
REGISTRATE.block("encased_shaft", EncasedShaftBlock::new)
.initialProperties(SharedProperties::stone)
.properties(Block.Properties::nonOpaque)
.transform(StressConfigDefaults.setNoImpact())
//.blockstate(BlockStateGen.axisBlockProvider(true))
.blockstate((c, p) -> axisBlock(c, p, blockState -> p.models().getExistingFile(p.modLoc("block/encased_shaft/" + blockState.get(EncasedShaftBlock.CASING).getName()))))
.blockstate((c, p) -> axisBlock(c, p, blockState -> p.models()
.getExistingFile(p.modLoc("block/encased_shaft/" + blockState.get(EncasedShaftBlock.CASING)
.getName()))))
.loot((p, b) -> p.registerDropping(b, SHAFT.get()))
.register();
@ -461,14 +465,34 @@ public class AllBlocks {
public static final BlockEntry<FluidPipeBlock> FLUID_PIPE = REGISTRATE.block("fluid_pipe", FluidPipeBlock::new)
.initialProperties(SharedProperties::softMetal)
.blockstate(BlockStateGen.pipe())
.onRegister(CreateRegistrate.blockModel(() -> FluidPipeModel::new))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new))
.item()
.transform(customItemModel())
.register();
public static final BlockEntry<EncasedPipeBlock> ENCASED_FLUID_PIPE =
REGISTRATE.block("encased_fluid_pipe", EncasedPipeBlock::new)
.initialProperties(SharedProperties::softMetal)
.blockstate((c, p) -> BlockStateGen.axisBlock(c, p, state -> p.models()
.cubeColumn(c.getName(), p.modLoc("block/copper_casing"), p.modLoc("block/encased_pipe"))))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new))
.loot((p, b) -> p.registerDropping(b, FLUID_PIPE.get()))
.register();
public static final BlockEntry<GlassFluidPipeBlock> GLASS_FLUID_PIPE =
REGISTRATE.block("glass_fluid_pipe", GlassFluidPipeBlock::new)
.initialProperties(SharedProperties::softMetal)
.addLayer(() -> RenderType::getCutoutMipped)
.blockstate((c, p) -> BlockStateGen.axisBlock(c, p, s -> p.models()
.getExistingFile(p.modLoc("block/fluid_pipe/window" + (s.get(GlassFluidPipeBlock.ALT) ? "_alt" : "")))))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new))
.loot((p, b) -> p.registerDropping(b, FLUID_PIPE.get()))
.register();
public static final BlockEntry<PumpBlock> MECHANICAL_PUMP = REGISTRATE.block("mechanical_pump", PumpBlock::new)
.initialProperties(SharedProperties::softMetal)
.blockstate(BlockStateGen.directionalBlockProviderIgnoresWaterlogged(true))
.onRegister(CreateRegistrate.blockModel(() -> PipeAttachmentModel::new))
.transform(StressConfigDefaults.setImpact(4.0))
.item()
.transform(customItemModel())

View file

@ -6,6 +6,7 @@ import static net.minecraft.util.Direction.UP;
import java.util.function.BiFunction;
import com.simibubi.create.content.logistics.block.chute.ChuteShapes;
import com.simibubi.create.foundation.utility.VoxelShaper;
import net.minecraft.block.Block;
@ -28,6 +29,7 @@ public class AllShapes {
CASING_11PX = shape(0, 0, 0, 16, 11, 16).forDirectional(),
MOTOR_BLOCK = shape(3, 0, 3, 13, 14, 13).forDirectional(),
FOUR_VOXEL_POLE = shape(6, 0, 6, 10, 16, 10).forAxis(), SIX_VOXEL_POLE = shape(5, 0, 5, 11, 16, 11).forAxis(),
EIGHT_VOXEL_POLE = shape(4, 0, 4, 12, 16, 12).forAxis(),
EXTRACTOR = shape(4, 2, 11, 12, 10, 17).forDirectional(SOUTH)
.withVerticalShapes(cuboid(4, 11, 4, 12, 17, 12)),
TRANSPOSER = shape(4, 4, -1, 12, 12, 1).add(5, 5, 0, 11, 11, 16)
@ -111,14 +113,16 @@ public class AllShapes {
// Static Block Shapes
public static final VoxelShape
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 13, 16).erase(2, 5, 2, 14, 14, 14)
BASIN_BLOCK_SHAPE = shape(0, 2, 0, 16, 16, 16).erase(2, 2, 2, 14, 16, 14)
.add(2, 0, 2, 14, 2, 14)
.build(), HEATER_BLOCK_SHAPE =
shape(2, 0, 2, 14, 14, 14).add(0, 0, 0, 16, 4, 16)
.build(), BASIN_COLLISION_SHAPE =
shape(0, 2, 0, 16, 16, 16).erase(2, 5, 2, 14, 16, 14)
.add(2, 0, 2, 14, 2, 14)
.build(),
HEATER_BLOCK_SHAPE = shape(2, 0, 2, 14, 14, 14).add(0, 0, 0, 16, 4, 16)
.build(),
HEATER_BLOCK_SPECIAL_COLLISION_SHAPE = shape(0, 0, 0, 16, 4, 16).build(),
CRUSHING_WHEEL_COLLISION_SHAPE = cuboid(0, 0, 0, 16, 22, 16),
SEAT = cuboid(0, 0, 0, 16, 8, 16),
CRUSHING_WHEEL_COLLISION_SHAPE = cuboid(0, 0, 0, 16, 22, 16), SEAT = cuboid(0, 0, 0, 16, 8, 16),
SEAT_COLLISION = cuboid(0, 0, 0, 16, 6, 16),
MECHANICAL_PROCESSOR_SHAPE = shape(VoxelShapes.fullCube()).erase(4, 0, 4, 12, 16, 12)
.build(),
@ -171,7 +175,8 @@ public class AllShapes {
LOGISTICS_TABLE = shape(TABLE_POLE_SHAPE).add(LOGISTICS_TABLE_SLOPE)
.forHorizontal(SOUTH),
SCHEMATICS_TABLE = shape(TABLE_POLE_SHAPE).add(SCHEMATICS_TABLE_SLOPE)
.forDirectional(SOUTH)
.forDirectional(SOUTH),
CHUTE_SLOPE = shape(ChuteShapes.createSlope()).forHorizontal(SOUTH)
;

View file

@ -44,7 +44,7 @@ public enum AllSoundEvents implements IDataProvider {
AllSoundEvents() {
id = Lang.asId(name());
}
AllSoundEvents(String name) {
id = name;
}
@ -65,7 +65,7 @@ public enum AllSoundEvents implements IDataProvider {
return id;
}
public AllSoundEvents generator(DataGenerator generator){
public AllSoundEvents generator(DataGenerator generator) {
this.generator = generator;
return this;
}
@ -83,7 +83,9 @@ public enum AllSoundEvents implements IDataProvider {
}
public void generate(Path path, DirectoryCache cache) {
Gson GSON = (new GsonBuilder()).setPrettyPrinting().disableHtmlEscaping().create();
Gson GSON = (new GsonBuilder()).setPrettyPrinting()
.disableHtmlEscaping()
.create();
path = path.resolve("assets/create");
try {
@ -94,7 +96,8 @@ public enum AllSoundEvents implements IDataProvider {
if (soundEvent.child != null) {
// wrapper
JsonObject s = new JsonObject();
s.addProperty("name", soundEvent.child.getName().toString());
s.addProperty("name", soundEvent.child.getName()
.toString());
s.addProperty("type", "event");
arr.add(s);
} else {
@ -120,6 +123,6 @@ public enum AllSoundEvents implements IDataProvider {
@Override
public String getName() {
return null;
return "Create's Custom Sound: " + name();
}
}

View file

@ -11,6 +11,7 @@ public enum AllSpecialTextures {
BLANK("blank.png"),
CHECKERED("checkerboard.png"),
THIN_CHECKERED("thin_checkerboard.png"),
CUTOUT_CHECKERED("cutout_checkerboard.png"),
HIGHLIGHT_CHECKERED("highlighted_checkerboard.png"),
SELECTION("selection.png"),

View file

@ -43,10 +43,13 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pul
import com.simibubi.create.content.contraptions.components.structureMovement.pulley.PulleyTileEntity;
import com.simibubi.create.content.contraptions.components.turntable.TurntableTileEntity;
import com.simibubi.create.content.contraptions.components.waterwheel.WaterWheelTileEntity;
import com.simibubi.create.content.contraptions.fluids.FluidTankRenderer;
import com.simibubi.create.content.contraptions.fluids.FluidTankTileEntity;
import com.simibubi.create.content.contraptions.fluids.PumpRenderer;
import com.simibubi.create.content.contraptions.fluids.PumpTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.StraightPipeTileEntity;
import com.simibubi.create.content.contraptions.fluids.pipes.TransparentStraightPipeRenderer;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankRenderer;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankTileEntity;
import com.simibubi.create.content.contraptions.processing.BasinRenderer;
import com.simibubi.create.content.contraptions.processing.BasinTileEntity;
import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerRenderer;
@ -57,7 +60,11 @@ import com.simibubi.create.content.contraptions.relays.advanced.sequencer.Sequen
import com.simibubi.create.content.contraptions.relays.belt.BeltRenderer;
import com.simibubi.create.content.contraptions.relays.belt.BeltTileEntity;
import com.simibubi.create.content.contraptions.relays.elementary.SimpleKineticTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.*;
import com.simibubi.create.content.contraptions.relays.encased.AdjustablePulleyTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.ClutchTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftRenderer;
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftTileEntity;
import com.simibubi.create.content.contraptions.relays.encased.SplitShaftRenderer;
import com.simibubi.create.content.contraptions.relays.gauge.GaugeRenderer;
import com.simibubi.create.content.contraptions.relays.gauge.SpeedGaugeTileEntity;
import com.simibubi.create.content.contraptions.relays.gauge.StressGaugeTileEntity;
@ -86,7 +93,12 @@ import com.simibubi.create.content.logistics.block.mechanicalArm.ArmRenderer;
import com.simibubi.create.content.logistics.block.mechanicalArm.ArmTileEntity;
import com.simibubi.create.content.logistics.block.packager.PackagerRenderer;
import com.simibubi.create.content.logistics.block.packager.PackagerTileEntity;
import com.simibubi.create.content.logistics.block.redstone.*;
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverRenderer;
import com.simibubi.create.content.logistics.block.redstone.AnalogLeverTileEntity;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeRenderer;
import com.simibubi.create.content.logistics.block.redstone.NixieTubeTileEntity;
import com.simibubi.create.content.logistics.block.redstone.RedstoneLinkTileEntity;
import com.simibubi.create.content.logistics.block.redstone.StockpileSwitchTileEntity;
import com.simibubi.create.content.logistics.block.transposer.LinkedTransposerTileEntity;
import com.simibubi.create.content.logistics.block.transposer.TransposerTileEntity;
import com.simibubi.create.content.schematics.block.SchematicTableTileEntity;
@ -95,6 +107,7 @@ import com.simibubi.create.content.schematics.block.SchematicannonTileEntity;
import com.simibubi.create.foundation.tileEntity.renderer.SmartTileEntityRenderer;
import com.tterrag.registrate.util.entry.TileEntityEntry;
import com.tterrag.registrate.util.nullness.NonNullFunction;
import net.minecraft.tileentity.TileEntityType;
public class AllTileEntities {
@ -191,6 +204,22 @@ public class AllTileEntities {
.renderer(() -> PumpRenderer::new)
.register();
public static final TileEntityEntry<FluidPipeTileEntity> FLUID_PIPE = Create.registrate()
.tileEntity("fluid_pipe", FluidPipeTileEntity::new)
.validBlocks(AllBlocks.FLUID_PIPE)
.register();
public static final TileEntityEntry<StraightPipeTileEntity> ENCASED_FLUID_PIPE = Create.registrate()
.tileEntity("encased_fluid_pipe", StraightPipeTileEntity::new)
.validBlocks(AllBlocks.ENCASED_FLUID_PIPE)
.register();
public static final TileEntityEntry<StraightPipeTileEntity> GLASS_FLUID_PIPE = Create.registrate()
.tileEntity("glass_fluid_pipe", StraightPipeTileEntity::new)
.validBlocks(AllBlocks.GLASS_FLUID_PIPE)
.renderer(() -> TransparentStraightPipeRenderer::new)
.register();
public static final TileEntityEntry<FluidTankTileEntity> FLUID_TANK = Create.registrate()
.tileEntity("fluid_tank", (NonNullFunction<TileEntityType<FluidTankTileEntity>, ? extends FluidTankTileEntity>) FluidTankTileEntity::new)
.validBlocks(AllBlocks.FLUID_TANK)

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.command.ServerLagger;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.data.CreateRegistrate;
import com.simibubi.create.foundation.data.LangMerger;
import com.simibubi.create.foundation.data.StandardRecipes;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.worldgen.AllWorldFeatures;
import com.tterrag.registrate.util.NonNullLazyValue;
@ -102,6 +103,7 @@ public class Create {
DataGenerator gen = event.getGenerator();
gen.addProvider(new AllAdvancements(gen));
gen.addProvider(new LangMerger(gen));
gen.addProvider(new StandardRecipes(gen));
gen.addProvider(AllSoundEvents.BLAZE_MUNCH.generator(gen));
}

View file

@ -43,7 +43,7 @@ public class KineticDebugger {
VoxelShape shape = world.getBlockState(toOutline)
.getRenderShape(world, toOutline);
if (te.getTheoreticalSpeed() != 0)
if (te.getTheoreticalSpeed() != 0 && !shape.isEmpty())
CreateClient.outliner.chaseAABB("kineticSource", shape.getBoundingBox()
.offset(toOutline))
.lineWidth(1 / 16f)

View file

@ -178,7 +178,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
}
@Override
public CompoundNBT write(CompoundNBT compound) {
protected void write(CompoundNBT compound, boolean clientPacket) {
compound.putFloat("Speed", speed);
if (needsSpeedUpdate())
@ -202,7 +202,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
compound.put("Network", networkTag);
}
return super.write(compound);
super.write(compound, clientPacket);
}
public boolean needsSpeedUpdate() {
@ -210,12 +210,13 @@ public abstract class KineticTileEntity extends SmartTileEntity
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
boolean overStressedBefore = overStressed;
clearKineticInformation();
// DO NOT READ kinetic information when placed after movement
if (wasMoved) {
super.read(compound);
super.read(compound, clientPacket);
return;
}
@ -235,14 +236,9 @@ public abstract class KineticTileEntity extends SmartTileEntity
overStressed = capacity < stress && StressImpact.isEnabled();
}
super.read(compound);
}
super.read(compound, clientPacket);
@Override
public void readClientUpdate(CompoundNBT tag) {
boolean overStressedBefore = overStressed;
super.readClientUpdate(tag);
if (overStressedBefore != overStressed && speed != 0)
if (clientPacket && overStressedBefore != overStressed && speed != 0)
effects.triggerOverStressedEffect();
}
@ -450,7 +446,7 @@ public abstract class KineticTileEntity extends SmartTileEntity
public int getFlickerScore() {
return flickerTally;
}
public static float convertToDirection(float axisSpeed, Direction d) {
return d.getAxisDirection() == AxisDirection.POSITIVE ? axisSpeed : -axisSpeed;
}

View file

@ -58,21 +58,21 @@ public abstract class BlockBreakingKineticTileEntity extends KineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putInt("Progress", destroyProgress);
compound.putInt("NextTick", ticksUntilNextProgress);
if (breakingPos != null)
compound.put("Breaking", NBTUtil.writeBlockPos(breakingPos));
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
destroyProgress = compound.getInt("Progress");
ticksUntilNextProgress = compound.getInt("NextTick");
if (compound.contains("Breaking"))
breakingPos = NBTUtil.readBlockPos(compound.getCompound("Breaking"));
super.read(compound);
super.read(compound, clientPacket);
}
@Override

View file

@ -3,7 +3,6 @@ package com.simibubi.create.content.contraptions.components.actors;
import java.util.UUID;
import com.mojang.authlib.GameProfile;
import com.simibubi.create.content.contraptions.components.structureMovement.MovementBehaviour;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.common.util.FakePlayer;

View file

@ -39,23 +39,23 @@ public class CuckooClockTileEntity extends KineticTileEntity {
super(type);
animationType = Animation.NONE;
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
if (sendAnimationUpdate)
NBTHelper.writeEnum(compound, "Animation", animationType);
sendAnimationUpdate = false;
return super.writeToClient(compound);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
if (tag.contains("Animation")) {
animationType = NBTHelper.readEnum(tag, "Animation", Animation.class);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (clientPacket && compound.contains("Animation")) {
animationType = NBTHelper.readEnum(compound, "Animation", Animation.class);
animationProgress.lastValue = 0;
animationProgress.value = 0;
}
super.readClientUpdate(tag);
}
@Override
public void write(CompoundNBT compound, boolean clientPacket) {
if (clientPacket && sendAnimationUpdate)
NBTHelper.writeEnum(compound, "Animation", animationType);
sendAnimationUpdate = false;
super.write(compound, clientPacket);
}
@Override

View file

@ -123,7 +123,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.put("Inventory", inventory.serializeNBT());
CompoundNBT inputNBT = new CompoundNBT();
@ -138,43 +138,19 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
compound.putInt("CountDown", countDown);
compound.putBoolean("Cover", covered);
return super.write(compound);
}
@Override
public CompoundNBT writeToClient(CompoundNBT tag) {
if (reRender) {
tag.putBoolean("Redraw", true);
super.write(compound, clientPacket);
if (clientPacket && reRender) {
compound.putBoolean("Redraw", true);
reRender = false;
}
return super.writeToClient(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
if (tag.contains("Redraw"))
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
protected void read(CompoundNBT compound, boolean clientPacket) {
Phase phaseBefore = phase;
GroupedItems before = this.groupedItems;
super.readClientUpdate(tag);
if (phaseBefore != phase && phase == Phase.CRAFTING)
groupedItemsBeforeCraft = before;
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75)
.add(VecHelper.getCenterOf(pos));
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
}
}
@Override
public void read(CompoundNBT compound) {
inventory.deserializeNBT(compound.getCompound("Inventory"));
input.read(compound.getCompound("ConnectedInput"));
groupedItems = GroupedItems.read(compound.getCompound("GroupedItems"));
@ -186,7 +162,22 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
this.phase = phase;
countDown = compound.getInt("CountDown");
covered = compound.getBoolean("Cover");
super.read(compound);
super.read(compound, clientPacket);
if (!clientPacket)
return;
if (compound.contains("Redraw"))
world.notifyBlockUpdate(getPos(), getBlockState(), getBlockState(), 16);
if (phaseBefore != phase && phase == Phase.CRAFTING)
groupedItemsBeforeCraft = before;
if (phaseBefore == Phase.EXPORTING && phase == Phase.WAITING) {
Direction facing = getBlockState().get(MechanicalCrafterBlock.HORIZONTAL_FACING);
Vec3d vec = new Vec3d(facing.getDirectionVec()).scale(.75)
.add(VecHelper.getCenterOf(pos));
Direction targetDirection = MechanicalCrafterBlock.getTargetDirection(getBlockState());
vec = vec.add(new Vec3d(targetDirection.getDirectionVec()).scale(1));
world.addParticle(ParticleTypes.CRIT, vec.x, vec.y, vec.z, 0, 0, 0);
}
}
@Override
@ -293,7 +284,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
Vec3d vec = facingVec.scale(.65)
.add(VecHelper.getCenterOf(pos));
Vec3d offset = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(VecHelper.planeByNormal(facingVec))
.mul(VecHelper.axisAlingedPlaneOf(facingVec))
.normalize()
.scale(progress * .5f)
.add(vec);
@ -307,7 +298,7 @@ public class MechanicalCrafterTileEntity extends KineticTileEntity {
for (int i = 0; i < 10; i++) {
Vec3d randVec = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(VecHelper.planeByNormal(facingVec))
.mul(VecHelper.axisAlingedPlaneOf(facingVec))
.normalize()
.scale(.25f);
Vec3d offset2 = randVec.add(vec);

View file

@ -38,15 +38,15 @@ public class HandCrankTileEntity extends GeneratingKineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putInt("InUse", inUse);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
inUse = compound.getInt("InUse");
super.read(compound);
super.read(compound, clientPacket);
}
@Override

View file

@ -215,19 +215,17 @@ public class CrushingWheelControllerTileEntity extends SmartTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
if (hasEntity())
compound.put("Entity", NBTUtil.writeUniqueId(entityUUID));
compound.put("Inventory", inventory.serializeNBT());
compound.putFloat("Speed", crushingspeed);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
super.read(compound);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (compound.contains("Entity") && !isFrozen() && !isOccupied()) {
entityUUID = NBTUtil.readUniqueId(compound.getCompound("Entity"));
this.searchForEntity = true;

View file

@ -51,11 +51,10 @@ import net.minecraftforge.items.ItemHandlerHelper;
public class DeployerTileEntity extends KineticTileEntity {
private static final List<Pair<BlockPos, Direction>> EXTRACTING_LOCATIONS = Arrays
.asList(Direction.values())
.stream()
.map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite()))
.collect(Collectors.toList());
private static final List<Pair<BlockPos, Direction>> EXTRACTING_LOCATIONS = Arrays.asList(Direction.values())
.stream()
.map(d -> Pair.of(BlockPos.ZERO.offset(d), d.getOpposite()))
.collect(Collectors.toList());
private FilteringBehaviour filtering;
private ExtractingBehaviour extracting;
@ -167,7 +166,8 @@ public class DeployerTileEntity extends KineticTileEntity {
return;
}
if (filtering.getFilter().isEmpty() && stack.isEmpty())
if (filtering.getFilter()
.isEmpty() && stack.isEmpty())
extracting.extract(1);
Direction facing = getBlockState().get(FACING);
@ -182,12 +182,16 @@ public class DeployerTileEntity extends KineticTileEntity {
state = State.EXPANDING;
Vec3d movementVector = getMovementVector();
Vec3d rayOrigin = VecHelper.getCenterOf(pos).add(movementVector.scale(3 / 2f));
Vec3d rayTarget = VecHelper.getCenterOf(pos).add(movementVector.scale(5 / 2f));
Vec3d rayOrigin = VecHelper.getCenterOf(pos)
.add(movementVector.scale(3 / 2f));
Vec3d rayTarget = VecHelper.getCenterOf(pos)
.add(movementVector.scale(5 / 2f));
RayTraceContext rayTraceContext =
new RayTraceContext(rayOrigin, rayTarget, BlockMode.OUTLINE, FluidMode.NONE, player);
BlockRayTraceResult result = world.rayTraceBlocks(rayTraceContext);
reach = (float) (.5f + Math.min(result.getHitVec().subtract(rayOrigin).length(), .75f));
reach = (float) (.5f + Math.min(result.getHitVec()
.subtract(rayOrigin)
.length(), .75f));
timer = 1000;
sendData();
@ -226,7 +230,9 @@ public class DeployerTileEntity extends KineticTileEntity {
if (!(otherTile instanceof DeployerTileEntity))
return false;
DeployerTileEntity deployerTile = (DeployerTileEntity) otherTile;
if (world.getBlockState(otherDeployer).get(FACING).getOpposite() != facing || deployerTile.mode != Mode.PUNCH)
if (world.getBlockState(otherDeployer)
.get(FACING)
.getOpposite() != facing || deployerTile.mode != Mode.PUNCH)
return false;
boop = true;
@ -295,13 +301,15 @@ public class DeployerTileEntity extends KineticTileEntity {
}
protected void tryDisposeOfItems() {
boolean noInv = extracting.getInventories().isEmpty();
boolean noInv = extracting.getInventories()
.isEmpty();
for (Iterator<ItemStack> iterator = overflowItems.iterator(); iterator.hasNext();) {
ItemStack itemStack = iterator.next();
if (noInv) {
Vec3d offset = getMovementVector();
Vec3d outPos = VecHelper.getCenterOf(pos).add(offset.scale(-.65f));
Vec3d outPos = VecHelper.getCenterOf(pos)
.add(offset.scale(-.65f));
Vec3d motion = offset.scale(-.25f);
ItemEntity e = new ItemEntity(world, outPos.x, outPos.y, outPos.z, itemStack.copy());
e.setMotion(motion);
@ -328,11 +336,12 @@ public class DeployerTileEntity extends KineticTileEntity {
protected Vec3d getMovementVector() {
if (!AllBlocks.DEPLOYER.has(getBlockState()))
return Vec3d.ZERO;
return new Vec3d(getBlockState().get(FACING).getDirectionVec());
return new Vec3d(getBlockState().get(FACING)
.getDirectionVec());
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
state = NBTHelper.readEnum(compound, "State", State.class);
mode = NBTHelper.readEnum(compound, "Mode", Mode.class);
timer = compound.getInt("Timer");
@ -340,48 +349,45 @@ public class DeployerTileEntity extends KineticTileEntity {
overflowItems = NBTHelper.readItemList(compound.getList("Overflow", NBT.TAG_COMPOUND));
if (compound.contains("HeldItem"))
heldItem = ItemStack.read(compound.getCompound("HeldItem"));
super.read(compound);
super.read(compound, clientPacket);
if (!clientPacket)
return;
reach = compound.getFloat("Reach");
if (compound.contains("Particle")) {
ItemStack particleStack = ItemStack.read(compound.getCompound("Particle"));
SandPaperItem.spawnParticles(VecHelper.getCenterOf(pos)
.add(getMovementVector().scale(2f)), particleStack, this.world);
}
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
NBTHelper.writeEnum(compound, "Mode", mode);
NBTHelper.writeEnum(compound, "State", state);
compound.putInt("Timer", timer);
if (player != null) {
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
compound.put("HeldItem", player.getHeldItemMainhand()
.serializeNBT());
ListNBT invNBT = new ListNBT();
player.inventory.write(invNBT);
compound.put("Inventory", invNBT);
compound.put("Overflow", NBTHelper.writeItemList(overflowItems));
}
return super.write(compound);
}
super.write(compound, clientPacket);
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
if (!clientPacket)
return;
compound.putFloat("Reach", reach);
if (player != null) {
compound.put("HeldItem", player.getHeldItemMainhand().serializeNBT());
if (player.spawnedItemEffects != null) {
compound.put("Particle", player.spawnedItemEffects.serializeNBT());
player.spawnedItemEffects = null;
}
if (player == null)
return;
compound.put("HeldItem", player.getHeldItemMainhand()
.serializeNBT());
if (player.spawnedItemEffects != null) {
compound.put("Particle", player.spawnedItemEffects.serializeNBT());
player.spawnedItemEffects = null;
}
return super.writeToClient(compound);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
reach = tag.getFloat("Reach");
if (tag.contains("Particle")) {
ItemStack particleStack = ItemStack.read(tag.getCompound("Particle"));
SandPaperItem
.spawnParticles(VecHelper.getCenterOf(pos).add(getMovementVector().scale(2f)), particleStack,
this.world);
}
super.readClientUpdate(tag);
}
private IItemHandlerModifiable createHandler() {
@ -395,7 +401,7 @@ public class DeployerTileEntity extends KineticTileEntity {
public AllBlockPartials getHandPose() {
return mode == Mode.PUNCH ? AllBlockPartials.DEPLOYER_HAND_PUNCHING
: heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING;
: heldItem.isEmpty() ? AllBlockPartials.DEPLOYER_HAND_POINTING : AllBlockPartials.DEPLOYER_HAND_HOLDING;
}
@Override

View file

@ -165,7 +165,7 @@ public class AirCurrent {
.get(BlockStateProperties.FACING);
pushing = source.getAirFlowDirection() == direction;
Vec3d directionVec = new Vec3d(direction.getDirectionVec());
Vec3d planeVec = VecHelper.planeByNormal(directionVec);
Vec3d planeVec = VecHelper.axisAlingedPlaneOf(directionVec);
// 4 Rays test for holes in the shapes blocking the flow
float offsetDistance = .25f;

View file

@ -6,6 +6,7 @@ import com.simibubi.create.content.contraptions.processing.burner.BlazeBurnerBlo
import com.simibubi.create.content.logistics.block.chute.ChuteTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.config.CKinetics;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
@ -30,21 +31,17 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
}
@Override
public void readClientUpdate(CompoundNBT tag) {
super.readClientUpdate(tag);
airCurrent.rebuild();
}
@Override
public void read(CompoundNBT compound) {
super.read(compound);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
isGenerator = compound.getBoolean("Generating");
if (clientPacket)
airCurrent.rebuild();
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Generating", isGenerator);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
@ -77,10 +74,12 @@ public class EncasedFanTileEntity extends GeneratingKineticTileEntity {
return false;
BlockState checkState = world.getBlockState(pos.down());
if (!checkState.getBlock().isIn(AllBlockTags.FAN_HEATERS.tag))
if (!checkState.getBlock()
.isIn(AllBlockTags.FAN_HEATERS.tag))
return false;
if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL).isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
if (checkState.has(BlazeBurnerBlock.HEAT_LEVEL) && !checkState.get(BlazeBurnerBlock.HEAT_LEVEL)
.isAtLeast(BlazeBurnerBlock.HeatLevel.FADING))
return false;
if (checkState.has(BlockStateProperties.LIT) && !checkState.get(BlockStateProperties.LIT))

View file

@ -38,26 +38,30 @@ public class NozzleTileEntity extends SmartTileEntity {
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
}
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
protected void write(CompoundNBT compound, boolean clientPacket) {
super.write(compound, clientPacket);
if (!clientPacket)
return;
compound.putFloat("Range", range);
compound.putBoolean("Pushing", pushing);
return super.writeToClient(compound);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
range = tag.getFloat("Range");
pushing = tag.getBoolean("Pushing");
super.readClientUpdate(tag);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (!clientPacket)
return;
range = compound.getFloat("Range");
pushing = compound.getBoolean("Pushing");
}
@Override
public void initialize() {
fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING).getOpposite());
fanPos = pos.offset(getBlockState().get(NozzleBlock.FACING)
.getOpposite());
super.initialize();
}
@ -72,24 +76,26 @@ public class NozzleTileEntity extends SmartTileEntity {
Vec3d center = VecHelper.getCenterOf(pos);
if (world.isRemote && range != 0) {
if (world.rand.nextInt(
MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) {
MathHelper.clamp((AllConfigs.SERVER.kinetics.fanPushDistance.get() - (int) range), 1, 10)) == 0) {
Vec3d start = VecHelper.offsetRandomly(center, world.rand, pushing ? 1 : range / 2);
Vec3d motion = center.subtract(start).normalize()
.scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1));
Vec3d motion = center.subtract(start)
.normalize()
.scale(MathHelper.clamp(range * (pushing ? .025f : 1f), 0, .5f) * (pushing ? -1 : 1));
world.addParticle(ParticleTypes.POOF, start.x, start.y, start.z, motion.x, motion.y, motion.z);
}
}
for (Iterator<Entity> iterator = pushingEntities.iterator(); iterator.hasNext();) {
Entity entity = iterator.next();
Vec3d diff = entity.getPositionVec().subtract(center);
Vec3d diff = entity.getPositionVec()
.subtract(center);
if (!(entity instanceof PlayerEntity) && world.isRemote)
continue;
double distance = diff.length();
if (distance > range || entity.isSneaking()
|| (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) {
|| (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) {
iterator.remove();
continue;
}
@ -98,8 +104,10 @@ public class NozzleTileEntity extends SmartTileEntity {
continue;
float factor = (entity instanceof ItemEntity) ? 1 / 128f : 1 / 32f;
Vec3d pushVec = diff.normalize().scale((range - distance) * (pushing ? 1 : -1));
entity.setMotion(entity.getMotion().add(pushVec.scale(factor)));
Vec3d pushVec = diff.normalize()
.scale((range - distance) * (pushing ? 1 : -1));
entity.setMotion(entity.getMotion()
.add(pushVec.scale(factor)));
entity.fallDistance = 0;
entity.velocityChanged = true;
}
@ -125,7 +133,8 @@ public class NozzleTileEntity extends SmartTileEntity {
return 0;
if (fan.getSpeed() == 0)
return 0;
pushing = fan.getAirFlowDirection() == fan.getBlockState().get(EncasedFanBlock.FACING);
pushing = fan.getAirFlowDirection() == fan.getBlockState()
.get(EncasedFanBlock.FACING);
return fan.getMaxDistance();
}
@ -140,11 +149,12 @@ public class NozzleTileEntity extends SmartTileEntity {
AxisAlignedBB bb = new AxisAlignedBB(center, center).grow(range / 2f);
for (Entity entity : world.getEntitiesWithinAABB(Entity.class, bb)) {
Vec3d diff = entity.getPositionVec().subtract(center);
Vec3d diff = entity.getPositionVec()
.subtract(center);
double distance = diff.length();
if (distance > range || entity.isSneaking()
|| (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) {
|| (entity instanceof PlayerEntity && ((PlayerEntity) entity).isCreative())) {
continue;
}
@ -164,7 +174,7 @@ public class NozzleTileEntity extends SmartTileEntity {
continue;
iterator.remove();
}
if (!pushing && pushingEntities.size() > 256 && !world.isRemote) {
world.createExplosion(null, center.x, center.y, center.z, 2, Mode.NONE);
for (Iterator<Entity> iterator = pushingEntities.iterator(); iterator.hasNext();) {
@ -178,8 +188,9 @@ public class NozzleTileEntity extends SmartTileEntity {
private boolean canSee(Entity entity) {
RayTraceContext context = new RayTraceContext(entity.getPositionVec(), VecHelper.getCenterOf(pos),
BlockMode.COLLIDER, FluidMode.NONE, entity);
return pos.equals(world.rayTraceBlocks(context).getPos());
BlockMode.COLLIDER, FluidMode.NONE, entity);
return pos.equals(world.rayTraceBlocks(context)
.getPos());
}
}

View file

@ -53,30 +53,21 @@ public class FlywheelTileEntity extends GeneratingKineticTileEntity {
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
return super.writeToClient(compound);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
super.readClientUpdate(tag);
visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed());
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putFloat("GeneratedSpeed", generatedSpeed);
compound.putFloat("GeneratedCapacity", generatedCapacity);
compound.putInt("Cooldown", stoppingCooldown);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
generatedSpeed = compound.getFloat("GeneratedSpeed");
generatedCapacity = compound.getFloat("GeneratedCapacity");
stoppingCooldown = compound.getInt("Cooldown");
super.read(compound);
super.read(compound, clientPacket);
if (clientPacket)
visualSpeed.withSpeed(1 / 32f).target(getGeneratedSpeed());
}
@Override

View file

@ -116,19 +116,19 @@ public class MillstoneTileEntity extends KineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putInt("Timer", timer);
compound.put("InputInventory", inputInv.serializeNBT());
compound.put("OutputInventory", outputInv.serializeNBT());
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
timer = compound.getInt("Timer");
inputInv.deserializeNBT(compound.getCompound("InputInventory"));
outputInv.deserializeNBT(compound.getCompound("OutputInventory"));
super.read(compound);
super.read(compound, clientPacket);
}
public int getProcessingSpeed() {

View file

@ -109,17 +109,17 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
running = compound.getBoolean("Running");
runningTicks = compound.getInt("Ticks");
super.read(compound);
super.read(compound, clientPacket);
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Running", running);
compound.putInt("Ticks", runningTicks);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override

View file

@ -15,6 +15,7 @@ import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.item.ItemHelper;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.entity.Entity;
@ -25,7 +26,6 @@ import net.minecraft.item.crafting.ICraftingRecipe;
import net.minecraft.item.crafting.IRecipe;
import net.minecraft.item.crafting.Ingredient;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.particles.ItemParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.tileentity.TileEntityType;
@ -85,37 +85,30 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
}
@Override
public void read(CompoundNBT compound) {
protected void read(CompoundNBT compound, boolean clientPacket) {
running = compound.getBoolean("Running");
mode = Mode.values()[compound.getInt("Mode")];
finished = compound.getBoolean("Finished");
runningTicks = compound.getInt("Ticks");
super.read(compound);
super.read(compound, clientPacket);
if (clientPacket) {
NBTHelper.iterateCompoundList(compound.getList("ParticleItems", NBT.TAG_COMPOUND),
c -> pressedItems.add(ItemStack.read(c)));
spawnParticles();
}
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Running", running);
compound.putInt("Mode", mode.ordinal());
compound.putBoolean("Finished", finished);
compound.putInt("Ticks", runningTicks);
return super.write(compound);
}
super.write(compound, clientPacket);
@Override
public CompoundNBT writeToClient(CompoundNBT tag) {
ListNBT particleItems = new ListNBT();
pressedItems.forEach(stack -> particleItems.add(stack.serializeNBT()));
tag.put("ParticleItems", particleItems);
return super.writeToClient(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
super.readClientUpdate(tag);
ListNBT particleItems = tag.getList("ParticleItems", NBT.TAG_COMPOUND);
particleItems.forEach(nbt -> pressedItems.add(ItemStack.read((CompoundNBT) nbt)));
spawnParticles();
if (clientPacket)
compound.put("ParticleItems", NBTHelper.writeCompoundList(pressedItems, ItemStack::serializeNBT));
}
@Override
@ -301,7 +294,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
CombinedItemFluidList remaining = new CombinedItemFluidList();
inputs.forEachItemStack(stack -> remaining.add(stack.copy()));
basinFluidInv.ifPresent(fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy())));
basinFluidInv.ifPresent(
fluidInv -> ((CombinedFluidHandler) fluidInv).forEachTank(fluidStack -> remaining.add(fluidStack.copy())));
Ingredients: for (Ingredient ingredient : ingredients) {
for (ItemStack stack : remaining.getItemStacks()) {

View file

@ -94,15 +94,15 @@ public class SawTileEntity extends BlockBreakingKineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
compound.put("Inventory", inventory.serializeNBT());
compound.putInt("RecipeIndex", recipeIndex);
return super.write(compound);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT compound) {
super.read(compound);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
inventory.deserializeNBT(compound.getCompound("Inventory"));
recipeIndex = compound.getInt("RecipeIndex");
}

View file

@ -465,7 +465,7 @@ public abstract class Contraption {
renderOrder.add(0, info.pos);
CompoundNBT tag = info.nbt;
MovementBehaviour movementBehaviour = AllMovementBehaviours.getMovementBehaviour(block);
if (tag == null || movementBehaviour == null || movementBehaviour.hasSpecialMovementRenderer())
if (tag == null || (movementBehaviour != null && movementBehaviour.hasSpecialMovementRenderer()))
return;
tag.putInt("x", info.pos.getX());
@ -797,7 +797,7 @@ public abstract class Contraption {
Vec3d vec = new Vec3d(Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis)
.getDirectionVec());
Vec3d planeByNormal = VecHelper.planeByNormal(vec);
Vec3d planeByNormal = VecHelper.axisAlingedPlaneOf(vec);
Vec3d min = vec.mul(bb.minX, bb.minY, bb.minZ)
.add(planeByNormal.scale(-maxDiff));
Vec3d max = vec.mul(bb.maxX, bb.maxY, bb.maxZ)

View file

@ -476,7 +476,7 @@ public class ContraptionEntity extends Entity implements IEntityAdditionalSpawnD
BearingContraption bc = (BearingContraption) getContraption();
Direction facing = bc.getFacing();
Vec3d activeAreaOffset = actor.getActiveAreaOffset(context);
if (activeAreaOffset.mul(VecHelper.planeByNormal(new Vec3d(facing.getDirectionVec())))
if (activeAreaOffset.mul(VecHelper.axisAlingedPlaneOf(new Vec3d(facing.getDirectionVec())))
.equals(Vec3d.ZERO)) {
if (VecHelper.onSameAxis(blockInfo.pos, BlockPos.ZERO, facing.getAxis())) {
context.motion = new Vec3d(facing.getDirectionVec()).scale(facing.getAxis()

View file

@ -1,7 +1,6 @@
package com.simibubi.create.content.contraptions.components.structureMovement;
import org.apache.commons.lang3.mutable.MutableObject;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionEntity;
import com.simibubi.create.content.contraptions.components.structureMovement.sync.ContraptionInteractionPacket;
import com.simibubi.create.foundation.networking.AllPackets;
import com.simibubi.create.foundation.utility.RaycastHelper;

View file

@ -227,26 +227,26 @@ public class ClockworkBearingTileEntity extends KineticTileEntity implements IBe
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putFloat("HourAngle", hourAngle);
tag.putFloat("MinuteAngle", minuteAngle);
return super.write(tag);
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Running", running);
compound.putFloat("HourAngle", hourAngle);
compound.putFloat("MinuteAngle", minuteAngle);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
hourAngle = tag.getFloat("HourAngle");
minuteAngle = tag.getFloat("MinuteAngle");
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
protected void read(CompoundNBT compound, boolean clientPacket) {
float hourAngleBefore = hourAngle;
float minuteAngleBefore = minuteAngle;
super.readClientUpdate(tag);
running = compound.getBoolean("Running");
hourAngle = compound.getFloat("HourAngle");
minuteAngle = compound.getFloat("MinuteAngle");
super.read(compound, clientPacket);
if (!clientPacket)
return;
if (running) {
clientHourAngleDiff = AngleHelper.getShortestAngleDiff(hourAngleBefore, hourAngle);
clientMinuteAngleDiff = AngleHelper.getShortestAngleDiff(minuteAngleBefore, minuteAngle);

View file

@ -102,27 +102,25 @@ public class MechanicalBearingTileEntity extends GeneratingKineticTileEntity imp
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putBoolean("Windmill", isWindmill);
tag.putFloat("Angle", angle);
tag.putFloat("LastGenerated", lastGeneratedSpeed);
return super.write(tag);
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Running", running);
compound.putBoolean("Windmill", isWindmill);
compound.putFloat("Angle", angle);
compound.putFloat("LastGenerated", lastGeneratedSpeed);
super.write(compound, clientPacket);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
isWindmill = tag.getBoolean("Windmill");
angle = tag.getFloat("Angle");
lastGeneratedSpeed = tag.getFloat("LastGenerated");
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
protected void read(CompoundNBT compound, boolean clientPacket) {
float angleBefore = angle;
super.readClientUpdate(tag);
running = compound.getBoolean("Running");
isWindmill = compound.getBoolean("Windmill");
angle = compound.getFloat("Angle");
lastGeneratedSpeed = compound.getFloat("LastGenerated");
super.read(compound, clientPacket);
if (!clientPacket)
return;
if (running) {
clientAngleDiff = AngleHelper.getShortestAngleDiff(angleBefore, angle);
angle = angleBefore;

View file

@ -81,7 +81,7 @@ public class SuperGlueItem extends Item {
@OnlyIn(Dist.CLIENT)
public static void spawnParticles(World world, BlockPos pos, Direction direction, boolean fullBlock) {
Vec3d vec = new Vec3d(direction.getDirectionVec());
Vec3d plane = VecHelper.planeByNormal(vec);
Vec3d plane = VecHelper.axisAlingedPlaneOf(vec);
Vec3d facePos = VecHelper.getCenterOf(pos)
.add(vec.scale(.5f));

View file

@ -6,6 +6,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder;
import com.simibubi.create.AllItems;
import com.simibubi.create.Create;
import com.simibubi.create.foundation.utility.AngleHelper;
import com.simibubi.create.foundation.utility.MatrixStacker;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
@ -63,7 +64,9 @@ public class SuperGlueRenderer extends EntityRenderer<SuperGlueEntity> {
Direction face = entity.getFacingDirection();
ms.push();
AngleHelper.applyRotation(face, ms);
MatrixStacker.of(ms)
.rotateY(AngleHelper.horizontalAngle(face))
.rotateX(AngleHelper.verticalAngle(face));
Entry peek = ms.peek();
Vec3d[][] quads = { quad1, quad2 };
@ -87,7 +90,7 @@ public class SuperGlueRenderer extends EntityRenderer<SuperGlueEntity> {
Vec3d diff = new Vec3d(Direction.SOUTH.getDirectionVec());
Vec3d extension = diff.normalize()
.scale(1 / 32f - 1 / 128f);
Vec3d plane = VecHelper.planeByNormal(diff);
Vec3d plane = VecHelper.axisAlingedPlaneOf(diff);
Axis axis = Direction.getFacingFromVector(diff.x, diff.y, diff.z)
.getAxis();

View file

@ -145,50 +145,38 @@ public abstract class LinearActuatorTileEntity extends KineticTileEntity impleme
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putBoolean("Running", running);
tag.putBoolean("Waiting", waitingForSpeedChange);
tag.putFloat("Offset", offset);
return super.write(tag);
}
@Override
public CompoundNBT writeToClient(CompoundNBT compound) {
if (forceMove) {
protected void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Running", running);
compound.putBoolean("Waiting", waitingForSpeedChange);
compound.putFloat("Offset", offset);
super.write(compound, clientPacket);
if (clientPacket && forceMove) {
compound.putBoolean("ForceMovement", forceMove);
forceMove = false;
}
return super.writeToClient(compound);
}
@Override
public void read(CompoundNBT tag) {
running = tag.getBoolean("Running");
waitingForSpeedChange = tag.getBoolean("Waiting");
offset = tag.getFloat("Offset");
super.read(tag);
}
@Override
public void readClientUpdate(CompoundNBT tag) {
boolean forceMovement = tag.contains("ForceMovement");
protected void read(CompoundNBT compound, boolean clientPacket) {
boolean forceMovement = compound.contains("ForceMovement");
float offsetBefore = offset;
super.readClientUpdate(tag);
if (forceMovement) {
if (movedContraption != null) {
applyContraptionPosition();
}
} else {
if (running) {
clientOffsetDiff = offset - offsetBefore;
offset = offsetBefore;
}
running = compound.getBoolean("Running");
waitingForSpeedChange = compound.getBoolean("Waiting");
offset = compound.getFloat("Offset");
super.read(compound, clientPacket);
if (!clientPacket)
return;
if (forceMovement)
applyContraptionPosition();
else if (running) {
clientOffsetDiff = offset - offsetBefore;
offset = offsetBefore;
}
if (!running)
movedContraption = null;
}
public abstract void disassemble();

View file

@ -29,15 +29,15 @@ public class MechanicalPistonTileEntity extends LinearActuatorTileEntity {
}
@Override
public void read(CompoundNBT tag) {
extensionLength = tag.getInt("ExtensionLength");
super.read(tag);
protected void read(CompoundNBT compound, boolean clientPacket) {
extensionLength = compound.getInt("ExtensionLength");
super.read(compound, clientPacket);
}
@Override
public CompoundNBT write(CompoundNBT tag) {
protected void write(CompoundNBT tag, boolean clientPacket) {
tag.putInt("ExtensionLength", extensionLength);
return super.write(tag);
super.write(tag, clientPacket);
}
@Override

View file

@ -8,6 +8,7 @@ import com.simibubi.create.content.contraptions.components.structureMovement.pis
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.behaviour.CenteredSideValueBoxTransform;
import com.simibubi.create.foundation.tileEntity.behaviour.ValueBoxTransform;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.IWaterLoggable;
@ -168,15 +169,15 @@ public class PulleyTileEntity extends LinearActuatorTileEntity {
}
@Override
public void read(CompoundNBT tag) {
initialOffset = tag.getInt("InitialOffset");
super.read(tag);
protected void read(CompoundNBT compound, boolean clientPacket) {
initialOffset = compound.getInt("InitialOffset");
super.read(compound, clientPacket);
}
@Override
public CompoundNBT write(CompoundNBT tag) {
tag.putInt("InitialOffset", initialOffset);
return super.write(tag);
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putInt("InitialOffset", initialOffset);
super.write(compound, clientPacket);
}
@Override

View file

@ -24,8 +24,8 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
}
@Override
public void read(CompoundNBT compound) {
super.read(compound);
protected void read(CompoundNBT compound, boolean clientPacket) {
super.read(compound, clientPacket);
if (compound.contains("Flows")) {
for (Direction d : Direction.values())
setFlow(d, compound.getCompound("Flows")
@ -39,13 +39,13 @@ public class WaterWheelTileEntity extends GeneratingKineticTileEntity {
}
@Override
public CompoundNBT write(CompoundNBT compound) {
public void write(CompoundNBT compound, boolean clientPacket) {
CompoundNBT flows = new CompoundNBT();
for (Direction d : Direction.values())
flows.putFloat(d.getName(), this.flows.get(d));
compound.put("Flows", flows);
return super.write(compound);
super.write(compound, clientPacket);
}
public void setFlow(Direction direction, float speed) {

View file

@ -87,17 +87,20 @@ public class CombinedFluidHandler implements IFluidHandler {
@Nonnull
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
FluidStack stack = new FluidStack(tanks[0].getFluid(), 0);
for (int i = 0; i < tanks.length; i++) {
if (tanks[i].isFluidEqual(stack)) {
if (stack.isEmpty() || tanks[i].isFluidEqual(stack)) {
int newDrainAmount = MathHelper.clamp(stack.getAmount() + tanks[i].getAmount(), 0, maxDrain);
if (action == FluidAction.EXECUTE) {
tanks[i].shrink(newDrainAmount - stack.getAmount());
if (tanks[i].isEmpty())
tanks[i] = FluidStack.EMPTY;
}
if (stack.isEmpty())
stack = tanks[i].copy();
if (stack.isEmpty())
continue;
stack.setAmount(newDrainAmount);
}
}

View file

@ -0,0 +1,355 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
public class FluidNetwork {
BlockFace pumpLocation;
Map<BlockPos, Pair<Integer, Map<Direction, Boolean>>> pipeGraph;
List<FluidNetworkFlow> flows;
Set<FluidNetworkEndpoint> targets;
Set<BlockFace> rangeEndpoints;
Map<BlockFace, FluidStack> previousFlow;
boolean connectToPumps;
int waitForUnloadedNetwork;
public FluidNetwork() {
pipeGraph = new HashMap<>();
flows = new ArrayList<>();
targets = new HashSet<>();
rangeEndpoints = new HashSet<>();
previousFlow = new HashMap<>();
}
public boolean hasEndpoints() {
for (FluidNetworkFlow pipeFlow : flows)
if (pipeFlow.hasValidTargets())
return true;
return false;
}
public Collection<FluidNetworkEndpoint> getEndpoints(boolean pulling) {
if (!pulling) {
for (FluidNetworkFlow pipeFlow : flows)
return pipeFlow.outputEndpoints;
return Collections.emptySet();
}
List<FluidNetworkEndpoint> list = new ArrayList<>();
for (FluidNetworkFlow pipeFlow : flows) {
if (!pipeFlow.hasValidTargets())
continue;
list.add(pipeFlow.source);
}
return list;
}
public void tick(IWorld world, PumpTileEntity pumpTE) {
if (connectToPumps) {
connectToOtherFNs(world, pumpTE);
connectToPumps = false;
}
}
public void tickFlows(IWorld world, PumpTileEntity pumpTE, boolean pulling, float speed) {
if (connectToPumps)
return;
initFlows(pumpTE, pulling);
previousFlow.clear();
flows.forEach(ep -> ep.tick(world, speed));
}
private void initFlows(PumpTileEntity pumpTE, boolean pulling) {
if (targets.isEmpty())
return;
if (!flows.isEmpty())
return;
World world = pumpTE.getWorld();
if (pulling) {
targets.forEach(ne -> flows.add(new FluidNetworkFlow(this, ne, world, pulling)));
} else {
PumpEndpoint pumpEndpoint = new PumpEndpoint(pumpLocation.getOpposite(), pumpTE);
flows.add(new FluidNetworkFlow(this, pumpEndpoint, world, pulling));
}
}
public void connectToOtherFNs(IWorld world, PumpTileEntity pump) {
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
int maxDistance = FluidPropagator.getPumpRange() * 2;
frontier.add(Pair.of(-1, pumpLocation.getPos()));
while (!frontier.isEmpty()) {
Pair<Integer, BlockPos> entry = frontier.remove(0);
int distance = entry.getFirst();
BlockPos currentPos = entry.getSecond();
if (!world.isAreaLoaded(currentPos, 0))
continue;
if (visited.contains(currentPos))
continue;
visited.add(currentPos);
List<Direction> connections;
if (currentPos.equals(pumpLocation.getPos())) {
connections = ImmutableList.of(pumpLocation.getFace());
} else {
BlockState currentState = world.getBlockState(currentPos);
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
if (pipe == null)
continue;
connections = FluidPropagator.getPipeConnections(currentState, pipe);
}
for (Direction face : connections) {
BlockFace blockFace = new BlockFace(currentPos, face);
BlockPos connectedPos = blockFace.getConnectedPos();
BlockState connectedState = world.getBlockState(connectedPos);
if (connectedPos.equals(pumpLocation.getPos()))
continue;
if (!world.isAreaLoaded(connectedPos, 0))
continue;
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
.getAxis() == face.getAxis()) {
TileEntity tileEntity = world.getTileEntity(connectedPos);
if (tileEntity instanceof PumpTileEntity) {
PumpTileEntity otherPump = (PumpTileEntity) tileEntity;
if (otherPump.networks == null)
continue;
otherPump.networks.forEach(fn -> {
int nearest = Integer.MAX_VALUE;
BlockFace argNearest = null;
for (BlockFace pumpEndpoint : fn.rangeEndpoints) {
if (pumpEndpoint.isEquivalent(pumpLocation)) {
argNearest = pumpEndpoint;
break;
}
Pair<Integer, Map<Direction, Boolean>> pair =
pipeGraph.get(pumpEndpoint.getConnectedPos());
if (pair == null)
continue;
Integer distanceFromPump = pair.getFirst();
Map<Direction, Boolean> pipeConnections = pair.getSecond();
if (!pipeConnections.containsKey(pumpEndpoint.getOppositeFace()))
continue;
if (nearest <= distanceFromPump)
continue;
nearest = distanceFromPump;
argNearest = pumpEndpoint;
}
if (argNearest != null) {
InterPumpEndpoint endpoint = new InterPumpEndpoint(world, argNearest.getOpposite(),
pump, otherPump, pumpLocation, fn.pumpLocation);
targets.add(endpoint);
fn.targets.add(endpoint.opposite(world));
}
});
}
continue;
}
if (visited.contains(connectedPos))
continue;
if (distance > maxDistance)
continue;
FluidPipeBehaviour targetPipe = FluidPropagator.getPipe(world, connectedPos);
if (targetPipe == null)
continue;
if (targetPipe.isConnectedTo(connectedState, face.getOpposite()))
frontier.add(Pair.of(distance + 1, connectedPos));
}
}
}
public void assemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
Map<BlockFace, OpenEndedPipe> openEnds = pumpTE.getOpenEnds(pumpLocation.getFace());
openEnds.values()
.forEach(OpenEndedPipe::markStale);
this.pumpLocation = pumpLocation;
if (!collectEndpoint(world, pumpLocation, openEnds, 0)) {
List<Pair<Integer, BlockPos>> frontier = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
int maxDistance = FluidPropagator.getPumpRange();
frontier.add(Pair.of(0, pumpLocation.getConnectedPos()));
while (!frontier.isEmpty()) {
Pair<Integer, BlockPos> entry = frontier.remove(0);
int distance = entry.getFirst();
BlockPos currentPos = entry.getSecond();
if (!world.isAreaLoaded(currentPos, 0))
continue;
if (visited.contains(currentPos))
continue;
visited.add(currentPos);
BlockState currentState = world.getBlockState(currentPos);
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, currentPos);
if (pipe == null)
continue;
for (Direction face : FluidPropagator.getPipeConnections(currentState, pipe)) {
BlockFace blockFace = new BlockFace(currentPos, face);
BlockPos connectedPos = blockFace.getConnectedPos();
if (connectedPos.equals(pumpLocation.getPos())) {
addEntry(blockFace.getPos(), blockFace.getFace(), true, distance);
continue;
}
if (!world.isAreaLoaded(connectedPos, 0))
continue;
if (collectEndpoint(world, blockFace, openEnds, distance))
continue;
if (FluidPropagator.getPipe(world, connectedPos) == null)
continue;
if (visited.contains(connectedPos))
continue;
if (distance + 1 >= maxDistance) {
rangeEndpoints.add(blockFace);
addEntry(currentPos, face, false, distance);
FluidPropagator.showBlockFace(blockFace)
.lineWidth(1 / 8f)
.colored(0xff0000);
continue;
}
addConnection(connectedPos, currentPos, face.getOpposite(), distance);
frontier.add(Pair.of(distance + 1, connectedPos));
}
}
}
Set<BlockFace> staleEnds = new HashSet<>();
openEnds.entrySet()
.forEach(e -> {
if (e.getValue()
.isStale())
staleEnds.add(e.getKey());
});
staleEnds.forEach(openEnds::remove);
connectToPumps = true;
}
private FluidNetworkEndpoint reuseOrCreateOpenEnd(IWorld world, Map<BlockFace, OpenEndedPipe> openEnds,
BlockFace toCreate) {
OpenEndedPipe openEndedPipe = null;
if (openEnds.containsKey(toCreate)) {
openEndedPipe = openEnds.get(toCreate);
openEndedPipe.unmarkStale();
} else {
openEndedPipe = new OpenEndedPipe(toCreate);
openEnds.put(toCreate, openEndedPipe);
}
return new FluidNetworkEndpoint(world, toCreate, openEndedPipe.getCapability());
}
private boolean collectEndpoint(IWorld world, BlockFace blockFace, Map<BlockFace, OpenEndedPipe> openEnds,
int distance) {
BlockPos connectedPos = blockFace.getConnectedPos();
BlockState connectedState = world.getBlockState(connectedPos);
// other pipe, no endpoint
FluidPipeBehaviour pipe = FluidPropagator.getPipe(world, connectedPos);
if (pipe != null && pipe.isConnectedTo(connectedState, blockFace.getOppositeFace()))
return false;
TileEntity tileEntity = world.getTileEntity(connectedPos);
// fluid handler endpoint
Direction face = blockFace.getFace();
if (tileEntity != null) {
LazyOptional<IFluidHandler> capability =
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, face.getOpposite());
if (capability.isPresent()) {
targets.add(new FluidNetworkEndpoint(world, blockFace, capability));
addEntry(blockFace.getPos(), face, false, distance);
FluidPropagator.showBlockFace(blockFace)
.colored(0x00b7c2)
.lineWidth(1 / 8f);
return true;
}
}
// open endpoint
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
.getAxis() == face.getAxis()) {
rangeEndpoints.add(blockFace);
addEntry(blockFace.getPos(), face, false, distance);
return true;
}
if (!FluidPropagator.isOpenEnd(world, blockFace.getPos(), face))
return false;
targets.add(reuseOrCreateOpenEnd(world, openEnds, blockFace));
addEntry(blockFace.getPos(), face, false, distance);
FluidPropagator.showBlockFace(blockFace)
.colored(0xb700c2)
.lineWidth(1 / 8f);
return true;
}
private void addConnection(BlockPos from, BlockPos to, Direction direction, int distance) {
addEntry(from, direction, true, distance);
addEntry(to, direction.getOpposite(), false, distance + 1);
}
private void addEntry(BlockPos pos, Direction direction, boolean outbound, int distance) {
if (!pipeGraph.containsKey(pos))
pipeGraph.put(pos, Pair.of(distance, new HashMap<>()));
pipeGraph.get(pos)
.getSecond()
.put(direction, outbound);
}
public void reAssemble(IWorld world, PumpTileEntity pumpTE, BlockFace pumpLocation) {
rangeEndpoints.clear();
targets.clear();
pipeGraph.clear();
assemble(world, pumpTE, pumpLocation);
}
public void remove(IWorld world) {
clearFlows(world, false);
}
public void clearFlows(IWorld world, boolean saveState) {
for (FluidNetworkFlow networkFlow : flows) {
if (!networkFlow.getFluidStack()
.isEmpty())
networkFlow.addToSkippedConnections(world);
networkFlow.resetFlow(world);
}
flows.clear();
}
}

View file

@ -0,0 +1,168 @@
package com.simibubi.create.content.contraptions.fluids;
import java.lang.ref.WeakReference;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.IWorld;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
class FluidNetworkEndpoint {
BlockFace location;
protected LazyOptional<IFluidHandler> handler;
public FluidNetworkEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
this.location = location;
this.handler = handler;
this.handler.addListener($ -> onHandlerInvalidated(world));
}
protected void onHandlerInvalidated(IWorld world) {
IFluidHandler tank = handler.orElse(null);
if (tank != null)
return;
TileEntity tileEntity = world.getTileEntity(location.getConnectedPos());
if (tileEntity == null)
return;
LazyOptional<IFluidHandler> capability =
tileEntity.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, location.getOppositeFace());
if (capability.isPresent()) {
handler = capability;
handler.addListener($ -> onHandlerInvalidated(world));
}
}
public FluidStack provideFluid() {
IFluidHandler tank = provideHandler().orElse(null);
if (tank == null)
return FluidStack.EMPTY;
return tank.drain(1, FluidAction.SIMULATE);
}
public LazyOptional<IFluidHandler> provideHandler() {
return handler;
}
}
class PumpEndpoint extends FluidNetworkEndpoint {
PumpTileEntity pumpTE;
public PumpEndpoint(BlockFace location, PumpTileEntity pumpTE) {
super(pumpTE.getWorld(), location, LazyOptional.empty());
this.pumpTE = pumpTE;
}
@Override
protected void onHandlerInvalidated(IWorld world) {}
@Override
public FluidStack provideFluid() {
return pumpTE.providedFluid;
}
}
class InterPumpEndpoint extends FluidNetworkEndpoint {
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps;
private InterPumpEndpoint(IWorld world, BlockFace location, LazyOptional<IFluidHandler> handler) {
super(world, location, handler);
}
public InterPumpEndpoint(IWorld world, BlockFace location, PumpTileEntity source, PumpTileEntity interfaced,
BlockFace sourcePos, BlockFace interfacedPos) {
this(world, location, LazyOptional.empty());
handler = LazyOptional.of(() -> new InterPumpFluidHandler(this));
pumps = Couple.create(Pair.of(sourcePos, new WeakReference<>(source)),
Pair.of(interfacedPos, new WeakReference<>(interfaced)));
}
public InterPumpEndpoint opposite(IWorld world) {
InterPumpEndpoint interPumpEndpoint = new InterPumpEndpoint(world, this.location.getOpposite(), handler);
interPumpEndpoint.pumps = pumps.copy();
return interPumpEndpoint;
}
public Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> getPumps() {
return pumps;
}
public boolean isPulling(boolean first) {
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = getPumps().get(first);
PumpTileEntity pumpTileEntity = pair.getSecond()
.get();
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
return false;
return pumpTileEntity.isPullingOnSide(pumpTileEntity.isFront(pair.getFirst()
.getFace()));
}
public int getTransferSpeed(boolean first) {
PumpTileEntity pumpTileEntity = getPumps().get(first)
.getSecond()
.get();
if (pumpTileEntity == null || pumpTileEntity.isRemoved())
return 0;
return pumpTileEntity.getFluidTransferSpeed();
}
@Override
public LazyOptional<IFluidHandler> provideHandler() {
if (isPulling(true) == isPulling(false))
return LazyOptional.empty();
if (getTransferSpeed(true) > getTransferSpeed(false))
return LazyOptional.empty();
return super.provideHandler();
}
@Override
public FluidStack provideFluid() {
if (!provideHandler().isPresent())
return FluidStack.EMPTY;
Couple<Pair<BlockFace, WeakReference<PumpTileEntity>>> pumps = getPumps();
for (boolean current : Iterate.trueAndFalse) {
if (isPulling(current))
continue;
Pair<BlockFace, WeakReference<PumpTileEntity>> pair = pumps.get(current);
BlockFace blockFace = pair.getFirst();
PumpTileEntity pumpTileEntity = pair.getSecond()
.get();
if (pumpTileEntity == null)
continue;
if (pumpTileEntity.networks == null)
continue;
FluidNetwork fluidNetwork = pumpTileEntity.networks.get(pumpTileEntity.isFront(blockFace.getFace()));
for (FluidNetworkFlow fluidNetworkFlow : fluidNetwork.flows) {
for (FluidNetworkEndpoint fne : fluidNetworkFlow.outputEndpoints) {
if (!(fne instanceof InterPumpEndpoint))
continue;
InterPumpEndpoint ipe = (InterPumpEndpoint) fne;
if (!ipe.location.isEquivalent(location))
continue;
FluidStack heldFluid = fluidNetworkFlow.fluidStack;
if (heldFluid.isEmpty())
return heldFluid;
FluidStack copy = heldFluid.copy();
copy.setAmount(1);
return heldFluid;
}
}
}
return FluidStack.EMPTY;
}
}

View file

@ -0,0 +1,304 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IWorld;
import net.minecraftforge.fluids.FluidStack;
class FluidNetworkFlow {
@FunctionalInterface
static interface PipeFlowConsumer {
void accept(FluidPipeBehaviour pipe, Direction face, boolean inbound);
}
/**
*
*/
private final FluidNetwork activePipeNetwork;
FluidNetworkEndpoint source;
FluidStack fluidStack;
Set<BlockFace> flowPointers;
Set<FluidNetworkEndpoint> outputEndpoints;
boolean pumpReached;
boolean pulling;
float speed;
public FluidNetworkFlow(FluidNetwork activePipeNetwork, FluidNetworkEndpoint source, IWorld world,
boolean pulling) {
this.activePipeNetwork = activePipeNetwork;
this.source = source;
this.pulling = pulling;
flowPointers = new HashSet<>();
outputEndpoints = new HashSet<>();
fluidStack = FluidStack.EMPTY;
tick(world, 0);
}
void resetFlow(IWorld world) {
fluidStack = FluidStack.EMPTY;
flowPointers.clear();
outputEndpoints.clear();
pumpReached = false;
forEachPipeFlow(world, (pipe, face, inbound) -> pipe.removeFlow(this, face, inbound));
}
void addToSkippedConnections(IWorld world) {
forEachPipeFlow(world, (pipe, face, inbound) -> {
if (!pipe.getFluid().isFluidEqual(fluidStack))
return;
BlockFace blockFace = new BlockFace(pipe.getPos(), face);
this.activePipeNetwork.previousFlow.put(blockFace, pipe.getFluid());
});
}
void forEachPipeFlow(IWorld world, FluidNetworkFlow.PipeFlowConsumer consumer) {
Set<BlockFace> flowPointers = new HashSet<>();
flowPointers.add(getSource());
// Update all branches of this flow, and create new ones if necessary
while (!flowPointers.isEmpty()) {
List<BlockFace> toAdd = new ArrayList<>();
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
BlockFace flowPointer = iterator.next();
BlockPos currentPos = flowPointer.getPos();
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
if (pipe == null) {
iterator.remove();
continue;
}
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
.getSecond();
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
boolean inbound = entry.getValue() != pulling;
Direction face = entry.getKey();
if (inbound && face != flowPointer.getFace())
continue;
consumer.accept(pipe, face, inbound);
if (inbound)
continue;
toAdd.add(new BlockFace(currentPos.offset(face), face.getOpposite()));
}
iterator.remove();
}
flowPointers.addAll(toAdd);
}
}
void tick(IWorld world, float speed) {
boolean skipping = speed == 0;
Map<BlockFace, FluidStack> previousFlow = this.activePipeNetwork.previousFlow;
if (skipping && previousFlow.isEmpty())
return;
this.speed = speed;
FluidStack provideFluid = source.provideFluid();
if (!fluidStack.isEmpty() && !fluidStack.isFluidEqual(provideFluid)) {
resetFlow(world);
return;
}
fluidStack = provideFluid;
// There is currently no unfinished flow being followed
if (flowPointers.isEmpty()) {
// The fluid source has run out -> reset
if (fluidStack.isEmpty()) {
if (hasValidTargets())
resetFlow(world);
return;
}
// Keep the flows if all is well
if (hasValidTargets())
return;
// Start a new flow from or towards the pump
BlockFace source = getSource();
if (tryConnectTo(world, source.getOpposite()))
return;
flowPointers.add(source);
}
boolean skipped = false;
Set<BlockFace> pausedPointers = new HashSet<>();
do {
skipped = false;
List<BlockFace> toAdd = null;
// Update all branches of this flow, and create new ones if necessary
for (Iterator<BlockFace> iterator = flowPointers.iterator(); iterator.hasNext();) {
BlockFace flowPointer = iterator.next();
BlockPos currentPos = flowPointer.getPos();
if (pausedPointers.contains(flowPointer))
continue;
FluidPipeBehaviour pipe = getPipeInTree(world, currentPos);
if (pipe == null) {
iterator.remove();
continue;
}
Map<Direction, Boolean> directions = this.activePipeNetwork.pipeGraph.get(currentPos)
.getSecond();
boolean inboundComplete = false;
boolean allFlowsComplete = true;
BlockState state = world.getBlockState(currentPos);
// First loop only inbound flows of a pipe to see if they have reached the
// center
for (boolean inboundPass : Iterate.trueAndFalse) {
if (!inboundPass && !inboundComplete)
break;
// For all connections of the pipe tree of the pump
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
Boolean awayFromPump = entry.getValue();
Direction direction = entry.getKey();
boolean inbound = awayFromPump != pulling;
if (inboundPass && direction != flowPointer.getFace())
continue;
if (!inboundPass && inbound)
continue;
if (!pipe.canTransferToward(fluidStack, state, direction, inbound))
continue;
BlockFace blockface = new BlockFace(currentPos, direction);
if (!pipe.hasStartedFlow(this, direction, inbound))
pipe.addFlow(this, direction, inbound, false);
if (skipping && canSkip(previousFlow, blockface)) {
pipe.skipFlow(direction, inbound);
FluidPropagator.showBlockFace(blockface)
.colored(0x0)
.lineWidth(1 / 8f);
skipped = true;
}
if (!pipe.hasCompletedFlow(direction, inbound)) {
allFlowsComplete = false;
continue;
}
if (inboundPass) {
inboundComplete = true;
continue;
}
// Outward pass, check if any target was reached
tryConnectTo(world, blockface);
}
}
if (!allFlowsComplete && !skipping)
continue;
// Create a new flow branch at each outward pipe connection
for (Entry<Direction, Boolean> entry : directions.entrySet()) {
if (entry.getValue() != pulling)
continue;
Direction face = entry.getKey();
BlockFace addedBlockFace = new BlockFace(currentPos.offset(face), face.getOpposite());
if (skipping && !canSkip(previousFlow, addedBlockFace)) {
allFlowsComplete = false;
continue;
}
if (toAdd == null)
toAdd = new ArrayList<>();
toAdd.add(addedBlockFace);
}
if (!allFlowsComplete && skipping) {
pausedPointers.add(flowPointer);
continue;
}
iterator.remove();
} // End of branch loop
if (toAdd != null)
flowPointers.addAll(toAdd);
} while (skipping && skipped);
}
private boolean canSkip(Map<BlockFace, FluidStack> previousFlow, BlockFace blockface) {
return previousFlow.containsKey(blockface) && previousFlow.get(blockface)
.isFluidEqual(fluidStack);
}
private boolean tryConnectTo(IWorld world, BlockFace blockface) {
// Pulling flow, target is the pump
if (pulling) {
if (!this.activePipeNetwork.pumpLocation.getOpposite()
.equals(blockface))
return false;
pumpReached = true;
TileEntity targetTE = world.getTileEntity(this.activePipeNetwork.pumpLocation.getPos());
if (targetTE instanceof PumpTileEntity)
((PumpTileEntity) targetTE).setProvidedFluid(fluidStack);
FluidPropagator.showBlockFace(this.activePipeNetwork.pumpLocation)
.colored(0x799351)
.lineWidth(1 / 8f);
return true;
}
// Pushing flow, targets are the endpoints
for (FluidNetworkEndpoint networkEndpoint : this.activePipeNetwork.targets) {
if (!networkEndpoint.location.isEquivalent(blockface))
continue;
outputEndpoints.add(networkEndpoint);
FluidPropagator.showBlockFace(blockface)
.colored(0x799351)
.lineWidth(1 / 8f);
return !(networkEndpoint instanceof InterPumpEndpoint);
}
return false;
}
private BlockFace getSource() {
return pulling ? source.location : this.activePipeNetwork.pumpLocation.getOpposite();
}
private FluidPipeBehaviour getPipeInTree(IWorld world, BlockPos currentPos) {
if (!world.isAreaLoaded(currentPos, 0))
return null;
if (!this.activePipeNetwork.pipeGraph.containsKey(currentPos))
return null;
return TileEntityBehaviour.get(world, currentPos, FluidPipeBehaviour.TYPE);
}
boolean hasValidTargets() {
return pumpReached || !outputEndpoints.isEmpty();
}
public float getSpeed() {
return speed;
}
public FluidStack getFluidStack() {
return fluidStack;
}
}

View file

@ -0,0 +1,57 @@
package com.simibubi.create.content.contraptions.fluids;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import net.minecraft.block.BlockState;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ILightReader;
public class FluidPipeAttachmentBehaviour extends TileEntityBehaviour {
public static BehaviourType<FluidPipeAttachmentBehaviour> TYPE = new BehaviourType<>();
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
if (!isPipeConnectedTowards(state, direction))
return AttachmentTypes.NONE;
BlockPos offsetPos = pos.offset(direction);
BlockState facingState = world.getBlockState(offsetPos);
if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING)
.getAxis() == direction.getAxis())
return AttachmentTypes.NONE;
if (FluidPropagator.hasFluidCapability(facingState, world, offsetPos, direction))
return AttachmentTypes.DRAIN;
return AttachmentTypes.RIM;
}
public boolean isPipeConnectedTowards(BlockState state, Direction direction) {
FluidPipeBehaviour fluidPipeBehaviour = TileEntityBehaviour.get(tileEntity, FluidPipeBehaviour.TYPE);
if (fluidPipeBehaviour == null)
return false;
return fluidPipeBehaviour.isConnectedTo(state, direction);
}
public static enum AttachmentTypes {
NONE, RIM, DRAIN;
public boolean hasModel() {
return this != NONE;
}
}
public FluidPipeAttachmentBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public BehaviourType<?> getType() {
return TYPE;
}
}

View file

@ -0,0 +1,524 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
import java.util.Set;
import javax.annotation.Nullable;
import com.simibubi.create.AllSpecialTextures;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.KineticDebugger;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.BehaviourType;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.LerpedFloat;
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
import com.simibubi.create.foundation.utility.NBTHelper;
import com.simibubi.create.foundation.utility.Pair;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.block.BlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.particles.BlockParticleData;
import net.minecraft.particles.IParticleData;
import net.minecraft.particles.ParticleTypes;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fml.DistExecutor;
public abstract class FluidPipeBehaviour extends TileEntityBehaviour {
public static BehaviourType<FluidPipeBehaviour> TYPE = new BehaviourType<>();
// Direction -> (inboundflows{}, outwardflows{})
Map<Direction, Couple<PipeFlows>> allFlows;
FluidStack fluid;
Couple<FluidStack> collision;
public FluidPipeBehaviour(SmartTileEntity te) {
super(te);
allFlows = new IdentityHashMap<>();
fluid = FluidStack.EMPTY;
}
@Override
public BehaviourType<?> getType() {
return TYPE;
}
public void notifyNetwork() {
FluidPropagator.propagateChangedPipe(this.getWorld(), tileEntity.getPos(), tileEntity.getBlockState());
}
public boolean canTransferToward(FluidStack fluid, BlockState state, Direction direction, boolean inbound) {
return isConnectedTo(state, direction);
}
public abstract boolean isConnectedTo(BlockState state, Direction direction);
public float getRimRadius(BlockState state, Direction direction) {
return 1 / 4f + 1 / 64f;
}
public boolean hasStartedFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
return allFlows.containsKey(face) && allFlows.get(face)
.get(inbound)
.hasFlow(flow);
}
public boolean hasCompletedFlow(Direction face, boolean inbound) {
return allFlows.containsKey(face) && allFlows.get(face)
.get(inbound)
.isCompleted();
}
@Override
public void write(CompoundNBT compound, boolean client) {
compound.put("Fluid", fluid.writeToNBT(new CompoundNBT()));
ListNBT flows = new ListNBT();
for (Direction face : Iterate.directions)
for (boolean inbound : Iterate.trueAndFalse) {
LerpedFloat flowProgress = getFlowProgress(face, inbound);
if (flowProgress == null)
continue;
CompoundNBT nbt = new CompoundNBT();
NBTHelper.writeEnum(nbt, "Face", face);
nbt.putBoolean("In", inbound);
PipeFlows pipeFlows = allFlows.get(face)
.get(inbound);
Set<FluidNetworkFlow> participants = pipeFlows.participants;
nbt.putBoolean("Silent", participants == null || participants.isEmpty());
nbt.put("Progress", flowProgress.writeNBT());
if (client)
nbt.putFloat("Strength", pipeFlows.bestFlowStrength);
flows.add(nbt);
}
compound.put("Flows", flows);
}
@Override
public void read(CompoundNBT compound, boolean client) {
fluid = FluidStack.loadFluidStackFromNBT(compound.getCompound("Fluid"));
if (client) {
for (Direction face : Iterate.directions)
if (allFlows.containsKey(face))
allFlows.get(face)
.forEach(pf -> pf.progress = null);
}
NBTHelper.iterateCompoundList(compound.getList("Flows", NBT.TAG_COMPOUND), nbt -> {
Direction face = NBTHelper.readEnum(nbt, "Face", Direction.class);
boolean inbound = nbt.getBoolean("In");
LerpedFloat progress = createFlowProgress(0);
progress.readNBT(nbt.getCompound("Progress"), false);
addFlow(null, face, inbound, nbt.getBoolean("Silent"));
setFlowProgress(face, inbound, progress);
if (client)
setVisualFlowStrength(face, inbound, nbt.getFloat("Strength"));
});
if (!client)
return;
for (Direction face : Iterate.directions) {
if (!allFlows.containsKey(face))
return;
Couple<PipeFlows> couple = allFlows.get(face);
if (couple.get(true).progress == null && couple.get(false).progress == null)
allFlows.remove(face);
if (allFlows.isEmpty())
clear();
}
}
public void addFlow(@Nullable FluidNetworkFlow flow, Direction face, boolean inbound, boolean silent) {
if (flow != null) {
FluidStack fluid = flow.getFluidStack();
if (!this.fluid.isEmpty() && !fluid.isFluidEqual(this.fluid)) {
collision = Couple.create(this.fluid, fluid);
return;
}
this.fluid = fluid;
}
if (!allFlows.containsKey(face)) {
allFlows.put(face, Couple.create(PipeFlows::new));
if (inbound && !silent)
spawnSplashOnRim(face);
}
if (flow != null) {
PipeFlows flows = allFlows.get(face)
.get(inbound);
flows.addFlow(flow);
contentsChanged();
}
}
public void removeFlow(FluidNetworkFlow flow, Direction face, boolean inbound) {
if (!allFlows.containsKey(face))
return;
Couple<PipeFlows> couple = allFlows.get(face);
couple.get(inbound)
.removeFlow(flow);
contentsChanged();
if (!couple.get(true)
.isActive()
&& !couple.get(false)
.isActive())
allFlows.remove(face);
if (allFlows.isEmpty())
clear();
}
public void setVisualFlowStrength(Direction face, boolean inbound, float strength) {
if (!allFlows.containsKey(face))
return;
allFlows.get(face)
.get(inbound).bestFlowStrength = strength;
}
public void setFlowProgress(Direction face, boolean inbound, LerpedFloat progress) {
if (!allFlows.containsKey(face))
return;
allFlows.get(face)
.get(inbound).progress = progress;
}
public LerpedFloat getFlowProgress(Direction face, boolean inbound) {
if (!allFlows.containsKey(face))
return null;
return allFlows.get(face)
.get(inbound).progress;
}
public void skipFlow(Direction face, boolean inbound) {
if (!allFlows.containsKey(face))
return;
Couple<PipeFlows> couple = allFlows.get(face);
couple.get(inbound)
.skip();
}
public void clear() {
allFlows.clear();
fluid = FluidStack.EMPTY;
contentsChanged();
}
public void spawnParticles() {
DistExecutor.runWhenOn(Dist.CLIENT, () -> this::spawnParticlesInner);
}
public void spawnSplashOnRim(Direction face) {
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> spawnSplashOnRimInner(face));
}
public static final int MAX_PARTICLE_RENDER_DISTANCE = 20;
public static final int SPLASH_PARTICLE_AMOUNT = 1;
public static final float IDLE_PARTICLE_SPAWN_CHANCE = 1 / 800f;
public static final Random r = new Random();
@OnlyIn(Dist.CLIENT)
private void spawnParticlesInner() {
if (!isRenderEntityWithinDistance())
return;
if (fluid.isEmpty())
return;
World world = Minecraft.getInstance().world;
BlockPos pos = tileEntity.getPos();
BlockState state = world.getBlockState(pos);
for (Direction face : Iterate.directions) {
boolean open = FluidPropagator.isOpenEnd(world, pos, face);
if (isConnectedTo(state, face)) {
if (open) {
spawnPouringLiquid(world, state, fluid, face, 1);
continue;
}
if (r.nextFloat() < IDLE_PARTICLE_SPAWN_CHANCE)
spawnRimParticles(world, state, fluid, face, 1);
}
}
}
@OnlyIn(Dist.CLIENT)
private void spawnSplashOnRimInner(Direction face) {
if (!isRenderEntityWithinDistance())
return;
if (fluid.isEmpty())
return;
World world = Minecraft.getInstance().world;
BlockPos pos = tileEntity.getPos();
BlockState state = world.getBlockState(pos);
spawnRimParticles(world, state, fluid, face, SPLASH_PARTICLE_AMOUNT);
}
@OnlyIn(Dist.CLIENT)
private void spawnRimParticles(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
BlockPos pos = tileEntity.getPos();
if (FluidPropagator.isOpenEnd(world, pos, side)) {
spawnPouringLiquid(world, state, fluid, side, amount);
return;
}
IParticleData particle = null;
if (FluidHelper.isWater(fluid.getFluid()))
particle = ParticleTypes.DRIPPING_WATER;
if (FluidHelper.isLava(fluid.getFluid()))
particle = ParticleTypes.DRIPPING_LAVA;
// TODO: Generic drip particle type for forge fluids
if (particle == null)
return;
float rimRadius = getRimRadius(state, side);
Vec3d directionVec = new Vec3d(side.getDirectionVec());
for (int i = 0; i < amount; i++) {
Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, 1)
.normalize();
vec = VecHelper.clampComponentWise(vec, rimRadius)
.mul(VecHelper.axisAlingedPlaneOf(directionVec))
.add(directionVec.scale(.45 + r.nextFloat() / 16f));
Vec3d m = vec;
vec = vec.add(VecHelper.getCenterOf(pos));
world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z);
}
}
@OnlyIn(Dist.CLIENT)
private void spawnPouringLiquid(World world, BlockState state, FluidStack fluid, Direction side, int amount) {
IParticleData particle = new BlockParticleData(ParticleTypes.BLOCK, fluid.getFluid()
.getDefaultState()
.getBlockState());
float rimRadius = getRimRadius(state, side);
Vec3d directionVec = new Vec3d(side.getDirectionVec());
Couple<PipeFlows> couple = allFlows.get(side);
if (couple == null)
return;
couple.forEachWithContext((flow, inbound) -> {
if (flow.progress == null)
return;
for (int i = 0; i < amount; i++) {
Vec3d vec = VecHelper.offsetRandomly(Vec3d.ZERO, r, rimRadius);
vec = vec.mul(VecHelper.axisAlingedPlaneOf(directionVec))
.add(directionVec.scale(.5 + r.nextFloat() / 4f));
Vec3d m = vec;
Vec3d centerOf = VecHelper.getCenterOf(tileEntity.getPos());
vec = vec.add(centerOf);
if (inbound) {
vec = vec.add(m);
m = centerOf.add(directionVec.scale(.5))
.subtract(vec)
.scale(3);
}
world.addOptionalParticle(particle, vec.x, vec.y - 1 / 16f, vec.z, m.x, m.y, m.z);
}
});
}
@OnlyIn(Dist.CLIENT)
private boolean isRenderEntityWithinDistance() {
Entity renderViewEntity = Minecraft.getInstance()
.getRenderViewEntity();
if (renderViewEntity == null)
return false;
Vec3d center = VecHelper.getCenterOf(tileEntity.getPos());
if (renderViewEntity.getPositionVec()
.distanceTo(center) > MAX_PARTICLE_RENDER_DISTANCE)
return false;
return true;
}
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
@Override
public void tick() {
super.tick();
boolean isRemote = getWorld().isRemote;
allFlows.values()
.forEach(c -> c.forEach(pf -> pf.tick(isRemote)));
if (isRemote) {
clientTick();
return;
}
if (collision != null) {
FluidReactions.handlePipeFlowCollision(getWorld(), tileEntity.getPos(), collision.getFirst(),
collision.getSecond());
collision = null;
return;
}
}
public Pair<Boolean, LerpedFloat> getStrogestFlow(Direction side) {
Couple<PipeFlows> couple = allFlows.get(side);
if (couple == null)
return null;
PipeFlows in = couple.get(true);
PipeFlows out = couple.get(false);
Couple<LerpedFloat> progress = couple.map(pf -> pf.progress);
boolean inboundStronger = false;
if (in.isCompleted() != out.isCompleted()) {
inboundStronger = in.isCompleted();
} else if ((progress.get(true) == null) != (progress.get(false) == null)) {
inboundStronger = progress.get(true) != null;
} else {
if (progress.get(true) != null)
inboundStronger = in.bestFlowStrength > out.bestFlowStrength;
}
return Pair.of(inboundStronger, progress.get(inboundStronger));
}
private void clientTick() {
spawnParticles();
if (!KineticDebugger.isActive())
return;
if (fluid.isEmpty())
return;
for (Entry<Direction, Couple<PipeFlows>> entry : allFlows.entrySet()) {
Direction face = entry.getKey();
Vec3d directionVec = new Vec3d(face.getDirectionVec());
float size = 1 / 4f;
boolean extended = !isConnectedTo(tileEntity.getBlockState(), face.getOpposite());
float length = extended ? .75f : .5f;
entry.getValue()
.forEachWithContext((flow, inbound) -> {
if (flow.progress == null)
return;
float value = flow.progress.getValue();
Vec3d start = directionVec.scale(inbound ? .5 : .5f - length);
Vec3d offset = directionVec.scale(length * (inbound ? -1 : 1))
.scale(value);
Vec3d scale = new Vec3d(1, 1, 1).subtract(directionVec.scale(face.getAxisDirection()
.getOffset()))
.scale(size);
AxisAlignedBB bb =
new AxisAlignedBB(start, start.add(offset)).offset(VecHelper.getCenterOf(tileEntity.getPos()))
.grow(scale.x, scale.y, scale.z);
int color = 0x7fdbda;
if (!fluid.isEmpty()) {
Fluid fluid2 = fluid.getFluid();
if (fluid2 == Fluids.WATER)
color = 0x1D4D9B;
if (fluid2 == Fluids.LAVA)
color = 0xFF773D;
}
CreateClient.outliner.chaseAABB(Pair.of(this, face), bb)
.withFaceTexture(AllSpecialTextures.CUTOUT_CHECKERED)
.colored(color)
.lineWidth(1 / 16f);
});
}
}
private void contentsChanged() {
tileEntity.markDirty();
tileEntity.sendData();
}
private LerpedFloat createFlowProgress(double speed) {
return LerpedFloat.linear()
.startWithValue(0)
.chase(1, speed, Chaser.LINEAR);
}
public FluidStack getFluid() {
return fluid;
}
class PipeFlows {
LerpedFloat progress;
Set<FluidNetworkFlow> participants;
float bestFlowStrength;
void addFlow(FluidNetworkFlow flow) {
if (participants == null)
participants = new HashSet<>();
participants.add(flow);
if (progress == null) {
progress = createFlowProgress(flow.getSpeed());
}
}
boolean hasFlow(FluidNetworkFlow flow) {
return participants != null && participants.contains(flow);
}
void tick(boolean onClient) {
if (progress == null)
return;
if (!onClient) {
if (participants == null)
return;
bestFlowStrength = 0;
for (FluidNetworkFlow networkFlow : participants)
bestFlowStrength = Math.max(bestFlowStrength, networkFlow.getSpeed());
if (isCompleted())
return;
if (progress.updateChaseSpeed(bestFlowStrength))
contentsChanged();
}
progress.tickChaser();
}
void skip() {
progress = LerpedFloat.linear()
.startWithValue(1);
}
void removeFlow(FluidNetworkFlow flow) {
if (participants == null)
return;
participants.remove(flow);
}
boolean isActive() {
return participants != null && !participants.isEmpty();
}
boolean isCompleted() {
return progress != null && progress.getValue() == 1;
}
}
}

View file

@ -1,157 +0,0 @@
package com.simibubi.create.content.contraptions.fluids;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.block.SixWayBlock;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.ILightReader;
import net.minecraft.world.IWorld;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import javax.annotation.Nullable;
public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable {
public FluidPipeBlock(Properties properties) {
super(4 / 16f, properties);
this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
}
public static boolean isPipe(BlockState state) {
return state.getBlock() instanceof FluidPipeBlock;
}
public static boolean isTank(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
return state.hasTileEntity() && world.getTileEntity(pos).getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite()).isPresent();
}
// TODO: more generic pipe connection handling. Ideally without marker interface
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
if (isPipe(neighbour) || isTank(neighbour, world, pos, blockFace))
return true;
return neighbour.getBlock() instanceof PumpBlock && blockFace.getAxis() == neighbour.get(PumpBlock.FACING)
.getAxis();
}
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
if (!isPipe(state))
return false;
if (!state.get(FACING_TO_PROPERTY_MAP.get(direction)))
return false;
BlockPos offsetPos = pos.offset(direction);
BlockState facingState = world.getBlockState(offsetPos);
if (facingState.getBlock() instanceof PumpBlock && facingState.get(PumpBlock.FACING)
.getAxis() == direction.getAxis())
return false;
if (!isPipe(facingState))
return true;
if (!isCornerOrEndPipe(world, pos, state))
return false;
if (isStraightPipe(world, offsetPos, facingState))
return true;
if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState))
return true;
if (isCornerOrEndPipe(world, offsetPos, facingState))
return direction.getAxisDirection() == AxisDirection.POSITIVE;
return false;
}
public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) {
return isPipe(state) && !isStraightPipe(world, pos, state) && !shouldDrawCasing(world, pos, state);
}
public static boolean isStraightPipe(ILightReader world, BlockPos pos, BlockState state) {
if (!isPipe(state))
return false;
boolean axisFound = false;
for (Axis axis : Iterate.axes) {
Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis);
Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
if (state.get(FACING_TO_PROPERTY_MAP.get(d1)) && state.get(FACING_TO_PROPERTY_MAP.get(d2)))
if (axisFound)
return false;
else
axisFound = true;
}
return axisFound;
}
public static boolean shouldDrawCasing(ILightReader world, BlockPos pos, BlockState state) {
if (!isPipe(state))
return false;
for (Axis axis : Iterate.axes) {
int connections = 0;
for (Direction direction : Iterate.directions)
if (direction.getAxis() != axis && state.get(FACING_TO_PROPERTY_MAP.get(direction)))
connections++;
if (connections > 2)
return true;
}
return false;
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN, BlockStateProperties.WATERLOGGED);
super.fillStateContainer(builder);
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(),
context.getPos()).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
IWorld world, BlockPos pos, BlockPos neighbourPos) {
if (state.get(BlockStateProperties.WATERLOGGED)) {
world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return updateBlockState(state, direction, direction.getOpposite(), world, pos);
}
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
ILightReader world, BlockPos pos) {
// Update sides that are not ignored
for (Direction d : Iterate.directions)
if (d != ignore)
state = state.with(FACING_TO_PROPERTY_MAP.get(d),
canConnectTo(world, pos.offset(d), world.getBlockState(pos.offset(d)), d.getOpposite()));
// See if it has enough connections
Direction connectedDirection = null;
for (Direction d : Iterate.directions) {
if (state.get(FACING_TO_PROPERTY_MAP.get(d))) {
if (connectedDirection != null)
return state;
connectedDirection = d;
}
}
// Add opposite end if only one connection
if (connectedDirection != null)
return state.with(FACING_TO_PROPERTY_MAP.get(connectedDirection.getOpposite()), true);
// Use preferred
return state.with(FACING_TO_PROPERTY_MAP.get(preferredDirection), true)
.with(FACING_TO_PROPERTY_MAP.get(preferredDirection.getOpposite()), true);
}
@Override
public IFluidState getFluidState(BlockState state) {
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState();
}
}

View file

@ -0,0 +1,189 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.mutable.MutableObject;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.CreateClient;
import com.simibubi.create.content.contraptions.fluids.pipes.AxisPipeBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.outliner.Outline.OutlineParams;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.World;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fml.DistExecutor;
public class FluidPropagator {
public static Direction validateNeighbourChange(BlockState state, World world, BlockPos pos, Block otherBlock,
BlockPos neighborPos, boolean isMoving) {
if (world.isRemote)
return null;
if (otherBlock instanceof FluidPipeBlock)
return null;
if (otherBlock instanceof AxisPipeBlock)
return null;
if (otherBlock instanceof PumpBlock)
return null;
if (otherBlock instanceof FlowingFluidBlock)
return null;
if (!isStraightPipe(state))
return null;
for (Direction d : Iterate.directions) {
if (!pos.offset(d)
.equals(neighborPos))
continue;
return d;
}
return null;
}
public static FluidPipeBehaviour getPipe(IBlockReader reader, BlockPos pos) {
return TileEntityBehaviour.get(reader, pos, FluidPipeBehaviour.TYPE);
}
public static boolean isOpenEnd(IBlockReader reader, BlockPos pos, Direction side) {
BlockPos connectedPos = pos.offset(side);
BlockState connectedState = reader.getBlockState(connectedPos);
FluidPipeBehaviour pipe = FluidPropagator.getPipe(reader, connectedPos);
if (pipe != null && pipe.isConnectedTo(connectedState, side.getOpposite()))
return false;
if (PumpBlock.isPump(connectedState) && connectedState.get(PumpBlock.FACING)
.getAxis() == side.getAxis())
return false;
if (Block.hasSolidSide(connectedState, reader, connectedPos, side.getOpposite()))
return false;
if (!(connectedState.getMaterial()
.isReplaceable() && connectedState.getBlockHardness(reader, connectedPos) != -1)
&& !connectedState.has(BlockStateProperties.WATERLOGGED))
return false;
return true;
}
public static void propagateChangedPipe(IWorld world, BlockPos pipePos, BlockState pipeState) {
List<BlockPos> frontier = new ArrayList<>();
Set<BlockPos> visited = new HashSet<>();
frontier.add(pipePos);
// Visit all connected pumps to update their network
while (!frontier.isEmpty()) {
BlockPos currentPos = frontier.remove(0);
if (visited.contains(currentPos))
continue;
visited.add(currentPos);
BlockState currentState = currentPos.equals(pipePos) ? pipeState : world.getBlockState(currentPos);
FluidPipeBehaviour pipe = getPipe(world, currentPos);
if (pipe == null)
continue;
for (Direction direction : getPipeConnections(currentState, pipe)) {
BlockPos target = currentPos.offset(direction);
if (!world.isAreaLoaded(target, 0))
continue;
TileEntity tileEntity = world.getTileEntity(target);
BlockState targetState = world.getBlockState(target);
if (tileEntity instanceof PumpTileEntity) {
if (!AllBlocks.MECHANICAL_PUMP.has(targetState) || targetState.get(PumpBlock.FACING)
.getAxis() != direction.getAxis())
continue;
PumpTileEntity pump = (PumpTileEntity) tileEntity;
pump.updatePipesOnSide(direction.getOpposite());
continue;
}
if (visited.contains(target))
continue;
FluidPipeBehaviour targetPipe = getPipe(world, target);
if (targetPipe == null)
continue;
if (targetPipe.isConnectedTo(targetState, direction.getOpposite()))
frontier.add(target);
}
}
}
public static List<Direction> getPipeConnections(BlockState state, FluidPipeBehaviour pipe) {
List<Direction> list = new ArrayList<>();
for (Direction d : Iterate.directions)
if (pipe.isConnectedTo(state, d))
list.add(d);
return list;
}
public static int getPumpRange() {
return AllConfigs.SERVER.fluids.mechanicalPumpRange.get();
}
public static OutlineParams showBlockFace(BlockFace face) {
MutableObject<OutlineParams> params = new MutableObject<>(new OutlineParams());
DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> {
Vec3d directionVec = new Vec3d(face.getFace()
.getDirectionVec());
Vec3d scaleVec = directionVec.scale(-.25f * face.getFace()
.getAxisDirection()
.getOffset());
directionVec = directionVec.scale(.5f);
params.setValue(CreateClient.outliner.showAABB(face,
FluidPropagator.smallCenter.offset(directionVec.add(new Vec3d(face.getPos())))
.grow(scaleVec.x, scaleVec.y, scaleVec.z)
.grow(1 / 16f)));
});
return params.getValue();
}
static AxisAlignedBB smallCenter = new AxisAlignedBB(BlockPos.ZERO).shrink(.25);
public static boolean hasFluidCapability(BlockState state, IBlockReader world, BlockPos pos, Direction blockFace) {
return state.hasTileEntity() && world.getTileEntity(pos)
.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, blockFace.getOpposite())
.isPresent();
}
public static boolean isStraightPipe(BlockState state) {
if (state.getBlock() instanceof AxisPipeBlock)
return true;
if (!FluidPipeBlock.isPipe(state))
return false;
boolean axisFound = false;
int connections = 0;
for (Axis axis : Iterate.axes) {
Direction d1 = Direction.getFacingFromAxis(AxisDirection.NEGATIVE, axis);
Direction d2 = Direction.getFacingFromAxis(AxisDirection.POSITIVE, axis);
boolean openAt1 = FluidPipeBlock.isOpenAt(state, d1);
boolean openAt2 = FluidPipeBlock.isOpenAt(state, d2);
if (openAt1)
connections++;
if (openAt2)
connections++;
if (openAt1 && openAt2)
if (axisFound)
return false;
else
axisFound = true;
}
return axisFound && connections == 2;
}
}

View file

@ -0,0 +1,37 @@
package com.simibubi.create.content.contraptions.fluids;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.utility.BlockHelper;
import net.minecraft.block.Blocks;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
public class FluidReactions {
public static void handlePipeFlowCollision(World world, BlockPos pos, FluidStack fluid, FluidStack fluid2) {
Fluid f1 = fluid.getFluid();
Fluid f2 = fluid2.getFluid();
BlockHelper.destroyBlock(world, pos, 1);
if (f1 == Fluids.WATER && f2 == Fluids.LAVA || f2 == Fluids.WATER && f1 == Fluids.LAVA)
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
}
public static void handlePipeSpillCollision(World world, BlockPos pos, Fluid pipeFluid, IFluidState worldFluid) {
Fluid pf = FluidHelper.convertToStill(pipeFluid);
Fluid wf = worldFluid.getFluid();
if (pf == Fluids.WATER && wf == Fluids.LAVA)
world.setBlockState(pos, Blocks.OBSIDIAN.getDefaultState());
if (pf == Fluids.WATER && wf == Fluids.FLOWING_LAVA)
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
else if (pf == Fluids.LAVA && wf == Fluids.WATER)
world.setBlockState(pos, Blocks.STONE.getDefaultState());
else if (pf == Fluids.LAVA && wf == Fluids.FLOWING_WATER)
world.setBlockState(pos, Blocks.COBBLESTONE.getDefaultState());
}
}

View file

@ -0,0 +1,44 @@
package com.simibubi.create.content.contraptions.fluids;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.templates.FluidTank;
public class InterPumpFluidHandler extends FluidTank {
InterPumpEndpoint endpoint;
public InterPumpFluidHandler(InterPumpEndpoint endpoint) {
super(Integer.MAX_VALUE);
this.endpoint = endpoint;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
if (resource.isEmpty())
return 0;
int maxInput = Math.min(resource.getAmount(), Math.max(getTransferCapacity() - getFluidAmount(), 0));
FluidStack toInsert = resource.copy();
toInsert.setAmount(maxInput);
FluidPropagator.showBlockFace(endpoint.location).colored(0x77d196).lineWidth(1/4f);
return super.fill(toInsert, action);
}
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
return super.drain(maxDrain, action);
}
public FluidStack provide() {
FluidStack heldFluid = getFluid();
if (heldFluid.isEmpty())
return heldFluid;
FluidStack copy = heldFluid.copy();
copy.setAmount(1);
return copy;
}
private int getTransferCapacity() {
return Math.min(endpoint.getTransferSpeed(true), endpoint.getTransferSpeed(false));
}
}

View file

@ -0,0 +1,172 @@
package com.simibubi.create.content.contraptions.fluids;
import javax.annotation.Nullable;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.BlockState;
import net.minecraft.block.FlowingFluidBlock;
import net.minecraft.fluid.Fluid;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.templates.FluidTank;
public class OpenEndedPipe {
World world;
private OpenEndFluidHandler fluidHandler;
private BlockPos outputPos;
private boolean wasPulling;
private boolean stale;
public OpenEndedPipe(BlockFace face) {
fluidHandler = new OpenEndFluidHandler();
outputPos = face.getConnectedPos();
}
public void tick(World world, boolean pulling) {
this.world = world;
if (!world.isAreaLoaded(outputPos, 0))
return;
if (pulling != wasPulling) {
if (pulling)
fluidHandler.clear();
wasPulling = pulling;
}
BlockState state = world.getBlockState(outputPos);
IFluidState fluidState = state.getFluidState();
boolean waterlog = state.has(BlockStateProperties.WATERLOGGED);
if (!waterlog && !state.getMaterial()
.isReplaceable())
return;
// TODO different pipe end types
if (pulling) {
if (fluidState.isEmpty() || !fluidState.isSource())
return;
if (!fluidHandler.tryCollectFluid(fluidState.getFluid()))
return;
if (waterlog) {
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, false), 3);
return;
}
world.setBlockState(outputPos, fluidState.getBlockState()
.with(FlowingFluidBlock.LEVEL, 14), 3);
return;
}
Fluid providedFluid = fluidHandler.tryProvidingFluid();
if (providedFluid == null)
return;
if (!fluidState.isEmpty() && fluidState.getFluid() != providedFluid) {
FluidReactions.handlePipeSpillCollision(world, outputPos, providedFluid, fluidState);
return;
}
if (fluidState.isSource())
return;
if (waterlog) {
if (providedFluid.getFluid() != Fluids.WATER)
return;
world.setBlockState(outputPos, state.with(BlockStateProperties.WATERLOGGED, true), 3);
return;
}
world.setBlockState(outputPos, providedFluid.getDefaultState()
.getBlockState(), 3);
}
public LazyOptional<IFluidHandler> getCapability() {
return LazyOptional.of(() -> fluidHandler);
}
public CompoundNBT writeToNBT(CompoundNBT compound) {
fluidHandler.writeToNBT(compound);
compound.putBoolean("Pulling", wasPulling);
return compound;
}
public void readNBT(CompoundNBT compound) {
fluidHandler.readFromNBT(compound);
wasPulling = compound.getBoolean("Pulling");
}
public void markStale() {
stale = true;
}
public void unmarkStale() {
stale = false;
}
public boolean isStale() {
return stale;
}
private class OpenEndFluidHandler extends FluidTank {
public OpenEndFluidHandler() {
super(1500);
}
@Override
public int fill(FluidStack resource, FluidAction action) {
// Never allow being filled when a source is attached
if (world == null)
return 0;
if (!world.isAreaLoaded(outputPos, 0))
return 0;
if (resource.isEmpty())
return 0;
BlockState state = world.getBlockState(outputPos);
IFluidState fluidState = state.getFluidState();
if (!fluidState.isEmpty() && fluidState.getFluid() != resource.getFluid()) {
FluidReactions.handlePipeSpillCollision(world, outputPos, resource.getFluid(), fluidState);
return 0;
}
if (fluidState.isSource())
return 0;
if (!(state.has(BlockStateProperties.WATERLOGGED) && resource.getFluid() == Fluids.WATER)
&& !state.getMaterial()
.isReplaceable())
return 0;
// Never allow being filled above 1000
FluidStack insertable = resource.copy();
insertable.setAmount(Math.min(insertable.getAmount(), Math.max(1000 - getFluidAmount(), 0)));
return super.fill(insertable, action);
}
public boolean tryCollectFluid(Fluid fluid) {
for (boolean simulate : Iterate.trueAndFalse)
if (super.fill(new FluidStack(fluid, 1000),
simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE) != 1000)
return false;
return true;
}
@Nullable
public Fluid tryProvidingFluid() {
Fluid fluid = getFluid().getFluid();
for (boolean simulate : Iterate.trueAndFalse)
if (drain(1000, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE).getAmount() != 1000)
return null;
return fluid;
}
public void clear() {
setFluid(FluidStack.EMPTY);
}
}
}

View file

@ -1,11 +1,15 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.simibubi.create.AllBlockPartials;
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour.AttachmentTypes;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.foundation.block.render.WrappedBakedModel;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.BlockState;
@ -18,19 +22,22 @@ import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
public class FluidPipeModel extends WrappedBakedModel {
public class PipeAttachmentModel extends WrappedBakedModel {
private static ModelProperty<PipeModelData> PIPE_PROPERTY = new ModelProperty<>();
public FluidPipeModel(IBakedModel template) {
public PipeAttachmentModel(IBakedModel template) {
super(template);
}
@Override
public IModelData getModelData(ILightReader world, BlockPos pos, BlockState state, IModelData tileData) {
PipeModelData data = new PipeModelData();
for (Direction d : Iterate.directions)
data.putRim(d, FluidPipeBlock.shouldDrawRim(world, pos, state, d));
FluidPipeAttachmentBehaviour attachmentBehaviour =
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
if (attachmentBehaviour != null)
for (Direction d : Iterate.directions)
data.putRim(d, attachmentBehaviour.getAttachment(world, pos, state, d));
data.setEncased(FluidPipeBlock.shouldDrawCasing(world, pos, state));
return new ModelDataMap.Builder().withInitial(PIPE_PROPERTY, data)
.build();
@ -41,8 +48,10 @@ public class FluidPipeModel extends WrappedBakedModel {
List<BakedQuad> quads = super.getQuads(state, side, rand, data);
if (data instanceof ModelDataMap) {
ModelDataMap modelDataMap = (ModelDataMap) data;
if (modelDataMap.hasProperty(PIPE_PROPERTY))
if (modelDataMap.hasProperty(PIPE_PROPERTY)) {
quads = new ArrayList<>(quads);
addQuads(quads, state, side, rand, modelDataMap, modelDataMap.getData(PIPE_PROPERTY));
}
}
return quads;
}
@ -50,8 +59,9 @@ public class FluidPipeModel extends WrappedBakedModel {
private void addQuads(List<BakedQuad> quads, BlockState state, Direction side, Random rand, IModelData data,
PipeModelData pipeData) {
for (Direction d : Iterate.directions)
if (pipeData.getRim(d))
quads.addAll(AllBlockPartials.PIPE_RIMS.get(d)
if (pipeData.hasRim(d))
quads.addAll(AllBlockPartials.PIPE_ATTACHMENTS.get(pipeData.getRim(d))
.get(d)
.get()
.getQuads(state, side, rand, data));
if (pipeData.isEncased())
@ -60,15 +70,15 @@ public class FluidPipeModel extends WrappedBakedModel {
}
private class PipeModelData {
boolean[] rims;
AttachmentTypes[] rims;
boolean encased;
public PipeModelData() {
rims = new boolean[6];
Arrays.fill(rims, false);
rims = new AttachmentTypes[6];
Arrays.fill(rims, AttachmentTypes.NONE);
}
public void putRim(Direction face, boolean rim) {
public void putRim(Direction face, AttachmentTypes rim) {
rims[face.getIndex()] = rim;
}
@ -76,7 +86,11 @@ public class FluidPipeModel extends WrappedBakedModel {
this.encased = encased;
}
public boolean getRim(Direction face) {
public boolean hasRim(Direction face) {
return rims[face.getIndex()] != AttachmentTypes.NONE;
}
public AttachmentTypes getRim(Direction face) {
return rims[face.getIndex()];
}

View file

@ -1,14 +1,24 @@
package com.simibubi.create.content.contraptions.fluids;
import java.util.Map;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.AllShapes;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.DirectionalKineticBlock;
import com.simibubi.create.content.contraptions.fluids.pipes.FluidPipeBlock;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemUseContext;
import net.minecraft.network.DebugPacketSender;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
@ -20,71 +30,137 @@ import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.IWorldReader;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
public class PumpBlock extends DirectionalKineticBlock implements IWaterLoggable {
public PumpBlock(Properties p_i48415_1_) {
super(p_i48415_1_);
setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
}
public PumpBlock(Properties p_i48415_1_) {
super(p_i48415_1_);
setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.MECHANICAL_PUMP.create();
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.MECHANICAL_PUMP.create();
}
@Override
public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) {
return originalState.with(FACING, originalState.get(FACING)
.getOpposite());
}
@Override
public BlockState getRotatedBlockState(BlockState originalState, Direction targetedFace) {
return originalState.with(FACING, originalState.get(FACING)
.getOpposite());
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(FACING)
.getAxis();
}
@Override
public BlockState updateAfterWrenched(BlockState newState, ItemUseContext context) {
BlockState state = super.updateAfterWrenched(newState, context);
World world = context.getWorld();
BlockPos pos = context.getPos();
if (world.isRemote)
return state;
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof PumpTileEntity))
return state;
PumpTileEntity pump = (PumpTileEntity) tileEntity;
if (pump.networks == null)
return state;
@Override
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) {
return AllShapes.PUMP.get(state.get(FACING));
}
FluidNetwork apn1 = pump.networks.get(true);
FluidNetwork apn2 = pump.networks.get(false);
@Override
public boolean hasIntegratedCogwheel(IWorldReader world, BlockPos pos, BlockState state) {
return true;
}
// Collect pipes that can be skipped
apn1.clearFlows(world, true);
apn2.clearFlows(world, true);
@Override
public IFluidState getFluidState(BlockState state) {
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false) : Fluids.EMPTY.getDefaultState();
}
// Swap skipsets as the networks change sides
Map<BlockFace, FluidStack> skippedConnections = apn1.previousFlow;
apn1.previousFlow = apn2.previousFlow;
apn2.previousFlow = skippedConnections;
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(BlockStateProperties.WATERLOGGED);
super.fillStateContainer(builder);
}
// Init networks next tick
pump.networksToUpdate.forEach(MutableBoolean::setTrue);
pump.networks.swap();
pump.reversed = !pump.reversed;
@Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
IWorld world, BlockPos pos, BlockPos neighbourPos) {
if (state.get(BlockStateProperties.WATERLOGGED)) {
world.getPendingFluidTicks().scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return state;
}
return state;
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
IFluidState ifluidstate = context.getWorld().getFluidState(context.getPos());
return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED, Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
}
@Override
public Axis getRotationAxis(BlockState state) {
return state.get(FACING)
.getAxis();
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) {
return AllShapes.PUMP.get(state.get(FACING));
}
@Override
public boolean hasIntegratedCogwheel(IWorldReader world, BlockPos pos, BlockState state) {
return true;
}
@Override
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
boolean isMoving) {
DebugPacketSender.func_218806_a(world, pos);
if (world.isRemote)
return;
if (otherBlock instanceof FluidPipeBlock)
return;
TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof PumpTileEntity))
return;
PumpTileEntity pump = (PumpTileEntity) tileEntity;
Direction facing = state.get(FACING);
for (boolean front : Iterate.trueAndFalse) {
Direction side = front ? facing : facing.getOpposite();
if (!pos.offset(side)
.equals(neighborPos))
continue;
pump.updatePipesOnSide(side);
}
}
@Override
public IFluidState getFluidState(BlockState state) {
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false)
: Fluids.EMPTY.getDefaultState();
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(BlockStateProperties.WATERLOGGED);
super.fillStateContainer(builder);
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
IWorld world, BlockPos pos, BlockPos neighbourPos) {
if (state.get(BlockStateProperties.WATERLOGGED)) {
world.getPendingFluidTicks()
.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return state;
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
IFluidState ifluidstate = context.getWorld()
.getFluidState(context.getPos());
return super.getStateForPlacement(context).with(BlockStateProperties.WATERLOGGED,
Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
}
public static boolean isPump(BlockState state) {
return state.getBlock() instanceof PumpBlock;
}
}

View file

@ -31,7 +31,7 @@ public class PumpRenderer extends KineticTileEntityRenderer {
PumpTileEntity pump = (PumpTileEntity) te;
Vec3d rotationOffset = new Vec3d(.5, 14 / 16f, .5);
BlockState blockState = te.getBlockState();
float angle = MathHelper.lerp(pump.arrowDirection.get(partialTicks), 0, 90) - 90;
float angle = MathHelper.lerp(pump.arrowDirection.getValue(partialTicks), 0, 90) - 90;
for (float yRot : new float[] { 0, 90 }) {
ms.push();
SuperByteBuffer arrow = AllBlockPartials.MECHANICAL_PUMP_ARROW.renderOn(blockState);

View file

@ -1,29 +1,380 @@
package com.simibubi.create.content.contraptions.fluids;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.gui.widgets.InterpolatedChasingValue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.mutable.MutableBoolean;
import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.BlockFace;
import com.simibubi.create.foundation.utility.Couple;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.LerpedFloat;
import com.simibubi.create.foundation.utility.LerpedFloat.Chaser;
import com.simibubi.create.foundation.utility.NBTHelper;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ILightReader;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class PumpTileEntity extends KineticTileEntity {
InterpolatedChasingValue arrowDirection;
LerpedFloat arrowDirection;
Couple<FluidNetwork> networks;
Couple<Map<BlockFace, OpenEndedPipe>> openEnds;
Couple<MutableBoolean> networksToUpdate;
boolean reversed;
FluidStack providedFluid;
public PumpTileEntity(TileEntityType<?> typeIn) {
super(typeIn);
arrowDirection = new InterpolatedChasingValue();
arrowDirection.start(1);
arrowDirection = LerpedFloat.linear()
.startWithValue(1);
networksToUpdate = Couple.create(MutableBoolean::new);
openEnds = Couple.create(HashMap::new);
setProvidedFluid(FluidStack.EMPTY);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours);
behaviours.add(new PumpAttachmentBehaviour(this));
}
@Override
public void initialize() {
super.initialize();
reversed = getSpeed() < 0;
}
@Override
public void tick() {
super.tick();
float speed = getSpeed();
if (world.isRemote) {
float speed = getSpeed();
if (speed != 0)
arrowDirection.target(Math.signum(speed));
arrowDirection.tick();
if (speed == 0)
return;
arrowDirection.chase(speed >= 0 ? 1 : -1, .5f, Chaser.EXP);
arrowDirection.tickChaser();
return;
}
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof PumpBlock))
return;
Direction face = blockState.get(PumpBlock.FACING);
MutableBoolean networkUpdated = new MutableBoolean(false);
if (networks == null) {
networks = Couple.create(new FluidNetwork(), new FluidNetwork());
networks.forEachWithContext((fn, front) -> {
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
fn.assemble(world, this, blockFace);
FluidPropagator.showBlockFace(blockFace)
.lineWidth(1 / 8f);
});
networkUpdated.setTrue();
}
networksToUpdate.forEachWithContext((update, front) -> {
if (update.isFalse())
return;
FluidNetwork activePipeNetwork = networks.get(front);
if (activePipeNetwork == null)
return;
BlockFace blockFace = new BlockFace(pos, front ? face : face.getOpposite());
activePipeNetwork.reAssemble(world, this, blockFace);
FluidPropagator.showBlockFace(blockFace)
.lineWidth(1 / 8f);
update.setFalse();
networkUpdated.setTrue();
});
if (networkUpdated.isTrue())
return;
networks.forEach(fn -> fn.tick(world, this));
if (speed == 0)
return;
if (speed < 0 != reversed) {
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, true));
reversed = speed < 0;
return;
}
boolean pullingSide = isPullingOnSide(true);
float flowSpeed = Math.abs(speed) / 256f;
networks.forEachWithContext((fn, front) -> {
boolean pulling = isPullingOnSide(front);
fn.tickFlows(world, this, pulling, flowSpeed);
openEnds.get(front)
.values()
.forEach(oep -> oep.tick(world, pulling));
});
if (!networks.get(pullingSide)
.hasEndpoints()) {
setProvidedFluid(FluidStack.EMPTY);
return;
}
if (networks.getFirst()
.hasEndpoints()
&& networks.getSecond()
.hasEndpoints()) {
performTransfer();
}
}
@Override
public void remove() {
super.remove();
if (networks != null)
networks.forEachWithContext((fn, current) -> fn.clearFlows(world, false));
}
private void performTransfer() {
boolean input = isPullingOnSide(true);
Collection<FluidNetworkEndpoint> inputs = networks.get(input)
.getEndpoints(true);
Collection<FluidNetworkEndpoint> outputs = networks.get(!input)
.getEndpoints(false);
int flowSpeed = getFluidTransferSpeed();
FluidStack transfer = FluidStack.EMPTY;
for (boolean simulate : Iterate.trueAndFalse) {
FluidAction action = simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE;
List<FluidNetworkEndpoint> availableInputs = new ArrayList<>(inputs);
while (!availableInputs.isEmpty() && transfer.getAmount() < flowSpeed) {
int diff = flowSpeed - transfer.getAmount();
int dividedTransfer = diff / availableInputs.size();
int remainder = diff % availableInputs.size();
for (Iterator<FluidNetworkEndpoint> iterator = availableInputs.iterator(); iterator.hasNext();) {
int toTransfer = dividedTransfer;
if (remainder > 0) {
toTransfer++;
remainder--;
}
FluidNetworkEndpoint ne = iterator.next();
IFluidHandler handler = ne.provideHandler()
.orElse(null);
if (handler == null) {
iterator.remove();
continue;
}
FluidStack drained = handler.drain(toTransfer, action);
if (drained.isEmpty()) {
iterator.remove();
continue;
}
if (transfer.isFluidEqual(drained) || transfer.isEmpty()) {
if (drained.getAmount() < toTransfer)
iterator.remove();
FluidStack copy = drained.copy();
copy.setAmount(drained.getAmount() + transfer.getAmount());
transfer = copy;
continue;
}
iterator.remove();
continue;
}
}
List<FluidNetworkEndpoint> availableOutputs = new ArrayList<>(outputs);
while (!availableOutputs.isEmpty() && transfer.getAmount() > 0) {
int dividedTransfer = transfer.getAmount() / availableOutputs.size();
int remainder = transfer.getAmount() % availableOutputs.size();
for (Iterator<FluidNetworkEndpoint> iterator = availableOutputs.iterator(); iterator.hasNext();) {
FluidNetworkEndpoint ne = iterator.next();
int toTransfer = dividedTransfer;
if (remainder > 0) {
toTransfer++;
remainder--;
}
if (transfer.isEmpty())
break;
IFluidHandler handler = ne.provideHandler()
.orElse(null);
if (handler == null) {
iterator.remove();
continue;
}
FluidStack divided = transfer.copy();
divided.setAmount(toTransfer);
int fill = handler.fill(divided, action);
transfer.setAmount(transfer.getAmount() - fill);
if (fill < toTransfer)
iterator.remove();
}
}
flowSpeed -= transfer.getAmount();
transfer = FluidStack.EMPTY;
}
}
public int getFluidTransferSpeed() {
float rotationSpeed = Math.abs(getSpeed());
int flowSpeed = (int) (rotationSpeed / 2f);
if (rotationSpeed != 0 && flowSpeed == 0)
flowSpeed = 1;
return flowSpeed;
}
@Override
public void write(CompoundNBT compound, boolean clientPacket) {
compound.putBoolean("Reversed", reversed);
serializeOpenEnds(compound);
super.write(compound, clientPacket);
}
@Override
protected void read(CompoundNBT compound, boolean clientPacket) {
reversed = compound.getBoolean("Reversed");
deserializeOpenEnds(compound);
super.read(compound, clientPacket);
}
public void updatePipesOnSide(Direction side) {
if (!isSideAccessible(side))
return;
updatePipeNetwork(isFront(side));
}
protected boolean isFront(Direction side) {
if (networks == null)
return false;
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof PumpBlock))
return false;
Direction front = blockState.get(PumpBlock.FACING);
boolean isFront = side == front;
return isFront;
}
protected void updatePipeNetwork(boolean front) {
if (networks != null)
networks.get(front)
.clearFlows(world, true);
networksToUpdate.get(front)
.setTrue();
if (getSpeed() == 0 || (isPullingOnSide(front)) && networks != null)
setProvidedFluid(FluidStack.EMPTY);
}
public boolean isSideAccessible(Direction side) {
BlockState blockState = getBlockState();
if (!(blockState.getBlock() instanceof PumpBlock))
return false;
return blockState.get(PumpBlock.FACING)
.getAxis() == side.getAxis();
}
public boolean isPullingOnSide(boolean front) {
return front == reversed;
}
public Map<BlockFace, OpenEndedPipe> getOpenEnds(Direction side) {
return openEnds.get(isFront(side));
}
private void serializeOpenEnds(CompoundNBT compound) {
compound.put("OpenEnds", openEnds.serializeEach(m -> {
CompoundNBT compoundNBT = new CompoundNBT();
ListNBT entries = new ListNBT();
m.entrySet()
.forEach(e -> {
CompoundNBT innerCompound = new CompoundNBT();
innerCompound.put("Pos", e.getKey()
.serializeNBT());
e.getValue()
.writeToNBT(innerCompound);
entries.add(innerCompound);
});
compoundNBT.put("Entries", entries);
return compoundNBT;
}));
}
private void deserializeOpenEnds(CompoundNBT compound) {
openEnds = Couple.deserializeEach(compound.getList("OpenEnds", NBT.TAG_COMPOUND), c -> {
Map<BlockFace, OpenEndedPipe> map = new HashMap<>();
NBTHelper.iterateCompoundList(c.getList("Entries", NBT.TAG_COMPOUND), innerCompound -> {
BlockFace key = BlockFace.fromNBT(innerCompound.getCompound("Pos"));
OpenEndedPipe value = new OpenEndedPipe(key);
value.readNBT(innerCompound);
map.put(key, value);
});
return map;
});
compound.put("OpenEnds", openEnds.serializeEach(m -> {
CompoundNBT compoundNBT = new CompoundNBT();
ListNBT entries = new ListNBT();
m.entrySet()
.forEach(e -> {
CompoundNBT innerCompound = new CompoundNBT();
innerCompound.put("Pos", e.getKey()
.serializeNBT());
e.getValue()
.writeToNBT(innerCompound);
entries.add(innerCompound);
});
compoundNBT.put("Entries", entries);
return compoundNBT;
}));
}
public void setProvidedFluid(FluidStack providedFluid) {
this.providedFluid = providedFluid;
}
class PumpAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
public PumpAttachmentBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public boolean isPipeConnectedTowards(BlockState state, Direction direction) {
return isSideAccessible(direction);
}
@Override
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
if (attachment == AttachmentTypes.RIM)
return AttachmentTypes.NONE;
return attachment;
}
}
}

View file

@ -0,0 +1,97 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import java.util.Map;
import java.util.Random;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.RotatedPillarBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.network.DebugPacketSender;
import net.minecraft.state.BooleanProperty;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.TickPriority;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public class AxisPipeBlock extends RotatedPillarBlock implements IWrenchable {
public AxisPipeBlock(Properties p_i48339_1_) {
super(p_i48339_1_);
}
@Override
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
boolean blockTypeChanged = state.getBlock() != newState.getBlock();
if (blockTypeChanged && !world.isRemote)
FluidPropagator.propagateChangedPipe(world, pos, state);
if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity()))
world.removeTileEntity(pos);
}
@Override
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) {
if (world.isRemote)
return;
if (state != oldState)
world.getPendingBlockTicks()
.scheduleTick(pos, this, 1, TickPriority.HIGH);
}
@Override
public ItemStack getPickBlock(BlockState state, RayTraceResult target, IBlockReader world, BlockPos pos,
PlayerEntity player) {
return AllBlocks.FLUID_PIPE.asStack();
}
@Override
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
boolean isMoving) {
DebugPacketSender.func_218806_a(world, pos);
Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving);
if (d == null)
return;
if (!isOpenAt(state, d))
return;
world.getPendingBlockTicks()
.scheduleTick(pos, this, 1, TickPriority.HIGH);
}
public static boolean isOpenAt(BlockState state, Direction d) {
return d.getAxis() == state.get(AXIS);
}
@Override
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
FluidPropagator.propagateChangedPipe(world, pos, state);
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) {
return AllShapes.EIGHT_VOXEL_POLE.get(state.get(AXIS));
}
public BlockState toRegularPipe(IWorld world, BlockPos pos, BlockState state) {
Direction side = Direction.getFacingFromAxis(AxisDirection.POSITIVE, state.get(AXIS));
Map<Direction, BooleanProperty> facingToPropertyMap = FluidPipeBlock.FACING_TO_PROPERTY_MAP;
return AllBlocks.FLUID_PIPE.get()
.updateBlockState(AllBlocks.FLUID_PIPE.getDefaultState()
.with(facingToPropertyMap.get(side), true)
.with(facingToPropertyMap.get(side.getOpposite()), true), side, null, world, pos);
}
}

View file

@ -0,0 +1,46 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import com.simibubi.create.AllTileEntities;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemUseContext;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.util.math.shapes.VoxelShapes;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class EncasedPipeBlock extends AxisPipeBlock {
public EncasedPipeBlock(Properties p_i48339_1_) {
super(p_i48339_1_);
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.ENCASED_FLUID_PIPE.create();
}
@Override
public VoxelShape getShape(BlockState state, IBlockReader p_220053_2_, BlockPos p_220053_3_,
ISelectionContext p_220053_4_) {
return VoxelShapes.fullCube();
}
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
World world = context.getWorld();
BlockPos pos = context.getPos();
world.setBlockState(pos, toRegularPipe(world, pos, state), 3);
return ActionResultType.SUCCESS;
}
}

View file

@ -0,0 +1,248 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import java.util.Random;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
import com.simibubi.create.content.contraptions.fluids.FluidPropagator;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.IWaterLoggable;
import net.minecraft.block.SixWayBlock;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.fluid.Fluids;
import net.minecraft.fluid.IFluidState;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.item.ItemUseContext;
import net.minecraft.network.DebugPacketSender;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.Axis;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.ILightReader;
import net.minecraft.world.IWorld;
import net.minecraft.world.TickPriority;
import net.minecraft.world.World;
import net.minecraft.world.server.ServerWorld;
public class FluidPipeBlock extends SixWayBlock implements IWaterLoggable, IWrenchable {
public FluidPipeBlock(Properties properties) {
super(4 / 16f, properties);
this.setDefaultState(super.getDefaultState().with(BlockStateProperties.WATERLOGGED, false));
}
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
World world = context.getWorld();
BlockPos pos = context.getPos();
Axis axis = getAxis(world, pos, state);
if (axis == null)
return ActionResultType.PASS;
if (context.getFace()
.getAxis() == axis)
return ActionResultType.PASS;
if (!world.isRemote)
world.setBlockState(pos, AllBlocks.GLASS_FLUID_PIPE.getDefaultState()
.with(GlassFluidPipeBlock.AXIS, axis));
return ActionResultType.SUCCESS;
}
@Override
public ActionResultType onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand,
BlockRayTraceResult hit) {
if (!AllBlocks.COPPER_CASING.isIn(player.getHeldItem(hand)))
return ActionResultType.PASS;
Axis axis = getAxis(world, pos, state);
if (axis == null)
return ActionResultType.PASS;
if (!world.isRemote)
world.setBlockState(pos, AllBlocks.ENCASED_FLUID_PIPE.getDefaultState()
.with(EncasedPipeBlock.AXIS, axis));
return ActionResultType.SUCCESS;
}
@Nullable
private Axis getAxis(IBlockReader world, BlockPos pos, BlockState state) {
if (!FluidPropagator.isStraightPipe(state))
return null;
Axis axis = null;
for (Direction d : Iterate.directions) {
if (isOpenAt(state, d)) {
axis = d.getAxis();
break;
}
}
return axis;
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.FLUID_PIPE.create();
}
@Override
public void onReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean isMoving) {
boolean blockTypeChanged = state.getBlock() != newState.getBlock();
if (blockTypeChanged && !world.isRemote)
FluidPropagator.propagateChangedPipe(world, pos, state);
if (state.hasTileEntity() && (blockTypeChanged || !newState.hasTileEntity()))
world.removeTileEntity(pos);
}
@Override
public void onBlockAdded(BlockState state, World world, BlockPos pos, BlockState oldState, boolean isMoving) {
if (world.isRemote)
return;
if (state != oldState)
world.getPendingBlockTicks()
.scheduleTick(pos, this, 1, TickPriority.HIGH);
}
@Override
public void neighborChanged(BlockState state, World world, BlockPos pos, Block otherBlock, BlockPos neighborPos,
boolean isMoving) {
DebugPacketSender.func_218806_a(world, pos);
Direction d = FluidPropagator.validateNeighbourChange(state, world, pos, otherBlock, neighborPos, isMoving);
if (d == null)
return;
if (!isOpenAt(state, d))
return;
world.getPendingBlockTicks()
.scheduleTick(pos, this, 1, TickPriority.HIGH);
}
@Override
public void scheduledTick(BlockState state, ServerWorld world, BlockPos pos, Random r) {
FluidPropagator.propagateChangedPipe(world, pos, state);
}
public static boolean isPipe(BlockState state) {
return state.getBlock() instanceof FluidPipeBlock;
}
public static boolean canConnectTo(ILightReader world, BlockPos pos, BlockState neighbour, Direction blockFace) {
if (isPipe(neighbour) || FluidPropagator.hasFluidCapability(neighbour, world, pos, blockFace))
return true;
FluidPipeAttachmentBehaviour attachmentBehaviour =
TileEntityBehaviour.get(world, pos, FluidPipeAttachmentBehaviour.TYPE);
if (attachmentBehaviour == null)
return false;
return attachmentBehaviour.isPipeConnectedTowards(neighbour, blockFace.getOpposite());
}
public static boolean shouldDrawRim(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
BlockPos offsetPos = pos.offset(direction);
BlockState facingState = world.getBlockState(offsetPos);
if (!isPipe(facingState))
return true;
if (!isCornerOrEndPipe(world, pos, state))
return false;
if (FluidPropagator.isStraightPipe(facingState))
return true;
if (!shouldDrawCasing(world, pos, state) && shouldDrawCasing(world, offsetPos, facingState))
return true;
if (isCornerOrEndPipe(world, offsetPos, facingState))
return direction.getAxisDirection() == AxisDirection.POSITIVE;
return true;
}
public static boolean isOpenAt(BlockState state, Direction direction) {
return state.get(FACING_TO_PROPERTY_MAP.get(direction));
}
public static boolean isCornerOrEndPipe(ILightReader world, BlockPos pos, BlockState state) {
return isPipe(state) && !FluidPropagator.isStraightPipe(state) && !shouldDrawCasing(world, pos, state);
}
public static boolean shouldDrawCasing(ILightReader world, BlockPos pos, BlockState state) {
if (!isPipe(state))
return false;
for (Axis axis : Iterate.axes) {
int connections = 0;
for (Direction direction : Iterate.directions)
if (direction.getAxis() != axis && isOpenAt(state, direction))
connections++;
if (connections > 2)
return true;
}
return false;
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> builder) {
builder.add(NORTH, EAST, SOUTH, WEST, UP, DOWN, BlockStateProperties.WATERLOGGED);
super.fillStateContainer(builder);
}
@Override
public BlockState getStateForPlacement(BlockItemUseContext context) {
IFluidState ifluidstate = context.getWorld()
.getFluidState(context.getPos());
return updateBlockState(getDefaultState(), context.getNearestLookingDirection(), null, context.getWorld(),
context.getPos()).with(BlockStateProperties.WATERLOGGED,
Boolean.valueOf(ifluidstate.getFluid() == Fluids.WATER));
}
@Override
public BlockState updatePostPlacement(BlockState state, Direction direction, BlockState neighbourState,
IWorld world, BlockPos pos, BlockPos neighbourPos) {
if (state.get(BlockStateProperties.WATERLOGGED)) {
world.getPendingFluidTicks()
.scheduleTick(pos, Fluids.WATER, Fluids.WATER.getTickRate(world));
}
return updateBlockState(state, direction, direction.getOpposite(), world, pos);
}
public BlockState updateBlockState(BlockState state, Direction preferredDirection, @Nullable Direction ignore,
ILightReader world, BlockPos pos) {
// Update sides that are not ignored
for (Direction d : Iterate.directions)
if (d != ignore)
state = state.with(FACING_TO_PROPERTY_MAP.get(d),
canConnectTo(world, pos.offset(d), world.getBlockState(pos.offset(d)), d.getOpposite()));
// See if it has enough connections
Direction connectedDirection = null;
for (Direction d : Iterate.directions) {
if (isOpenAt(state, d)) {
if (connectedDirection != null)
return state;
connectedDirection = d;
}
}
// Add opposite end if only one connection
if (connectedDirection != null)
return state.with(FACING_TO_PROPERTY_MAP.get(connectedDirection.getOpposite()), true);
// Use preferred
return state.with(FACING_TO_PROPERTY_MAP.get(preferredDirection), true)
.with(FACING_TO_PROPERTY_MAP.get(preferredDirection.getOpposite()), true);
}
@Override
public IFluidState getFluidState(BlockState state) {
return state.get(BlockStateProperties.WATERLOGGED) ? Fluids.WATER.getStillFluidState(false)
: Fluids.EMPTY.getDefaultState();
}
}

View file

@ -0,0 +1,67 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import java.util.List;
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ILightReader;
public class FluidPipeTileEntity extends SmartTileEntity {
public FluidPipeTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new StandardPipeBehaviour(this));
behaviours.add(new StandardPipeAttachmentBehaviour(this));
}
class StandardPipeBehaviour extends FluidPipeBehaviour {
public StandardPipeBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public boolean isConnectedTo(BlockState state, Direction direction) {
return FluidPipeBlock.isPipe(state) && state.get(FluidPipeBlock.FACING_TO_PROPERTY_MAP.get(direction));
}
}
class StandardPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
public StandardPipeAttachmentBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
BlockPos offsetPos = pos.offset(direction);
if (!FluidPipeBlock.isPipe(world.getBlockState(offsetPos))) {
FluidPipeAttachmentBehaviour attachmentBehaviour =
TileEntityBehaviour.get(world, offsetPos, FluidPipeAttachmentBehaviour.TYPE);
if (attachmentBehaviour != null && attachmentBehaviour
.isPipeConnectedTowards(world.getBlockState(offsetPos), direction.getOpposite()))
return AttachmentTypes.NONE;
}
if (attachment == AttachmentTypes.RIM && !FluidPipeBlock.shouldDrawRim(world, pos, state, direction))
return AttachmentTypes.NONE;
return attachment;
}
}
}

View file

@ -0,0 +1,54 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import com.simibubi.create.AllTileEntities;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.item.ItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.StateContainer.Builder;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ActionResultType;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
public class GlassFluidPipeBlock extends AxisPipeBlock {
public static final BooleanProperty ALT = BooleanProperty.create("alt");
public GlassFluidPipeBlock(Properties p_i48339_1_) {
super(p_i48339_1_);
setDefaultState(getDefaultState().with(ALT, false));
}
@Override
protected void fillStateContainer(Builder<Block, BlockState> p_206840_1_) {
super.fillStateContainer(p_206840_1_.add(ALT));
}
@Override
public boolean hasTileEntity(BlockState state) {
return true;
}
@Override
public TileEntity createTileEntity(BlockState state, IBlockReader world) {
return AllTileEntities.GLASS_FLUID_PIPE.create();
}
@Override
public ActionResultType onWrenched(BlockState state, ItemUseContext context) {
BlockState newState = state;
World world = context.getWorld();
BlockPos pos = context.getPos();
if (!state.get(ALT))
newState = state.with(ALT, true);
else
newState = toRegularPipe(world, pos, state);
world.setBlockState(pos, newState, 3);
return ActionResultType.SUCCESS;
}
}

View file

@ -0,0 +1,64 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import java.util.List;
import com.simibubi.create.content.contraptions.fluids.FluidPipeAttachmentBehaviour;
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import net.minecraft.block.BlockState;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.Direction.AxisDirection;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.ILightReader;
public class StraightPipeTileEntity extends SmartTileEntity {
public StraightPipeTileEntity(TileEntityType<?> tileEntityTypeIn) {
super(tileEntityTypeIn);
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {
behaviours.add(new StraightPipeBehaviour(this));
behaviours.add(new StraightPipeAttachmentBehaviour(this));
}
class StraightPipeBehaviour extends FluidPipeBehaviour {
public StraightPipeBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public boolean isConnectedTo(BlockState state, Direction direction) {
return state.get(AxisPipeBlock.AXIS) == direction.getAxis();
}
}
class StraightPipeAttachmentBehaviour extends FluidPipeAttachmentBehaviour {
public StraightPipeAttachmentBehaviour(SmartTileEntity te) {
super(te);
}
@Override
public AttachmentTypes getAttachment(ILightReader world, BlockPos pos, BlockState state, Direction direction) {
AttachmentTypes attachment = super.getAttachment(world, pos, state, direction);
BlockState otherState = world.getBlockState(pos.offset(direction));
if (state.getBlock() instanceof AxisPipeBlock && otherState.getBlock() instanceof AxisPipeBlock) {
if (state.get(AxisPipeBlock.AXIS) == otherState.get(AxisPipeBlock.AXIS)) {
if (state.getBlock() == otherState.getBlock()
|| direction.getAxisDirection() == AxisDirection.POSITIVE)
return AttachmentTypes.NONE;
}
}
return attachment;
}
}
}

View file

@ -0,0 +1,59 @@
package com.simibubi.create.content.contraptions.fluids.pipes;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.simibubi.create.content.contraptions.fluids.FluidPipeBehaviour;
import com.simibubi.create.foundation.fluid.FluidRenderer;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.renderer.SafeTileEntityRenderer;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.LerpedFloat;
import com.simibubi.create.foundation.utility.Pair;
import net.minecraft.client.renderer.IRenderTypeBuffer;
import net.minecraft.client.renderer.tileentity.TileEntityRendererDispatcher;
import net.minecraft.util.Direction;
import net.minecraftforge.fluids.FluidStack;
public class TransparentStraightPipeRenderer extends SafeTileEntityRenderer<StraightPipeTileEntity> {
public TransparentStraightPipeRenderer(TileEntityRendererDispatcher dispatcher) {
super(dispatcher);
}
@Override
protected void renderSafe(StraightPipeTileEntity te, float partialTicks, MatrixStack ms, IRenderTypeBuffer buffer,
int light, int overlay) {
FluidPipeBehaviour pipe = TileEntityBehaviour.get(te, FluidPipeBehaviour.TYPE);
if (pipe == null)
return;
FluidStack fluidStack = pipe.getFluid();
if (fluidStack.isEmpty())
return;
for (Direction side : Iterate.directions) {
if (!pipe.isConnectedTo(te.getBlockState(), side))
continue;
Pair<Boolean, LerpedFloat> strogestFlow = pipe.getStrogestFlow(side);
if (strogestFlow == null)
continue;
LerpedFloat second = strogestFlow.getSecond();
if (second == null)
continue;
float value = second.getValue(partialTicks);
Boolean inbound = strogestFlow.getFirst();
if (value == 1 && !inbound) {
FluidPipeBehaviour adjacent = TileEntityBehaviour.get(te.getWorld(), te.getPos()
.offset(side), FluidPipeBehaviour.TYPE);
if (adjacent != null && adjacent.getFluid()
.isEmpty())
value -= 1e-6f;
}
FluidRenderer.renderFluidStream(fluidStack, side, 3 / 16f, value, inbound, buffer, ms, light);
}
}
}

View file

@ -1,4 +1,4 @@
package com.simibubi.create.content.contraptions.fluids;
package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
@ -182,7 +182,7 @@ public class FluidTankBlock extends Block implements IWrenchable, ITE<FluidTankT
return ActionResultType.SUCCESS;
}
controllerTE.sendData();
controllerTE.sendDataImmediately();
controllerTE.markDirty();
}
}

View file

@ -1,4 +1,4 @@
package com.simibubi.create.content.contraptions.fluids;
package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.foundation.block.connected.CTSpriteShiftEntry;
import com.simibubi.create.foundation.block.connected.HorizontalCTBehaviour;

View file

@ -1,4 +1,4 @@
package com.simibubi.create.content.contraptions.fluids;
package com.simibubi.create.content.contraptions.fluids.tank;
import java.util.ArrayList;
import java.util.Comparator;
@ -276,6 +276,7 @@ public class FluidTankConnectivityHandler {
}
}
te.fluidCapability.invalidate();
if (tryReconnect)
formTanks(world, cache == null ? new TankSearchCache() : cache, frontier);
}

View file

@ -1,6 +1,6 @@
package com.simibubi.create.content.contraptions.fluids;
package com.simibubi.create.content.contraptions.fluids.tank;
import com.simibubi.create.content.contraptions.fluids.FluidTankBlock.Shape;
import com.simibubi.create.content.contraptions.fluids.tank.FluidTankBlock.Shape;
import com.simibubi.create.foundation.data.AssetLookup;
import com.simibubi.create.foundation.data.SpecialBlockStateGen;
import com.tterrag.registrate.providers.DataGenContext;

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