Merge branch 'mc1.18/copycat' into mc1.18/0.5.1

This commit is contained in:
simibubi 2022-10-21 22:04:42 +02:00
commit da5b752e1f
61 changed files with 1934 additions and 80 deletions

View file

@ -63,6 +63,9 @@ a87097f3a092264d9b74966ee9e3bcfc0b743f80 assets/create/blockstates/copper_tile_s
1cc9cdcd48ea76fe3407dce0973220ff9f63f51a assets/create/blockstates/copper_tile_stairs.json
cbae7653d6a6f2d98370e9a4a3bd91fdb529f89d assets/create/blockstates/copper_tiles.json
543af282e2cb44f00509d850814b4501f3491d48 assets/create/blockstates/copper_valve_handle.json
22a91cc73d6b492dddd9354693b873701fb82c01 assets/create/blockstates/copycat_base.json
f4d185b9eb086e5024a9818bad57d524267d6e13 assets/create/blockstates/copycat_panel.json
f4d185b9eb086e5024a9818bad57d524267d6e13 assets/create/blockstates/copycat_step.json
b759be6f47fb960a7757b70d194921a38261c90a assets/create/blockstates/creative_crate.json
da3f1203dd0b0096ce19e09705060a0ed0478bee assets/create/blockstates/creative_fluid_tank.json
f0031f5e970b3d5695472ed384950b8631b015ed assets/create/blockstates/creative_motor.json
@ -562,24 +565,24 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo
5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json
7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json
b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json
29da6f08028cfed0f311c8073d7615d6821aaee6 assets/create/lang/en_ud.json
0070b8f388464c998ebdec0dd9ed00f95910922b assets/create/lang/en_us.json
819a773dac8b804a497bc798aa5b60011de1f736 assets/create/lang/unfinished/de_de.json
ed149274800dbc226bdc3dc0ba5f37fd5aff7e9a assets/create/lang/unfinished/es_cl.json
59ba35103b2ec6b30b00c38e6410994eb1050a06 assets/create/lang/unfinished/es_es.json
27463977eae36ec876a0a298885f606297c971c1 assets/create/lang/unfinished/fr_fr.json
b8f760ee53958b6193350c82a0ad6ec4df0116d9 assets/create/lang/unfinished/it_it.json
766d570603a8cb1475002045db8976d7bfae72f1 assets/create/lang/unfinished/ja_jp.json
5d585d77810a3bc6b4247eff5a08f0a85fcc0e7c assets/create/lang/unfinished/ko_kr.json
1275ee80cc65b49a77c26dbbd3bfba9eac762ead assets/create/lang/unfinished/nl_nl.json
9c2210faa1a598567c9b8c6e0529183227afd8de assets/create/lang/unfinished/pl_pl.json
4e07b14961b64aa05a60193335663a4ea2cbe4ef assets/create/lang/unfinished/pt_br.json
4f27ff82d89d4b25b3cc237118611c385b6bedd9 assets/create/lang/unfinished/pt_pt.json
3b76d014cacd40e53e1f8f10545a133e2289ebc7 assets/create/lang/unfinished/ro_ro.json
b315407f620e95f376e4b0aab5cc6755c6410227 assets/create/lang/unfinished/ru_ru.json
5ec15854ee92e6e463341b226da3682f213ad7a5 assets/create/lang/unfinished/uk_ua.json
1be5b9da89c4f22421bda20eae909f69dd8f7554 assets/create/lang/unfinished/zh_cn.json
df88975ac97350e6f77355c053f853f14d867ecb assets/create/lang/unfinished/zh_tw.json
3054a5519fbf91481b0c9c8160a20679fa9530da assets/create/lang/en_ud.json
c57c7f223e483ec45f7b94a33582f2bf66c4cf60 assets/create/lang/en_us.json
4080736502d1f2367ae70d9aae33ca0314db5bd9 assets/create/lang/unfinished/de_de.json
76227addfbcb0cb33c6851fdcc915b774493b801 assets/create/lang/unfinished/es_cl.json
2cce9e6ef650c78c594d62b96cd3f976dc2affec assets/create/lang/unfinished/es_es.json
ffd78f1c2269cfc95c9cddb81f98500451f1e249 assets/create/lang/unfinished/fr_fr.json
7da0e0a81888382ef09808dc26a0acc00981bfc5 assets/create/lang/unfinished/it_it.json
777e9fcbd341e8b7c1a76400f384a7892cebd84f assets/create/lang/unfinished/ja_jp.json
3efd5341a65b265b015caff7756c93a9e62e24b2 assets/create/lang/unfinished/ko_kr.json
d69eb7e9ada984144b84adcaa66bd58d34392f93 assets/create/lang/unfinished/nl_nl.json
ef1d3c48c5b29618c7c03b862cb414450f61b2b4 assets/create/lang/unfinished/pl_pl.json
fd304a1b08cb1a26a71bf14e03427f3ea347b851 assets/create/lang/unfinished/pt_br.json
02c1b9461cf73901e7c524970fb70bc27cbeb805 assets/create/lang/unfinished/pt_pt.json
5e55fe730dadb7c4cb5f8cac65dd2288c3fc8349 assets/create/lang/unfinished/ro_ro.json
ab0235e297d83f14990c9c11c9ea494cb725c082 assets/create/lang/unfinished/ru_ru.json
2dcd9d1659d59f399b44b2d0e0e7428e248cafca assets/create/lang/unfinished/uk_ua.json
1ec8b3397df54e2af39e3e52c1ffb7c0a11a3b8b assets/create/lang/unfinished/zh_cn.json
6b2ccb147e70ae407da8686b5b989991a11bd802 assets/create/lang/unfinished/zh_tw.json
487a511a01b2a4531fb672f917922312db78f958 assets/create/models/block/acacia_window.json
b48060cba1a382f373a05bf0039054053eccf076 assets/create/models/block/acacia_window_pane_noside.json
3066db1bf03cffa1a9c7fbacf47ae586632f4eb3 assets/create/models/block/acacia_window_pane_noside_alt.json
@ -1697,6 +1700,8 @@ ecaea6626101acc4c655a33e2148c336bfde9895 assets/create/models/item/copper_shingl
0f6e8e2ff3543fd0b076da64fa2cf8c2bfd017e9 assets/create/models/item/copper_tile_stairs.json
532d2c60de6129082b7ff5a713e9a70d89078f58 assets/create/models/item/copper_tiles.json
5583368909c319acfcf0f7a419bedf23272fe613 assets/create/models/item/copper_valve_handle.json
d17c8d4e1daf2e128254ee6897585c5d84902433 assets/create/models/item/copycat_panel.json
aa1b9e74076d71cd096e057dc752023b2bf1d994 assets/create/models/item/copycat_step.json
4e253e7c0626dfd76e2d39786ce1a34e0baaa62d assets/create/models/item/crafter_slot_cover.json
1f947dafff30da701b7675f5b026ccab3129b079 assets/create/models/item/crafting_blueprint.json
db68f1fcc5b91f3ee0cc023538d965d76dd13506 assets/create/models/item/creative_blaze_cake.json
@ -3450,6 +3455,9 @@ dccfbda7fd3a7a75c323dea619d8d309ae980469 data/create/loot_tables/blocks/copper_s
8abac40a29800a0ca18c50ec8ce346cad15ad47a data/create/loot_tables/blocks/copper_tile_stairs.json
3eddbc442b37ba3bb309eaf26c2f4ad06de40df7 data/create/loot_tables/blocks/copper_tiles.json
6430f776846393ab6d70d23faeccb3e353c66129 data/create/loot_tables/blocks/copper_valve_handle.json
5c1df8443043b3fe3b665dba348e2ff188bcbe31 data/create/loot_tables/blocks/copycat_base.json
565441b809ded4218e69abd88bf26abee763ca08 data/create/loot_tables/blocks/copycat_panel.json
3f3df2ffc1efb1492a2a42c1eff14e5cad06b6f5 data/create/loot_tables/blocks/copycat_step.json
24f8cf0606fda07ecc26970f9aeb3f9da75e9a8f data/create/loot_tables/blocks/creative_crate.json
02efe9913be9d546c73f89e29016abf486c25f39 data/create/loot_tables/blocks/creative_fluid_tank.json
ea6580ed7d1b08ec10838bff7fa46b907e981277 data/create/loot_tables/blocks/creative_motor.json
@ -5641,11 +5649,13 @@ ac265a674626e0e832330086fd18fe0be37fc327 data/create/recipes/weathered_copper_ti
5942a571f79c40524bbf408775cf91de4715f2b6 data/create/recipes/weathered_copper_tile_stairs_from_weathered_copper_tiles_stonecutting.json
2d549ea56fb226c0e31e66c0391996093f8bece9 data/create/tags/blocks/brittle.json
d99d5c67bdffff60789a19bd51a5c5267c75e0a4 data/create/tags/blocks/casing.json
bc203f09dd7f48965d146d0bd035fb904cb75e7d data/create/tags/blocks/copycat_allow.json
d4a3b66f4b763b9a2dcdea74b7273f0ae85cb335 data/create/tags/blocks/copycat_deny.json
443f75adbf3d2f6fb0aad4b344372669470065b8 data/create/tags/blocks/fan_transparent.json
6e5d3b2123fbb00e7f439c091623619502551bca data/create/tags/blocks/non_movable.json
10781e8cfcbb3486327aace3aa00e437fb44b331 data/create/tags/blocks/ore_override_stone.json
418c6da531d6206e3cbe4049dce3db23c4270bed data/create/tags/blocks/passive_boiler_heaters.json
74f4ba5f6f61c30e27947c6fb4557e888d018285 data/create/tags/blocks/safe_nbt.json
3492722cffa53b96d7a91f8c04d792329d902c85 data/create/tags/blocks/safe_nbt.json
6cdeeac1689f7b5bfd9bc40b462143d8eaf3ad0b data/create/tags/blocks/seats.json
d063e12c9ef75f39518c6d129ea35d833464d547 data/create/tags/blocks/toolboxes.json
8861f982c335a1f17796df4af53a7d5dc91fc85a data/create/tags/blocks/tree_attachments.json
@ -5740,8 +5750,8 @@ e16d74571ae10007f06f3b86ddf05d3ca9b73559 data/minecraft/tags/blocks/doors.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/dripstone_replaceable_blocks.json
69f596fcb065e26b02ce246760432b5174191b76 data/minecraft/tags/blocks/impermeable.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/lush_ground_replaceable.json
f1d3b91aab8ea3c59a06b8ccc1a469b3ef953220 data/minecraft/tags/blocks/mineable/axe.json
53541d9dce5cf1462da568b9bde5a11d8fbe24b7 data/minecraft/tags/blocks/mineable/pickaxe.json
a8662d145a8b1b5faa263c2aac9d12e7727c8c3f data/minecraft/tags/blocks/mineable/axe.json
6f18f0d6fe0e4204079cbf9c7b6dc79c8cebcaa9 data/minecraft/tags/blocks/mineable/pickaxe.json
2db7759fe036160c14c6ed19a68604ca16f4de60 data/minecraft/tags/blocks/moss_replaceable.json
e157c1d3af30e409e34bbefbe15a037e6e1c8daa data/minecraft/tags/blocks/needs_iron_tool.json
a08f67865337f62601c5e333b4011382d10020e4 data/minecraft/tags/blocks/needs_stone_tool.json

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "create:block/copycat_base/block"
}
}
}

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "minecraft:block/air"
}
}
}

View file

@ -0,0 +1,7 @@
{
"variants": {
"": {
"model": "minecraft:block/air"
}
}
}

View file

@ -64,6 +64,9 @@
"block.create.copper_tile_stairs": "s\u0279\u0131\u0250\u0287S \u01DD\u05DF\u0131\u27D8 \u0279\u01DDddo\u0186",
"block.create.copper_tiles": "s\u01DD\u05DF\u0131\u27D8 \u0279\u01DDddo\u0186",
"block.create.copper_valve_handle": "\u01DD\u05DFpu\u0250H \u01DD\u028C\u05DF\u0250\u039B \u0279\u01DDddo\u0186",
"block.create.copycat_base": "\u01DDs\u0250\u15FA \u0287\u0250\u0254\u028Edo\u0186",
"block.create.copycat_panel": "\u05DF\u01DDu\u0250\u0500 \u0287\u0250\u0254\u028Edo\u0186",
"block.create.copycat_step": "d\u01DD\u0287S \u0287\u0250\u0254\u028Edo\u0186",
"block.create.creative_crate": "\u01DD\u0287\u0250\u0279\u0186 \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186",
"block.create.creative_fluid_tank": "\u029Eu\u0250\u27D8 p\u0131n\u05DF\u2132 \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186",
"block.create.creative_motor": "\u0279o\u0287oW \u01DD\u028C\u0131\u0287\u0250\u01DD\u0279\u0186",

View file

@ -67,6 +67,9 @@
"block.create.copper_tile_stairs": "Copper Tile Stairs",
"block.create.copper_tiles": "Copper Tiles",
"block.create.copper_valve_handle": "Copper Valve Handle",
"block.create.copycat_base": "Copycat Base",
"block.create.copycat_panel": "Copycat Panel",
"block.create.copycat_step": "Copycat Step",
"block.create.creative_crate": "Creative Crate",
"block.create.creative_fluid_tank": "Creative Fluid Tank",
"block.create.creative_motor": "Creative Motor",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 870",
"_": "Missing Localizations: 873",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Kupferfliesentreppe",
"block.create.copper_tiles": "Kupferfliesen",
"block.create.copper_valve_handle": "Kupfer Ventilgriff",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Kreative anpassbare Kiste",
"block.create.creative_fluid_tank": "Kreativer Flüssigkeitstank",
"block.create.creative_motor": "Kreativer Motor",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1016",
"_": "Missing Localizations: 1019",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs",
"block.create.copper_tiles": "Baldosas de Cobre",
"block.create.copper_valve_handle": "Válvula de Cobre",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Cajón del Creativo",
"block.create.creative_fluid_tank": "Tanque de Fluidos del Creativo",
"block.create.creative_motor": "Motor del Creativo",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 36",
"_": "Missing Localizations: 39",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Escaleras de baldosas de cobre",
"block.create.copper_tiles": "Bloque de baldosas de cobre",
"block.create.copper_valve_handle": "Asa de válvula de cobre",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Caja creativa",
"block.create.creative_fluid_tank": "Tanque de fluidos creativo",
"block.create.creative_motor": "Motor creativo",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2165",
"_": "Missing Localizations: 2168",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs",
"block.create.copper_tiles": "Tuiles en cuivre",
"block.create.copper_valve_handle": "Vanne en cuivre",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Créateur de schémacanon",
"block.create.creative_fluid_tank": "Réservoir créatif",
"block.create.creative_motor": "Moteur",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 30",
"_": "Missing Localizations: 33",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Scalini di mattonelle di rame",
"block.create.copper_tiles": "Piastrelle di rame",
"block.create.copper_valve_handle": "Maniglia per valvola di rame",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Cassa (creativa)",
"block.create.creative_fluid_tank": "Serbatoio per fluidi (creativa)",
"block.create.creative_motor": "Motore (creativa)",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 32",
"_": "Missing Localizations: 35",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "銅タイルの階段",
"block.create.copper_tiles": "銅タイル",
"block.create.copper_valve_handle": "銅のバルブハンドル",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "クリエティブクレート",
"block.create.creative_fluid_tank": "クリエイティブ液体タンク",
"block.create.creative_motor": "クリエイティブモーター",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 36",
"_": "Missing Localizations: 39",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "구리 타일 계단",
"block.create.copper_tiles": "구리 타일",
"block.create.copper_valve_handle": "구리 밸브 손잡이",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "크리에이티브 창고",
"block.create.creative_fluid_tank": "크리에이티브 탱크",
"block.create.creative_motor": "크리에이티브 모터",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2513",
"_": "Missing Localizations: 2516",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs",
"block.create.copper_tiles": "UNLOCALIZED: Copper Tiles",
"block.create.copper_valve_handle": "UNLOCALIZED: Copper Valve Handle",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Bouwtekeningkannon Creatiefeerder",
"block.create.creative_fluid_tank": "UNLOCALIZED: Creative Fluid Tank",
"block.create.creative_motor": "UNLOCALIZED: Creative Motor",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 40",
"_": "Missing Localizations: 43",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Schody z miedziaych kafelków",
"block.create.copper_tiles": "Miedziane kafelki",
"block.create.copper_valve_handle": "Miedziane pokrętło",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Kreatywna skrzynka",
"block.create.creative_fluid_tank": "Kreatywny zbiornik",
"block.create.creative_motor": "Kreatywny silnik",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1359",
"_": "Missing Localizations: 1362",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Escada de ladrilho de cobre",
"block.create.copper_tiles": "Ladrilho de cobre",
"block.create.copper_valve_handle": "Válvula de Cobre",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Caixa Criativa",
"block.create.creative_fluid_tank": "Tanque de Fluidos Criativo",
"block.create.creative_motor": "Motor Criativo",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 2224",
"_": "Missing Localizations: 2227",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs",
"block.create.copper_tiles": "UNLOCALIZED: Copper Tiles",
"block.create.copper_valve_handle": "Manopla de válvula de Cobre",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Caixa Criativa",
"block.create.creative_fluid_tank": "Tanque de Fluidos Criativo",
"block.create.creative_motor": "Motor Criativo",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 683",
"_": "Missing Localizations: 686",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Scări De Țiglă De Cupru",
"block.create.copper_tiles": "Țigle De Cupru",
"block.create.copper_valve_handle": "Mâner De Supapă De Cupru",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Ladă Creativ",
"block.create.creative_fluid_tank": "Rezervor De Fluid Creativ",
"block.create.creative_motor": "Motor Creativ",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 28",
"_": "Missing Localizations: 31",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "Ступеньки из медной плитки",
"block.create.copper_tiles": "Медная плитка",
"block.create.copper_valve_handle": "Медный ручной вентиль",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Творческий ящик",
"block.create.creative_fluid_tank": "Творческий жидкостный бак",
"block.create.creative_motor": "Творческий мотор",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 1014",
"_": "Missing Localizations: 1017",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "UNLOCALIZED: Copper Tile Stairs",
"block.create.copper_tiles": "Мідна плитка",
"block.create.copper_valve_handle": "Мідний ручний клапан",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "Творчий ящик",
"block.create.creative_fluid_tank": "Творчий бак для рідини",
"block.create.creative_motor": "Творчий мотор",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 28",
"_": "Missing Localizations: 31",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "铜瓦楼梯",
"block.create.copper_tiles": "铜瓦",
"block.create.copper_valve_handle": "铜阀门手轮",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "创造板条箱",
"block.create.creative_fluid_tank": "创造流体储罐",
"block.create.creative_motor": "创造马达",

View file

@ -1,5 +1,5 @@
{
"_": "Missing Localizations: 36",
"_": "Missing Localizations: 39",
"_": "->------------------------] Game Elements [------------------------<-",
@ -68,6 +68,9 @@
"block.create.copper_tile_stairs": "銅磚瓦階梯",
"block.create.copper_tiles": "銅磚瓦",
"block.create.copper_valve_handle": "銅製閥門開關",
"block.create.copycat_base": "UNLOCALIZED: Copycat Base",
"block.create.copycat_panel": "UNLOCALIZED: Copycat Panel",
"block.create.copycat_step": "UNLOCALIZED: Copycat Step",
"block.create.creative_crate": "創造板條箱",
"block.create.creative_fluid_tank": "創造流體儲存罐",
"block.create.creative_motor": "創造馬達",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,6 @@
{
"replace": false,
"values": [
"minecraft:barrel"
]
}

View file

@ -0,0 +1,8 @@
{
"replace": false,
"values": [
"#minecraft:cauldrons",
"#minecraft:saplings",
"#minecraft:climbable"
]
}

View file

@ -15,6 +15,8 @@
"create:radial_chassis",
"create:sequenced_gearshift",
"create:rotation_speed_controller",
"create:copycat_step",
"create:copycat_panel",
"create:andesite_funnel",
"create:andesite_belt_funnel",
"create:brass_funnel",

View file

@ -53,6 +53,7 @@
"create:deployer",
"create:portable_storage_interface",
"create:redstone_contact",
"create:elevator_contact",
"create:mechanical_harvester",
"create:mechanical_plough",
"create:white_seat",
@ -99,7 +100,8 @@
"create:rotation_speed_controller",
"create:mechanical_arm",
"create:railway_casing",
"create:elevator_contact",
"create:copycat_step",
"create:copycat_panel",
"create:content_observer",
"create:stockpile_switch",
"create:creative_crate",

View file

@ -102,6 +102,7 @@
"create:deployer",
"create:portable_storage_interface",
"create:redstone_contact",
"create:elevator_contact",
"create:mechanical_harvester",
"create:mechanical_plough",
"create:andesite_casing",
@ -126,7 +127,9 @@
"create:train_trapdoor",
"create:framed_glass_door",
"create:framed_glass_trapdoor",
"create:elevator_contact",
"create:copycat_base",
"create:copycat_step",
"create:copycat_panel",
"create:item_vault",
"create:andesite_funnel",
"create:andesite_belt_funnel",

View file

@ -144,6 +144,10 @@ import com.simibubi.create.content.curiosities.deco.PlacardBlock;
import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
import com.simibubi.create.content.curiosities.deco.TrainTrapdoorBlock;
import com.simibubi.create.content.curiosities.deco.TrapdoorCTBehaviour;
import com.simibubi.create.content.curiosities.frames.CopycatPanelBlock;
import com.simibubi.create.content.curiosities.frames.CopycatPanelModel;
import com.simibubi.create.content.curiosities.frames.CopycatStepBlock;
import com.simibubi.create.content.curiosities.frames.CopycatStepModel;
import com.simibubi.create.content.curiosities.girder.ConnectedGirderModel;
import com.simibubi.create.content.curiosities.girder.GirderBlock;
import com.simibubi.create.content.curiosities.girder.GirderBlockStateGenerator;
@ -1319,6 +1323,24 @@ public class AllBlocks {
.transform(customItemModel("_", "block"))
.register();
public static final BlockEntry<ElevatorContactBlock> ELEVATOR_CONTACT =
REGISTRATE.block("elevator_contact", ElevatorContactBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW))
.properties(p -> p.lightLevel(ElevatorContactBlock::getLight))
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.directionalBlock(c.get(), state -> {
Boolean calling = state.getValue(ElevatorContactBlock.CALLING);
Boolean powering = state.getValue(ElevatorContactBlock.POWERING);
return powering ? AssetLookup.partialBaseModel(c, p, "powered")
: calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p);
}))
.loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get()))
.onRegister(assignDataBehaviour(new CurrentFloorDisplaySource(), "current_floor"))
.item()
.transform(customItemModel("_", "block"))
.register();
public static final BlockEntry<HarvesterBlock> MECHANICAL_HARVESTER =
REGISTRATE.block("mechanical_harvester", HarvesterBlock::new)
.initialProperties(SharedProperties::stone)
@ -1662,22 +1684,28 @@ public class AllBlocks {
.addLayer(() -> RenderType::cutoutMipped)
.register();
public static final BlockEntry<ElevatorContactBlock> ELEVATOR_CONTACT =
REGISTRATE.block("elevator_contact", ElevatorContactBlock::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.TERRACOTTA_YELLOW))
.properties(p -> p.lightLevel(ElevatorContactBlock::getLight))
.transform(axeOrPickaxe())
.blockstate((c, p) -> p.directionalBlock(c.get(), state -> {
Boolean calling = state.getValue(ElevatorContactBlock.CALLING);
Boolean powering = state.getValue(ElevatorContactBlock.POWERING);
return powering ? AssetLookup.partialBaseModel(c, p, "powered")
: calling ? AssetLookup.partialBaseModel(c, p, "dim") : AssetLookup.partialBaseModel(c, p);
}))
.loot((p, b) -> p.dropOther(b, REDSTONE_CONTACT.get()))
.onRegister(assignDataBehaviour(new CurrentFloorDisplaySource(), "current_floor"))
public static final BlockEntry<Block> COPYCAT_BASE = REGISTRATE.block("copycat_base", Block::new)
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.color(MaterialColor.GLOW_LICHEN))
.addLayer(() -> RenderType::cutoutMipped)
.transform(pickaxeOnly())
.blockstate((c, p) -> p.simpleBlock(c.get(), AssetLookup.partialBaseModel(c, p)))
.register();
public static final BlockEntry<CopycatStepBlock> COPYCAT_STEP =
REGISTRATE.block("copycat_step", CopycatStepBlock::new)
.transform(BuilderTransformers.copycat())
.onRegister(CreateRegistrate.blockModel(() -> CopycatStepModel::new))
.item()
.transform(customItemModel("_", "block"))
.transform(customItemModel("copycat_base", "step"))
.register();
public static final BlockEntry<CopycatPanelBlock> COPYCAT_PANEL =
REGISTRATE.block("copycat_panel", CopycatPanelBlock::new)
.transform(BuilderTransformers.copycat())
.onRegister(CreateRegistrate.blockModel(() -> CopycatPanelModel::new))
.item()
.transform(customItemModel("copycat_base", "panel"))
.register();
public static final BlockEntry<ItemVaultBlock> ITEM_VAULT = REGISTRATE.block("item_vault", ItemVaultBlock::new)

View file

@ -30,6 +30,7 @@ public class AllShapes {
CASING_13PX = shape(0, 0, 0, 16, 13, 16).forDirectional(),
CASING_12PX = shape(0, 0, 0, 16, 12, 16).forDirectional(),
CASING_11PX = shape(0, 0, 0, 16, 11, 16).forDirectional(),
CASING_3PX = shape(0, 0, 0, 16, 3, 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(),
@ -124,6 +125,9 @@ public class AllShapes {
GIRDER_BEAM_SHAFT = shape(GIRDER_BEAM.get(Axis.X)).add(SIX_VOXEL_POLE.get(Axis.Z))
.forHorizontalAxis(),
STEP_BOTTOM = shape(0, 0, 8, 16, 8, 16).forHorizontal(SOUTH),
STEP_TOP = shape(0, 8, 8, 16, 16, 16).forHorizontal(SOUTH),
CONTROLS = shape(0, 0, 6, 16, 14, 16).forHorizontal(NORTH),
CONTRAPTION_CONTROLS = shape(0, 0, 6, 2, 14, 16).add(14, 0, 6, 16, 14, 16)
.add(0, 0, 14, 16, 14, 16)

View file

@ -125,6 +125,8 @@ public class AllTags {
WINDOWABLE,
WRENCH_PICKUP,
TREE_ATTACHMENTS,
COPYCAT_ALLOW,
COPYCAT_DENY,
RELOCATION_NOT_SUPPORTED(FORGE),
WG_STONE(FORGE),
@ -408,6 +410,11 @@ public class AllTags {
AllBlockTags.SAFE_NBT.includeAll(BlockTags.SIGNS);
AllBlockTags.SAFE_NBT.includeAll(BlockTags.BANNERS);
AllBlockTags.COPYCAT_ALLOW.add(Blocks.BARREL);
AllBlockTags.COPYCAT_DENY.includeAll(BlockTags.CAULDRONS);
AllBlockTags.COPYCAT_DENY.includeAll(BlockTags.SAPLINGS);
AllBlockTags.COPYCAT_DENY.includeAll(BlockTags.CLIMBABLE);
AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.RAILS);
AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.BUTTONS);
AllBlockTags.WRENCH_PICKUP.includeAll(BlockTags.PRESSURE_PLATES);

View file

@ -142,6 +142,7 @@ import com.simibubi.create.content.curiosities.deco.PlacardRenderer;
import com.simibubi.create.content.curiosities.deco.PlacardTileEntity;
import com.simibubi.create.content.curiosities.deco.SlidingDoorRenderer;
import com.simibubi.create.content.curiosities.deco.SlidingDoorTileEntity;
import com.simibubi.create.content.curiosities.frames.CopycatTileEntity;
import com.simibubi.create.content.curiosities.toolbox.ToolBoxInstance;
import com.simibubi.create.content.curiosities.toolbox.ToolboxRenderer;
import com.simibubi.create.content.curiosities.toolbox.ToolboxTileEntity;
@ -827,6 +828,11 @@ public class AllTileEntities {
.validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR)
.register();
public static final BlockEntityEntry<CopycatTileEntity> UNIVERSAL_FRAME = Create.registrate()
.tileEntity("universal_frame", CopycatTileEntity::new)
.validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP)
.register();
public static final BlockEntityEntry<FlapDisplayTileEntity> FLAP_DISPLAY = Create.registrate()
.tileEntity("flap_display", FlapDisplayTileEntity::new)
.instance(() -> MechanicalCrafterInstance::new)

View file

@ -2,11 +2,13 @@ package com.simibubi.create.content.contraptions.components.structureMovement.be
import org.apache.commons.lang3.tuple.Pair;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.content.contraptions.components.structureMovement.AssemblyException;
import com.simibubi.create.content.contraptions.components.structureMovement.Contraption;
import com.simibubi.create.content.contraptions.components.structureMovement.ContraptionType;
import com.simibubi.create.content.contraptions.components.structureMovement.render.ContraptionLighter;
import com.simibubi.create.content.curiosities.frames.CopycatTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import net.minecraft.core.BlockPos;
@ -14,6 +16,7 @@ import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate.StructureBlockInfo;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
@ -59,11 +62,18 @@ public class BearingContraption extends Contraption {
@Override
public void addBlock(BlockPos pos, Pair<StructureBlockInfo, BlockEntity> capture) {
BlockPos localPos = pos.subtract(anchor);
if (!getBlocks().containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(capture.getKey().state))
if (!getBlocks().containsKey(localPos) && AllBlockTags.WINDMILL_SAILS.matches(getSailBlock(capture)))
sailBlocks++;
super.addBlock(pos, capture);
}
private BlockState getSailBlock(Pair<StructureBlockInfo, BlockEntity> capture) {
BlockState state = capture.getKey().state;
if (AllBlocks.COPYCAT_PANEL.has(state) && capture.getRight()instanceof CopycatTileEntity cte)
return cte.getMaterial();
return state;
}
@Override
public CompoundTag writeNBT(boolean spawnPacket) {
CompoundTag tag = super.writeNBT(spawnPacket);

View file

@ -84,9 +84,13 @@ public class SailBlock extends WrenchableDirectionalBlock {
ItemStack heldItem = player.getItemInHand(hand);
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
if (placementHelper.matchesItem(heldItem))
return placementHelper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray);
if (!player.isShiftKeyDown() && player.mayBuild()) {
if (placementHelper.matchesItem(heldItem)) {
placementHelper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray);
return InteractionResult.SUCCESS;
}
}
if (heldItem.getItem() instanceof ShearsItem) {
if (!world.isClientSide)
@ -119,7 +123,8 @@ public class SailBlock extends WrenchableDirectionalBlock {
}
// Dye all adjacent
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, hit, state.getValue(FACING).getAxis());
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, hit, state.getValue(FACING)
.getAxis());
for (Direction d : directions) {
BlockPos offset = pos.relative(d);
BlockState adjacentState = world.getBlockState(offset);
@ -182,7 +187,8 @@ public class SailBlock extends WrenchableDirectionalBlock {
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos, Player player) {
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter world, BlockPos pos,
Player player) {
ItemStack pickBlock = super.getCloneItemStack(state, target, world, pos, player);
if (pickBlock.isEmpty())
return AllBlocks.SAIL.get()

View file

@ -34,7 +34,8 @@ public class PipeAttachmentModel extends BakedModelWrapperWithData {
}
@Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
PipeModelData data = new PipeModelData();
FluidTransportBehaviour transport = TileEntityBehaviour.get(world, pos, FluidTransportBehaviour.TYPE);
BracketedTileEntityBehaviour bracket = TileEntityBehaviour.get(world, pos, BracketedTileEntityBehaviour.TYPE);

View file

@ -42,11 +42,12 @@ public class FluidTankModel extends CTModel {
}
@Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
CullData cullData = new CullData();
for (Direction d : Iterate.horizontalDirections)
cullData.setCulled(d, ConnectivityHandler.isConnected(world, pos, pos.relative(d)));
return super.gatherModelData(builder, world, pos, state).withInitial(CULL_PROPERTY, cullData);
return super.gatherModelData(builder, world, pos, state, tileData).withInitial(CULL_PROPERTY, cullData);
}
@Override

View file

@ -37,8 +37,10 @@ public class TrainTrapdoorBlock extends TrapDoorBlock implements IWrenchable {
}
public static boolean isConnected(BlockState state, BlockState other, Direction pDirection) {
state = state.setValue(WATERLOGGED, false);
other = other.setValue(WATERLOGGED, false);
state = state.setValue(WATERLOGGED, false)
.setValue(POWERED, false);
other = other.setValue(WATERLOGGED, false)
.setValue(POWERED, false);
boolean open = state.getValue(OPEN);
Half half = state.getValue(HALF);

View file

@ -0,0 +1,365 @@
package com.simibubi.create.content.curiosities.frames;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.wrench.IWrenchable;
import com.simibubi.create.foundation.block.ITE;
import net.minecraft.client.Minecraft;
import net.minecraft.client.color.block.BlockColor;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.SpawnPlacements.Type;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.GrassColor;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.SoundType;
import net.minecraft.world.level.block.StairBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityTicker;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.HitResult;
import net.minecraft.world.phys.shapes.Shapes;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
public abstract class CopycatBlock extends Block implements ITE<CopycatTileEntity>, IWrenchable {
public CopycatBlock(Properties pProperties) {
super(pProperties);
}
@Nullable
@Override
public <S extends BlockEntity> BlockEntityTicker<S> getTicker(Level p_153212_, BlockState p_153213_,
BlockEntityType<S> p_153214_) {
return null;
}
@Override
public InteractionResult onSneakWrenched(BlockState state, UseOnContext context) {
onWrenched(state, context);
return IWrenchable.super.onSneakWrenched(state, context);
}
@Override
public InteractionResult onWrenched(BlockState state, UseOnContext context) {
return onTileEntityUse(context.getLevel(), context.getClickedPos(), ufte -> {
ItemStack consumedItem = ufte.getConsumedItem();
if (!ufte.hasCustomMaterial())
return InteractionResult.PASS;
Player player = context.getPlayer();
if (!player.isCreative())
player.getInventory()
.placeItemBackInInventory(consumedItem);
context.getLevel()
.levelEvent(2001, context.getClickedPos(), Block.getId(ufte.getBlockState()));
ufte.setMaterial(AllBlocks.COPYCAT_BASE.getDefaultState());
ufte.setItem(ItemStack.EMPTY);
return InteractionResult.SUCCESS;
});
}
@Override
public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand,
BlockHitResult pHit) {
if (pPlayer == null)
return InteractionResult.PASS;
Direction face = pHit.getDirection();
ItemStack itemInHand = pPlayer.getItemInHand(pHand);
BlockState material = getAcceptedBlockState(pLevel, pPos, itemInHand, face);
if (material == null)
return InteractionResult.PASS;
return onTileEntityUse(pLevel, pPos, ufte -> {
if (ufte.getMaterial()
.is(material.getBlock())) {
if (!ufte.cycleMaterial())
return InteractionResult.PASS;
ufte.getLevel()
.playSound(null, ufte.getBlockPos(), SoundEvents.ITEM_FRAME_ADD_ITEM, SoundSource.BLOCKS, .75f,
.95f);
return InteractionResult.SUCCESS;
}
if (ufte.hasCustomMaterial())
return InteractionResult.PASS;
if (pLevel.isClientSide())
return InteractionResult.SUCCESS;
ufte.setMaterial(material);
ufte.setItem(itemInHand);
ufte.getLevel()
.playSound(null, ufte.getBlockPos(), material.getSoundType()
.getPlaceSound(), SoundSource.BLOCKS, 1, .75f);
if (pPlayer.isCreative())
return InteractionResult.SUCCESS;
itemInHand.shrink(1);
if (itemInHand.isEmpty())
pPlayer.setItemInHand(pHand, ItemStack.EMPTY);
return InteractionResult.SUCCESS;
});
}
@Override
public void setPlacedBy(Level pLevel, BlockPos pPos, BlockState pState, LivingEntity pPlacer, ItemStack pStack) {
if (pPlacer == null)
return;
ItemStack offhandItem = pPlacer.getItemInHand(InteractionHand.OFF_HAND);
BlockState appliedState =
getAcceptedBlockState(pLevel, pPos, offhandItem, Direction.orderedByNearest(pPlacer)[0]);
if (appliedState == null)
return;
withTileEntityDo(pLevel, pPos, ufte -> {
if (ufte.hasCustomMaterial())
return;
ufte.setMaterial(appliedState);
ufte.setItem(offhandItem);
if (pPlacer instanceof Player player && player.isCreative())
return;
offhandItem.shrink(1);
if (offhandItem.isEmpty())
pPlacer.setItemInHand(InteractionHand.OFF_HAND, ItemStack.EMPTY);
});
}
@Nullable
public static BlockState getAcceptedBlockState(Level pLevel, BlockPos pPos, ItemStack item, Direction face) {
if (!(item.getItem()instanceof BlockItem bi))
return null;
Block block = bi.getBlock();
if (block instanceof CopycatBlock)
return null;
if (AllBlockTags.COPYCAT_DENY.matches(block))
return null;
BlockState appliedState = block.defaultBlockState();
if (!AllBlockTags.COPYCAT_ALLOW.matches(block)) {
if (block instanceof EntityBlock)
return null;
if (block instanceof StairBlock)
return null;
VoxelShape shape = appliedState.getShape(pLevel, pPos);
if (shape.isEmpty() || !shape.bounds()
.equals(Shapes.block()
.bounds()))
return null;
VoxelShape collisionShape = appliedState.getCollisionShape(pLevel, pPos);
if (collisionShape.isEmpty())
return null;
}
if (face != null) {
Axis axis = face.getAxis();
if (appliedState.hasProperty(BlockStateProperties.FACING))
appliedState = appliedState.setValue(BlockStateProperties.FACING, face);
if (appliedState.hasProperty(BlockStateProperties.HORIZONTAL_FACING) && axis != Axis.Y)
appliedState = appliedState.setValue(BlockStateProperties.HORIZONTAL_FACING, face);
if (appliedState.hasProperty(BlockStateProperties.AXIS))
appliedState = appliedState.setValue(BlockStateProperties.AXIS, axis);
if (appliedState.hasProperty(BlockStateProperties.HORIZONTAL_AXIS) && axis != Axis.Y)
appliedState = appliedState.setValue(BlockStateProperties.HORIZONTAL_AXIS, axis);
}
return appliedState;
}
@Override
public void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
if (!pState.hasBlockEntity() || pState.getBlock() == pNewState.getBlock())
return;
if (!pIsMoving)
withTileEntityDo(pLevel, pPos, ufte -> Block.popResource(pLevel, pPos, ufte.getConsumedItem()));
pLevel.removeBlockEntity(pPos);
}
@Override
public void playerWillDestroy(Level pLevel, BlockPos pPos, BlockState pState, Player pPlayer) {
super.playerWillDestroy(pLevel, pPos, pState, pPlayer);
if (pPlayer.isCreative())
withTileEntityDo(pLevel, pPos, ufte -> ufte.setItem(ItemStack.EMPTY));
}
@Override
public Class<CopycatTileEntity> getTileEntityClass() {
return CopycatTileEntity.class;
}
@Override
public BlockEntityType<? extends CopycatTileEntity> getTileEntityType() {
return AllTileEntities.UNIVERSAL_FRAME.get();
}
// Connected Textures
@Nullable
/**
* The wrapped blockstate at toPos. Wrapper guaranteed to be a block of this
* type <br>
* Return null if the 'from' state shouldn't connect to this block/face
*
* @param from
* @param reader
* @param targetPos
* @param face
* @return
*/
public abstract BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos);
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return false;
}
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return false;
}
public static BlockState getMaterial(BlockGetter reader, BlockPos targetPos) {
if (reader.getBlockEntity(targetPos)instanceof CopycatTileEntity ufte)
return ufte.getMaterial();
return Blocks.AIR.defaultBlockState();
}
public boolean canFaceBeOccluded(BlockState state, Direction face) {
return false;
}
// Wrapped properties
@Override
public SoundType getSoundType(BlockState state, LevelReader level, BlockPos pos, Entity entity) {
return getMaterial(level, pos).getSoundType();
}
@Override
public float getFriction(BlockState state, LevelReader level, BlockPos pos, Entity entity) {
return getMaterial(level, pos).getFriction(level, pos, entity);
}
@Override
public int getLightEmission(BlockState state, BlockGetter level, BlockPos pos) {
return getMaterial(level, pos).getLightEmission(level, pos);
}
@Override
public boolean canHarvestBlock(BlockState state, BlockGetter level, BlockPos pos, Player player) {
return getMaterial(level, pos).canHarvestBlock(level, pos, player);
}
@Override
public float getExplosionResistance(BlockState state, BlockGetter level, BlockPos pos, Explosion explosion) {
return getMaterial(level, pos).getExplosionResistance(level, pos, explosion);
}
@Override
public ItemStack getCloneItemStack(BlockState state, HitResult target, BlockGetter level, BlockPos pos,
Player player) {
BlockState material = getMaterial(level, pos);
if (AllBlocks.COPYCAT_BASE.has(material))
return new ItemStack(this);
return material.getCloneItemStack(target, level, pos, player);
}
@Override
public boolean addLandingEffects(BlockState state1, ServerLevel level, BlockPos pos, BlockState state2,
LivingEntity entity, int numberOfParticles) {
return getMaterial(level, pos).addLandingEffects(level, pos, state2, entity, numberOfParticles);
}
@Override
public boolean addRunningEffects(BlockState state, Level level, BlockPos pos, Entity entity) {
return getMaterial(level, pos).addRunningEffects(level, pos, entity);
}
@Override
public float getEnchantPowerBonus(BlockState state, LevelReader level, BlockPos pos) {
return getMaterial(level, pos).getEnchantPowerBonus(level, pos);
}
@Override
public boolean canEntityDestroy(BlockState state, BlockGetter level, BlockPos pos, Entity entity) {
return getMaterial(level, pos).canEntityDestroy(level, pos, entity);
}
@Override
public boolean isValidSpawn(BlockState state, BlockGetter level, BlockPos pos, Type type,
EntityType<?> entityType) {
return false;
}
@Override
public void fallOn(Level pLevel, BlockState pState, BlockPos pPos, Entity pEntity, float p_152430_) {
BlockState material = getMaterial(pLevel, pPos);
material.getBlock()
.fallOn(pLevel, material, pPos, pEntity, p_152430_);
}
@Override
public float getDestroyProgress(BlockState pState, Player pPlayer, BlockGetter pLevel, BlockPos pPos) {
return getMaterial(pLevel, pPos).getDestroyProgress(pPlayer, pLevel, pPos);
}
//
@OnlyIn(Dist.CLIENT)
public static BlockColor wrappedColor() {
return new WrappedBlockColor();
}
@OnlyIn(Dist.CLIENT)
public static class WrappedBlockColor implements BlockColor {
@Override
public int getColor(BlockState pState, @Nullable BlockAndTintGetter pLevel, @Nullable BlockPos pPos,
int pTintIndex) {
if (pLevel == null || pPos == null)
return GrassColor.get(0.5D, 1.0D);
return Minecraft.getInstance()
.getBlockColors()
.getColor(getMaterial(pLevel, pPos), pLevel, pPos, pTintIndex);
}
}
}

View file

@ -0,0 +1,221 @@
package com.simibubi.create.content.curiosities.frames;
import static com.simibubi.create.content.curiosities.frames.CopycatTileEntity.MATERIAL_PROPERTY;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedU;
import static com.simibubi.create.foundation.block.render.SpriteShiftEntry.getUnInterpolatedV;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.foundation.block.connected.BakedModelWrapperWithData;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VecHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.ItemBlockRenderTypes;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.BlockPos.MutableBlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.MinecraftForgeClient;
import net.minecraftforge.client.model.data.EmptyModelData;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelDataMap.Builder;
import net.minecraftforge.client.model.data.ModelProperty;
public abstract class CopycatModel extends BakedModelWrapperWithData {
private static final ModelProperty<IModelData> WRAPPED_DATA_PROPERTY = new ModelProperty<>();
private static final ModelProperty<OcclusionData> OCCLUSION_PROPERTY = new ModelProperty<>();
public CopycatModel(BakedModel originalModel) {
super(originalModel);
}
@Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
BlockState wrappedState = getMaterial(world, pos, state);
if (wrappedState == null)
return builder;
if (tileData instanceof ModelDataMap mdm && mdm.hasProperty(MATERIAL_PROPERTY))
builder.withInitial(MATERIAL_PROPERTY, mdm.getData(MATERIAL_PROPERTY));
OcclusionData occlusionData = new OcclusionData();
if (state.getBlock()instanceof CopycatBlock ufb) {
MutableBlockPos mutablePos = new MutableBlockPos();
for (Direction face : Iterate.directions)
if (ufb.canFaceBeOccluded(state, face))
if (!Block.shouldRenderFace(wrappedState, world, pos, face, mutablePos.setWithOffset(pos, face)))
occlusionData.occlude(face);
builder.withInitial(OCCLUSION_PROPERTY, occlusionData);
}
IModelData modelData = getModelOf(wrappedState).getModelData(world, pos, wrappedState, EmptyModelData.INSTANCE);
return builder.withInitial(WRAPPED_DATA_PROPERTY, modelData);
}
@Override
public List<BakedQuad> getQuads(BlockState state, Direction side, Random rand, IModelData extraData) {
List<BakedQuad> quads = super.getQuads(state, side, rand, extraData);
BlockState material = getMaterial(extraData);
IModelData wrappedData = extraData.getData(WRAPPED_DATA_PROPERTY);
if (material == null)
return quads;
RenderType renderType = MinecraftForgeClient.getRenderType();
if (renderType != null && !ItemBlockRenderTypes.canRenderInLayer(material, renderType))
return quads;
if (wrappedData == null)
wrappedData = EmptyModelData.INSTANCE;
OcclusionData occlusionData = extraData.getData(OCCLUSION_PROPERTY);
if (occlusionData != null && occlusionData.isOccluded(side))
return quads;
return getCroppedQuads(state, side, rand, material, wrappedData);
}
protected abstract List<BakedQuad> getCroppedQuads(BlockState state, Direction side, Random rand,
BlockState material, IModelData wrappedData);
public static boolean cropAndMove(BakedQuad quad, AABB crop, Vec3 move) {
int[] vertexData = quad.getVertices();
Vec3 xyz0 = QuadHelper.getXYZ(vertexData, 0);
Vec3 xyz1 = QuadHelper.getXYZ(vertexData, 1);
Vec3 xyz2 = QuadHelper.getXYZ(vertexData, 2);
Vec3 xyz3 = QuadHelper.getXYZ(vertexData, 3);
Vec3 uAxis = xyz3.add(xyz2)
.scale(.5);
Vec3 vAxis = xyz1.add(xyz2)
.scale(.5);
Vec3 center = xyz3.add(xyz2)
.add(xyz0)
.add(xyz1)
.scale(.25);
float u0 = QuadHelper.getU(vertexData, 0);
float u3 = QuadHelper.getU(vertexData, 3);
float v0 = QuadHelper.getV(vertexData, 0);
float v1 = QuadHelper.getV(vertexData, 1);
TextureAtlasSprite sprite = quad.getSprite();
float uScale = (float) Math
.round((getUnInterpolatedU(sprite, u3) - getUnInterpolatedU(sprite, u0)) / xyz3.distanceTo(xyz0));
float vScale = (float) Math
.round((getUnInterpolatedV(sprite, v1) - getUnInterpolatedV(sprite, v0)) / xyz1.distanceTo(xyz0));
if (uScale == 0) {
float v3 = QuadHelper.getV(vertexData, 3);
float u1 = QuadHelper.getU(vertexData, 1);
uAxis = xyz1.add(xyz2)
.scale(.5);
vAxis = xyz3.add(xyz2)
.scale(.5);
uScale = (float) Math
.round((getUnInterpolatedU(sprite, u1) - getUnInterpolatedU(sprite, u0)) / xyz1.distanceTo(xyz0));
vScale = (float) Math
.round((getUnInterpolatedV(sprite, v3) - getUnInterpolatedV(sprite, v0)) / xyz3.distanceTo(xyz0));
}
uAxis = uAxis.subtract(center)
.normalize();
vAxis = vAxis.subtract(center)
.normalize();
Vec3 min = new Vec3(crop.minX, crop.minY, crop.minZ);
Vec3 max = new Vec3(crop.maxX, crop.maxY, crop.maxZ);
for (int vertex = 0; vertex < 4; vertex++) {
Vec3 xyz = QuadHelper.getXYZ(vertexData, vertex);
Vec3 newXyz = VecHelper.componentMin(max, VecHelper.componentMax(xyz, min));
Vec3 diff = newXyz.subtract(xyz);
if (diff.lengthSqr() > 0) {
float u = QuadHelper.getU(vertexData, vertex);
float v = QuadHelper.getV(vertexData, vertex);
float uDiff = (float) uAxis.dot(diff) * uScale;
float vDiff = (float) vAxis.dot(diff) * vScale;
QuadHelper.setU(vertexData, vertex, sprite.getU(getUnInterpolatedU(sprite, u) + uDiff));
QuadHelper.setV(vertexData, vertex, sprite.getV(getUnInterpolatedV(sprite, v) + vDiff));
}
QuadHelper.setXYZ(vertexData, vertex, newXyz.add(move));
}
return true;
}
@Override
public TextureAtlasSprite getParticleIcon(IModelData data) {
BlockState material = getMaterial(data);
IModelData wrappedData = data.getData(WRAPPED_DATA_PROPERTY);
if (wrappedData == null)
wrappedData = EmptyModelData.INSTANCE;
if (material != null)
return getModelOf(material).getParticleIcon(wrappedData);
return super.getParticleIcon(data);
}
@Nullable
public BlockState getMaterial(IModelData extraData) {
BlockState material = extraData.getData(MATERIAL_PROPERTY);
return material == null ? AllBlocks.COPYCAT_BASE.getDefaultState() : material;
}
@Nullable
public BlockState getMaterial(BlockAndTintGetter world, BlockPos pos, BlockState state) {
if (!(state.getBlock()instanceof CopycatBlock ufb))
return null;
return ufb.getTileEntityOptional(world, pos)
.map(CopycatTileEntity::getMaterial)
.orElse(null);
}
public BakedModel getModelOf(BlockState wrappedState) {
return Minecraft.getInstance()
.getBlockRenderer()
.getBlockModel(wrappedState);
}
private static class OcclusionData {
private final boolean[] occluded;
public OcclusionData() {
occluded = new boolean[6];
Arrays.fill(occluded, false);
}
public void occlude(Direction face) {
occluded[face.get3DDataValue()] = true;
}
public boolean isOccluded(Direction face) {
return face == null ? false : occluded[face.get3DDataValue()];
}
}
}

View file

@ -0,0 +1,206 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.List;
import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
import net.minecraft.MethodsReturnNonnullByDefault;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
public class CopycatPanelBlock extends WaterloggedCopycatBlock {
public static final DirectionProperty FACING = BlockStateProperties.FACING;
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
public CopycatPanelBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(defaultBlockState().setValue(FACING, Direction.UP));
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult ray) {
if (!player.isShiftKeyDown() && player.mayBuild()) {
ItemStack heldItem = player.getItemInHand(hand);
IPlacementHelper placementHelper = PlacementHelpers.get(placementHelperId);
if (placementHelper.matchesItem(heldItem)) {
placementHelper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray);
return InteractionResult.SUCCESS;
}
}
return super.use(state, world, pos, player, hand, ray);
}
@Override
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return true;
}
@Override
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
Direction facing = state.getValue(FACING);
BlockState toState = reader.getBlockState(toPos);
if (!toState.is(this))
return facing != face.getOpposite();
BlockPos diff = fromPos.subtract(toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
return facing == toState.getValue(FACING)
.getOpposite()
&& !(coord != 0 && coord == facing.getAxisDirection()
.getStep());
}
@Override
public boolean canFaceBeOccluded(BlockState state, Direction face) {
return state.getValue(FACING)
.getOpposite() == face;
}
@Override
public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos) {
BlockState panelState = reader.getBlockState(toPos);
Direction facing = panelState.getValue(FACING);
if (!otherState.is(this))
return facing == face.getOpposite() ? getMaterial(reader, toPos) : null;
if (isOccluded(panelState, otherState, facing))
return getMaterial(reader, toPos);
BlockPos diff = fromPos.subtract(toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (otherState.setValue(WATERLOGGED, false) == panelState.setValue(WATERLOGGED, false) && coord == 0)
return getMaterial(reader, toPos);
return null;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
BlockState stateForPlacement = super.getStateForPlacement(pContext);
return stateForPlacement.setValue(FACING, pContext.getNearestLookingDirection()
.getOpposite());
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
super.createBlockStateDefinition(pBuilder.add(FACING));
}
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
return AllShapes.CASING_3PX.get(pState.getValue(FACING));
}
@Override
public boolean isPathfindable(BlockState pState, BlockGetter pLevel, BlockPos pPos, PathComputationType pType) {
return false;
}
@Override
public boolean supportsExternalFaceHiding(BlockState state) {
return true;
}
@Override
public boolean hidesNeighborFace(BlockGetter level, BlockPos pos, BlockState state, BlockState neighborState,
Direction dir) {
if (state.is(this) == neighborState.is(this)
&& getMaterial(level, pos).skipRendering(getMaterial(level, pos.relative(dir)), dir.getOpposite()))
return isOccluded(state, neighborState, dir.getOpposite());
return state.getValue(FACING) == dir.getOpposite()
&& getMaterial(level, pos).skipRendering(neighborState, dir.getOpposite());
}
public static boolean isOccluded(BlockState state, BlockState other, Direction pDirection) {
state = state.setValue(WATERLOGGED, false);
other = other.setValue(WATERLOGGED, false);
Direction facing = state.getValue(FACING);
if (facing.getOpposite() == other.getValue(FACING) && pDirection == facing)
return true;
if (other.getValue(FACING) != facing)
return false;
return pDirection.getAxis() != facing.getAxis();
}
@Override
public BlockState rotate(BlockState state, Rotation rot) {
return state.setValue(FACING, rot.rotate(state.getValue(FACING)));
}
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState state, Mirror mirrorIn) {
return state.rotate(mirrorIn.getRotation(state.getValue(FACING)));
}
@MethodsReturnNonnullByDefault
private static class PlacementHelper implements IPlacementHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return AllBlocks.COPYCAT_PANEL::isIn;
}
@Override
public Predicate<BlockState> getStatePredicate() {
return AllBlocks.COPYCAT_PANEL::has;
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
List<Direction> directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, ray.getLocation(),
state.getValue(FACING)
.getAxis(),
dir -> world.getBlockState(pos.relative(dir))
.getMaterial()
.isReplaceable());
if (directions.isEmpty())
return PlacementOffset.fail();
else {
return PlacementOffset.success(pos.relative(directions.get(0)),
s -> s.setValue(FACING, state.getValue(FACING)));
}
}
}
}

View file

@ -0,0 +1,68 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.model.data.IModelData;
public class CopycatPanelModel extends CopycatModel {
public CopycatPanelModel(BakedModel originalModel) {
super(originalModel);
}
@Override
protected List<BakedQuad> getCroppedQuads(BlockState state, Direction side, Random rand, BlockState material,
IModelData wrappedData) {
Direction facing = state.getOptionalValue(CopycatPanelBlock.FACING)
.orElse(Direction.UP);
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
AABB cube = new AABB(BlockPos.ZERO);
BakedModel model = getModelOf(material);
List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData);
int size = templateQuads.size();
List<BakedQuad> quads = new ArrayList<>();
// 2 Pieces
for (boolean front : Iterate.trueAndFalse) {
for (int i = 0; i < size; i++) {
BakedQuad quad = templateQuads.get(i);
Direction direction = quad.getDirection();
if (front && direction == facing)
continue;
if (!front && direction == facing.getOpposite())
continue;
float contract = 16 - (front ? 1 : 2);
AABB bb = cube.contract(normal.x * contract / 16, normal.y * contract / 16, normal.z * contract / 16);
if (!front)
bb = bb.move(normal.scale(14 / 16f));
BakedQuad newQuad = QuadHelper.clone(quad);
if (cropAndMove(newQuad, bb, normal.scale(front ? 0 : -13 / 16f)));
quads.add(newQuad);
}
}
return quads;
}
}

View file

@ -0,0 +1,282 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.function.Predicate;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllShapes;
import com.simibubi.create.content.curiosities.tools.ExtendoGripItem;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.utility.Iterate;
import com.simibubi.create.foundation.utility.VoxelShaper;
import com.simibubi.create.foundation.utility.placement.IPlacementHelper;
import com.simibubi.create.foundation.utility.placement.PlacementHelpers;
import com.simibubi.create.foundation.utility.placement.PlacementOffset;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Direction.Axis;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BlockItem;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.BlockAndTintGetter;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Mirror;
import net.minecraft.world.level.block.Rotation;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.block.state.properties.EnumProperty;
import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.world.level.pathfinder.PathComputationType;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.shapes.CollisionContext;
import net.minecraft.world.phys.shapes.VoxelShape;
import net.minecraftforge.common.ForgeMod;
public class CopycatStepBlock extends WaterloggedCopycatBlock {
public static EnumProperty<Half> HALF = BlockStateProperties.HALF;
public static DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
private static final int placementHelperId = PlacementHelpers.register(new PlacementHelper());
public CopycatStepBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(defaultBlockState().setValue(HALF, Half.BOTTOM)
.setValue(FACING, Direction.SOUTH));
}
@Override
public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand,
BlockHitResult ray) {
if (!player.isShiftKeyDown() && player.mayBuild()) {
ItemStack heldItem = player.getItemInHand(hand);
IPlacementHelper helper = PlacementHelpers.get(placementHelperId);
if (helper.matchesItem(heldItem))
return helper.getOffset(player, world, state, pos, ray)
.placeInWorld(world, (BlockItem) heldItem.getItem(), player, hand, ray);
}
return super.use(state, world, pos, player, hand, ray);
}
@Override
public BlockState getConnectiveMaterial(BlockAndTintGetter reader, BlockState otherState, Direction face,
BlockPos fromPos, BlockPos toPos) {
if (!otherState.is(this))
return null;
BlockState stepState = reader.getBlockState(toPos);
Direction facing = stepState.getValue(FACING);
BlockPos diff = fromPos.subtract(toPos);
if (diff.getY() != 0) {
if (isOccluded(stepState, otherState, diff.getY() > 0 ? Direction.UP : Direction.DOWN))
return getMaterial(reader, toPos);
return null;
}
if (isOccluded(stepState, otherState, facing))
return getMaterial(reader, toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
if (otherState.setValue(WATERLOGGED, false) == stepState.setValue(WATERLOGGED, false) && coord == 0)
return getMaterial(reader, toPos);
return null;
}
@Override
public boolean isUnblockableConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
return true;
}
@Override
public boolean isIgnoredConnectivitySide(BlockAndTintGetter reader, BlockState state, Direction face,
BlockPos fromPos, BlockPos toPos) {
BlockState toState = reader.getBlockState(toPos);
if (!toState.is(this)) {
if (!canFaceBeOccluded(state, face.getOpposite()))
return true;
for (Direction d : Iterate.directions)
if (fromPos.relative(d)
.equals(toPos) && !canFaceBeOccluded(state, d))
return true;
return false;
}
Direction facing = state.getValue(FACING);
BlockPos diff = fromPos.subtract(toPos);
int coord = facing.getAxis()
.choose(diff.getX(), diff.getY(), diff.getZ());
Half half = state.getValue(HALF);
if (half != toState.getValue(HALF))
return diff.getY() == 0;
return facing == toState.getValue(FACING)
.getOpposite()
&& !(coord != 0 && coord != facing.getAxisDirection()
.getStep());
}
@Override
public boolean canFaceBeOccluded(BlockState state, Direction face) {
if (face.getAxis() == Axis.Y)
return (state.getValue(HALF) == Half.TOP) == (face == Direction.UP);
return state.getValue(FACING) == face;
}
@Override
public boolean isPathfindable(BlockState pState, BlockGetter pLevel, BlockPos pPos, PathComputationType pType) {
return false;
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
BlockState stateForPlacement =
super.getStateForPlacement(pContext).setValue(FACING, pContext.getHorizontalDirection());
Direction direction = pContext.getClickedFace();
if (direction == Direction.UP)
return stateForPlacement;
if (direction == Direction.DOWN || (pContext.getClickLocation().y - pContext.getClickedPos()
.getY() > 0.5D))
return stateForPlacement.setValue(HALF, Half.TOP);
return stateForPlacement;
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
super.createBlockStateDefinition(pBuilder.add(HALF, FACING));
}
@Override
public VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {
VoxelShaper voxelShaper = pState.getValue(HALF) == Half.BOTTOM ? AllShapes.STEP_BOTTOM : AllShapes.STEP_TOP;
return voxelShaper.get(pState.getValue(FACING));
}
@Override
public boolean supportsExternalFaceHiding(BlockState state) {
return true;
}
@Override
public boolean hidesNeighborFace(BlockGetter level, BlockPos pos, BlockState state, BlockState neighborState,
Direction dir) {
if (state.is(this) == neighborState.is(this)
&& getMaterial(level, pos).skipRendering(getMaterial(level, pos.relative(dir)), dir.getOpposite()))
return isOccluded(state, neighborState, dir);
return false;
}
public static boolean isOccluded(BlockState state, BlockState other, Direction pDirection) {
state = state.setValue(WATERLOGGED, false);
other = other.setValue(WATERLOGGED, false);
Half half = state.getValue(HALF);
boolean vertical = pDirection.getAxis() == Axis.Y;
if (half != other.getValue(HALF))
return vertical && (pDirection == Direction.UP) == (half == Half.TOP);
if (vertical)
return false;
Direction facing = state.getValue(FACING);
if (facing.getOpposite() == other.getValue(FACING) && pDirection == facing)
return true;
if (other.getValue(FACING) != facing)
return false;
return pDirection.getAxis() != facing.getAxis();
}
@Override
public BlockState rotate(BlockState pState, Rotation pRot) {
return pState.setValue(FACING, pRot.rotate(pState.getValue(FACING)));
}
@Override
@SuppressWarnings("deprecation")
public BlockState mirror(BlockState pState, Mirror pMirror) {
return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));
}
private static class PlacementHelper implements IPlacementHelper {
@Override
public Predicate<ItemStack> getItemPredicate() {
return AllBlocks.COPYCAT_STEP::isIn;
}
@Override
public Predicate<BlockState> getStatePredicate() {
return AllBlocks.COPYCAT_STEP::has;
}
public int attachedSteps(Level world, BlockPos pos, Direction direction) {
BlockPos checkPos = pos.relative(direction);
BlockState state = world.getBlockState(checkPos);
int count = 0;
while (getStatePredicate().test(state)) {
count++;
checkPos = checkPos.relative(direction);
state = world.getBlockState(checkPos);
}
return count;
}
@Override
public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos,
BlockHitResult ray) {
Direction dir = null;
Direction facing = state.getValue(FACING);
for (Direction nearest : Direction.orderedByNearest(player)) {
if (nearest.getAxis() != facing.getClockWise()
.getAxis())
continue;
dir = nearest;
break;
}
int range = AllConfigs.SERVER.curiosities.placementAssistRange.get();
if (player != null) {
AttributeInstance reach = player.getAttribute(ForgeMod.REACH_DISTANCE.get());
if (reach != null && reach.hasModifier(ExtendoGripItem.singleRangeAttributeModifier))
range += 4;
}
int row = attachedSteps(world, pos, dir);
if (row >= range)
return PlacementOffset.fail();
BlockPos newPos = pos.relative(dir, row + 1);
BlockState newState = world.getBlockState(newPos);
if (!state.canSurvive(world, newPos))
return PlacementOffset.fail();
if (newState.getMaterial()
.isReplaceable())
return PlacementOffset.success(newPos, bState -> {
return bState.setValue(FACING, facing)
.setValue(HALF, state.getValue(HALF));
});
return PlacementOffset.fail();
}
}
}

View file

@ -0,0 +1,87 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.client.resources.model.BakedModel;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.Half;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.client.model.data.IModelData;
public class CopycatStepModel extends CopycatModel {
public CopycatStepModel(BakedModel originalModel) {
super(originalModel);
}
@Override
protected List<BakedQuad> getCroppedQuads(BlockState state, Direction side, Random rand, BlockState material,
IModelData wrappedData) {
Direction facing = state.getOptionalValue(CopycatStepBlock.FACING)
.orElse(Direction.SOUTH);
boolean upperHalf = state.getOptionalValue(CopycatStepBlock.HALF)
.orElse(Half.BOTTOM) == Half.TOP;
Vec3 zero = Vec3.ZERO;
Vec3 up = new Vec3(0, 1, 0);
Vec3 normal = Vec3.atLowerCornerOf(facing.getNormal());
BakedModel model = getModelOf(material);
List<BakedQuad> templateQuads = model.getQuads(material, side, rand, wrappedData);
int size = templateQuads.size();
AABB cube = new AABB(BlockPos.ZERO);
List<BakedQuad> quads = new ArrayList<>();
// 4 Pieces
for (boolean top : Iterate.trueAndFalse) {
for (boolean front : Iterate.trueAndFalse) {
for (int i = 0; i < size; i++) {
BakedQuad quad = templateQuads.get(i);
Direction direction = quad.getDirection();
if (front && direction == facing)
continue;
if (!front && direction == facing.getOpposite())
continue;
if (!top && direction == Direction.UP)
continue;
if (top && direction == Direction.DOWN)
continue;
AABB bb = cube.contract(-normal.x * .75, .75, -normal.z * .75);
if (front)
bb = bb.move(normal.scale(-.75));
if (top)
bb = bb.move(up.scale(.75));
Vec3 offset = zero;
if (front)
offset = offset.add(normal.scale(.5));
if (top != upperHalf)
offset = offset.add(up.scale(upperHalf ? .5 : -.5));
BakedQuad newQuad = QuadHelper.clone(quad);
if (cropAndMove(newQuad, bb, offset))
quads.add(newQuad);
}
}
}
return quads;
}
}

View file

@ -0,0 +1,170 @@
package com.simibubi.create.content.curiosities.frames;
import java.util.List;
import com.google.gson.JsonParser;
import com.mojang.serialization.JsonOps;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.content.contraptions.components.structureMovement.ITransformableTE;
import com.simibubi.create.content.contraptions.components.structureMovement.StructureTransform;
import com.simibubi.create.content.logistics.block.redstone.RoseQuartzLampBlock;
import com.simibubi.create.content.schematics.ISpecialBlockEntityItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement;
import com.simibubi.create.content.schematics.ItemRequirement.ItemUseType;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.utility.Iterate;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraftforge.client.model.data.IModelData;
import net.minecraftforge.client.model.data.ModelDataMap;
import net.minecraftforge.client.model.data.ModelProperty;
import net.minecraftforge.items.ItemHandlerHelper;
public class CopycatTileEntity extends SmartTileEntity implements ISpecialBlockEntityItemRequirement, ITransformableTE {
ItemStack consumedItem;
BlockState baseBlock;
public CopycatTileEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
super(type, pos, state);
baseBlock = AllBlocks.COPYCAT_BASE.getDefaultState();
consumedItem = ItemStack.EMPTY;
}
public void setItem(ItemStack item) {
consumedItem = ItemHandlerHelper.copyStackWithSize(item, 1);
setChanged();
}
public ItemStack getConsumedItem() {
return consumedItem;
}
@Override
public ItemRequirement getRequiredItems(BlockState state) {
if (consumedItem.isEmpty())
return ItemRequirement.NONE;
return new ItemRequirement(ItemUseType.CONSUME, consumedItem);
}
public void setMaterial(BlockState blockState) {
BlockState wrapperState = getBlockState();
if (!baseBlock.is(blockState.getBlock()))
for (Direction side : Iterate.directions) {
BlockPos neighbour = worldPosition.relative(side);
BlockState neighbourState = level.getBlockState(neighbour);
if (neighbourState != wrapperState)
continue;
if (!(level.getBlockEntity(neighbour)instanceof CopycatTileEntity ufte))
continue;
BlockState otherMaterial = ufte.getMaterial();
if (!otherMaterial.is(blockState.getBlock()))
continue;
blockState = otherMaterial;
break;
}
baseBlock = blockState;
if (!level.isClientSide()) {
notifyUpdate();
return;
}
redraw();
}
public boolean hasCustomMaterial() {
return !AllBlocks.COPYCAT_BASE.has(getMaterial());
}
public BlockState getMaterial() {
return baseBlock;
}
public boolean cycleMaterial() {
if (baseBlock.hasProperty(BlockStateProperties.FACING))
setMaterial(baseBlock.cycle(BlockStateProperties.FACING));
else if (baseBlock.hasProperty(BlockStateProperties.HORIZONTAL_FACING))
setMaterial(baseBlock.cycle(BlockStateProperties.HORIZONTAL_FACING));
else if (baseBlock.hasProperty(BlockStateProperties.AXIS))
setMaterial(baseBlock.cycle(BlockStateProperties.AXIS));
else if (baseBlock.hasProperty(BlockStateProperties.HORIZONTAL_AXIS))
setMaterial(baseBlock.cycle(BlockStateProperties.HORIZONTAL_AXIS));
else if (baseBlock.hasProperty(BlockStateProperties.LIT))
setMaterial(baseBlock.cycle(BlockStateProperties.LIT));
else if (baseBlock.hasProperty(RoseQuartzLampBlock.POWERING))
setMaterial(baseBlock.cycle(RoseQuartzLampBlock.POWERING));
else
return false;
return true;
}
@Override
protected void read(CompoundTag tag, boolean clientPacket) {
super.read(tag, clientPacket);
consumedItem = ItemStack.of(tag.getCompound("Item"));
BlockState prevMaterial = baseBlock;
if (!tag.contains("Material"))
return;
JsonOps ops = JsonOps.INSTANCE;
BlockState.CODEC.decode(ops, JsonParser.parseString(tag.getString("Material")))
.result()
.ifPresent(p -> baseBlock = p.getFirst());
if (clientPacket && prevMaterial != baseBlock)
redraw();
}
private void redraw() {
if (!isVirtual())
requestModelDataUpdate();
if (hasLevel()) {
level.sendBlockUpdated(getBlockPos(), getBlockState(), getBlockState(), 16);
level.getChunkSource()
.getLightEngine()
.checkBlock(worldPosition);
}
}
@Override
protected void write(CompoundTag tag, boolean clientPacket) {
super.write(tag, clientPacket);
tag.put("Item", consumedItem.serializeNBT());
JsonOps ops = JsonOps.INSTANCE;
BlockState.CODEC.encode(baseBlock, ops, ops.empty())
.result()
.map(je -> je.toString())
.ifPresent(s -> tag.putString("Material", s));
}
public static final ModelProperty<BlockState> MATERIAL_PROPERTY = new ModelProperty<>();
@Override
public IModelData getModelData() {
return new ModelDataMap.Builder().withInitial(MATERIAL_PROPERTY, baseBlock)
.build();
}
@Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) {}
@Override
public void transform(StructureTransform transform) {
baseBlock = transform.apply(baseBlock);
notifyUpdate();
}
}

View file

@ -0,0 +1,43 @@
package com.simibubi.create.content.curiosities.frames;
import com.simibubi.create.foundation.block.ProperWaterloggedBlock;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.item.context.BlockPlaceContext;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateDefinition.Builder;
import net.minecraft.world.level.material.FluidState;
public abstract class WaterloggedCopycatBlock extends CopycatBlock implements ProperWaterloggedBlock {
public WaterloggedCopycatBlock(Properties pProperties) {
super(pProperties);
registerDefaultState(defaultBlockState().setValue(WATERLOGGED, false));
}
@Override
protected void createBlockStateDefinition(Builder<Block, BlockState> pBuilder) {
super.createBlockStateDefinition(pBuilder.add(WATERLOGGED));
}
@Override
public FluidState getFluidState(BlockState pState) {
return fluidState(pState);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext pContext) {
return withWater(super.getStateForPlacement(pContext), pContext);
}
@Override
public BlockState updateShape(BlockState pState, Direction pDirection, BlockState pNeighborState,
LevelAccessor pLevel, BlockPos pCurrentPos, BlockPos pNeighborPos) {
updateWater(pLevel, pState, pCurrentPos);
return pState;
}
}

View file

@ -28,11 +28,13 @@ public class ConnectedGirderModel extends CTModel {
}
@Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
ConnectionData connectionData = new ConnectionData();
for (Direction d : Iterate.horizontalDirections)
connectionData.setConnected(d, GirderBlock.isConnected(world, pos, state, d));
return super.gatherModelData(builder, world, pos, state).withInitial(CONNECTION_PROPERTY, connectionData);
return super.gatherModelData(builder, world, pos, state, tileData).withInitial(CONNECTION_PROPERTY,
connectionData);
}
@Override

View file

@ -16,14 +16,15 @@ public abstract class BakedModelWrapperWithData extends BakedModelWrapper<BakedM
}
@Override
public final IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state, IModelData tileData) {
public final IModelData getModelData(BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
Builder builder = new ModelDataMap.Builder();
if (originalModel instanceof BakedModelWrapperWithData)
((BakedModelWrapperWithData) originalModel).gatherModelData(builder, world, pos, state);
return gatherModelData(builder, world, pos, state).build();
((BakedModelWrapperWithData) originalModel).gatherModelData(builder, world, pos, state, tileData);
return gatherModelData(builder, world, pos, state, tileData).build();
}
protected abstract ModelDataMap.Builder gatherModelData(ModelDataMap.Builder builder, BlockAndTintGetter world,
BlockPos pos, BlockState state);
BlockPos pos, BlockState state, IModelData tileData);
}

View file

@ -5,6 +5,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Random;
import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import com.simibubi.create.foundation.block.connected.ConnectedTextureBehaviour.CTContext;
import com.simibubi.create.foundation.block.render.QuadHelper;
import com.simibubi.create.foundation.utility.Iterate;
@ -33,7 +34,8 @@ public class CTModel extends BakedModelWrapperWithData {
}
@Override
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state) {
protected Builder gatherModelData(Builder builder, BlockAndTintGetter world, BlockPos pos, BlockState state,
IModelData tileData) {
return builder.withInitial(CT_PROPERTY, createCTData(world, pos, state));
}
@ -41,8 +43,11 @@ public class CTModel extends BakedModelWrapperWithData {
CTData data = new CTData();
MutableBlockPos mutablePos = new MutableBlockPos();
for (Direction face : Iterate.directions) {
BlockState actualState = world.getBlockState(pos);
if (!behaviour.buildContextForOccludedDirections()
&& !Block.shouldRenderFace(state, world, pos, face, mutablePos.setWithOffset(pos, face)))
&& !Block.shouldRenderFace(state, world, pos, face, mutablePos.setWithOffset(pos, face))
&& !(actualState.getBlock()instanceof CopycatBlock ufb
&& !ufb.canFaceBeOccluded(actualState, face)))
continue;
CTType dataType = behaviour.getDataType(state, face);
if (dataType == null)

View file

@ -3,6 +3,8 @@ package com.simibubi.create.foundation.block.connected;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
@ -14,7 +16,8 @@ import net.minecraft.world.level.block.state.BlockState;
public abstract class ConnectedTextureBehaviour {
@Nullable
public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, @NotNull TextureAtlasSprite sprite);
public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction,
@NotNull TextureAtlasSprite sprite);
// TODO: allow more than one data type per state/face?
@Nullable
@ -27,10 +30,18 @@ public abstract class ConnectedTextureBehaviour {
protected boolean isBeingBlocked(BlockState state, BlockAndTintGetter reader, BlockPos pos, BlockPos otherPos,
Direction face) {
BlockPos blockingPos = otherPos.relative(face);
BlockState blockState = reader.getBlockState(pos);
if (blockState.getBlock()instanceof CopycatBlock ufb
&& ufb.isUnblockableConnectivitySide(reader, blockState, face, pos, otherPos))
return false;
return face.getAxis()
.choose(pos.getX(), pos.getY(), pos.getZ()) == face.getAxis()
.choose(otherPos.getX(), otherPos.getY(), otherPos.getZ())
&& connectsTo(state, reader.getBlockState(blockingPos), reader, pos, blockingPos, face);
&& connectsTo(state,
getCTBlockState(reader, blockState, face.getOpposite(), pos.relative(face), blockingPos), reader, pos,
blockingPos, face);
}
public boolean connectsTo(BlockState state, BlockState other, BlockAndTintGetter reader, BlockPos pos,
@ -47,10 +58,27 @@ public abstract class ConnectedTextureBehaviour {
final Direction horizontal, final Direction vertical, int sh, int sv) {
BlockPos p = pos.relative(horizontal, sh)
.relative(vertical, sv);
boolean test = connectsTo(state, reader.getBlockState(p), reader, pos, p, face,
BlockState blockState = reader.getBlockState(pos);
if (blockState.getBlock()instanceof CopycatBlock ufb
&& ufb.isIgnoredConnectivitySide(reader, blockState, face, pos, p))
return false;
return connectsTo(state, getCTBlockState(reader, blockState, face, pos, p), reader, pos, p, face,
sh == 0 ? null : sh == -1 ? horizontal.getOpposite() : horizontal,
sv == 0 ? null : sv == -1 ? vertical.getOpposite() : vertical);
return test;
}
public BlockState getCTBlockState(BlockAndTintGetter reader, BlockState reference, Direction face, BlockPos fromPos,
BlockPos toPos) {
BlockState blockState = reader.getBlockState(toPos);
if (blockState.getBlock()instanceof CopycatBlock ufb) {
BlockState connectiveMaterial = ufb.getConnectiveMaterial(reader, reference, face, fromPos, toPos);
return connectiveMaterial == null ? blockState : connectiveMaterial;
}
return blockState;
}
protected boolean reverseUVs(BlockState state, Direction face) {
@ -75,7 +103,8 @@ public abstract class ConnectedTextureBehaviour {
return axis == Axis.X ? Direction.SOUTH : Direction.WEST;
}
public CTContext buildContext(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face, ContextRequirement requirement) {
public CTContext buildContext(BlockAndTintGetter reader, BlockPos pos, BlockState state, Direction face,
ContextRequirement requirement) {
boolean positive = face.getAxisDirection() == AxisDirection.POSITIVE;
Direction h = getRightDirection(reader, pos, state, face);
Direction v = getUpDirection(reader, pos, state, face);
@ -139,7 +168,8 @@ public abstract class ConnectedTextureBehaviour {
public final boolean up, down, left, right;
public final boolean topLeft, topRight, bottomLeft, bottomRight;
public ContextRequirement(boolean up, boolean down, boolean left, boolean right, boolean topLeft, boolean topRight, boolean bottomLeft, boolean bottomRight) {
public ContextRequirement(boolean up, boolean down, boolean left, boolean right, boolean topLeft,
boolean topRight, boolean bottomLeft, boolean bottomRight) {
this.up = up;
this.down = down;
this.left = left;
@ -239,7 +269,8 @@ public abstract class ConnectedTextureBehaviour {
public static abstract class Base extends ConnectedTextureBehaviour {
@Override
@Nullable
public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction, @Nullable TextureAtlasSprite sprite);
public abstract CTSpriteShiftEntry getShift(BlockState state, Direction direction,
@Nullable TextureAtlasSprite sprite);
@Override
@Nullable

View file

@ -1,5 +1,6 @@
package com.simibubi.create.foundation.block.connected;
import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import com.simibubi.create.content.palettes.ConnectedPillarBlock;
import com.simibubi.create.content.palettes.LayeredBlock;
@ -27,6 +28,10 @@ public class RotatedPillarCTBehaviour extends HorizontalCTBehaviour {
return false;
if (isBeingBlocked(state, reader, pos, otherPos, face))
return false;
if (reader.getBlockState(pos).getBlock() instanceof CopycatBlock)
return true;
if (reader.getBlockState(otherPos).getBlock() instanceof CopycatBlock)
return true;
if (primaryOffset != null && primaryOffset.getAxis() != stateAxis
&& !ConnectedPillarBlock.getConnection(state, primaryOffset))
return false;

View file

@ -6,6 +6,7 @@ import com.mojang.blaze3d.vertex.DefaultVertexFormat;
import com.mojang.blaze3d.vertex.VertexFormat;
import net.minecraft.client.renderer.block.model.BakedQuad;
import net.minecraft.world.phys.Vec3;
public final class QuadHelper {
@ -28,6 +29,13 @@ public final class QuadHelper {
quad.getTintIndex(), quad.getDirection(), quad.getSprite(), quad.isShade());
}
public static Vec3 getXYZ(int[] vertexData, int vertex) {
float x = Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + X_OFFSET]);
float y = Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + Y_OFFSET]);
float z = Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + Z_OFFSET]);
return new Vec3(x, y, z);
}
public static float getU(int[] vertexData, int vertex) {
return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + U_OFFSET]);
}
@ -36,6 +44,12 @@ public final class QuadHelper {
return Float.intBitsToFloat(vertexData[vertex * VERTEX_STRIDE + V_OFFSET]);
}
public static void setXYZ(int[] vertexData, int vertex, Vec3 xyz) {
vertexData[vertex * VERTEX_STRIDE + X_OFFSET] = Float.floatToRawIntBits((float) xyz.x);
vertexData[vertex * VERTEX_STRIDE + Y_OFFSET] = Float.floatToRawIntBits((float) xyz.y);
vertexData[vertex * VERTEX_STRIDE + Z_OFFSET] = Float.floatToRawIntBits((float) xyz.z);
}
public static void setU(int[] vertexData, int vertex, float u) {
vertexData[vertex * VERTEX_STRIDE + U_OFFSET] = Float.floatToRawIntBits(u);
}

View file

@ -15,6 +15,7 @@ import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.simibubi.create.AllBlocks;
import com.simibubi.create.AllTags;
import com.simibubi.create.AllTags.AllBlockTags;
import com.simibubi.create.AllTags.AllItemTags;
import com.simibubi.create.Create;
@ -30,6 +31,7 @@ import com.simibubi.create.content.contraptions.relays.encased.EncasedCogwheelBl
import com.simibubi.create.content.contraptions.relays.encased.EncasedShaftBlock;
import com.simibubi.create.content.curiosities.deco.SlidingDoorBlock;
import com.simibubi.create.content.curiosities.deco.SlidingDoorMovementBehaviour;
import com.simibubi.create.content.curiosities.frames.CopycatBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelBlock.Shape;
import com.simibubi.create.content.logistics.block.belts.tunnel.BeltTunnelItem;
@ -62,6 +64,7 @@ import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.PistonType;
import net.minecraft.world.level.material.Material;
import net.minecraft.world.level.material.MaterialColor;
import net.minecraft.world.level.storage.loot.LootPool;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.LootTable.Builder;
@ -101,6 +104,22 @@ public class BuilderTransformers {
.onRegister(block -> IBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block)));
}
public static <B extends CopycatBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> copycat() {
return b -> b.initialProperties(SharedProperties::softMetal)
.blockstate((c, p) -> p.simpleBlock(c.get(), p.models()
.getExistingFile(p.mcLoc("air"))))
.initialProperties(SharedProperties::softMetal)
.properties(p -> p.noOcclusion()
.color(MaterialColor.NONE))
.addLayer(() -> RenderType::solid)
.addLayer(() -> RenderType::cutout)
.addLayer(() -> RenderType::cutoutMipped)
.addLayer(() -> RenderType::translucent)
.color(() -> CopycatBlock::wrappedColor)
.tag(AllBlockTags.SAFE_NBT.tag)
.transform(AllTags.axeOrPickaxe());
}
public static <B extends TrapDoorBlock, P> NonNullUnaryOperator<BlockBuilder<B, P>> trapdoor(boolean orientable) {
return b -> b.blockstate((c, p) -> {
ModelFile bottom = AssetLookup.partialBaseModel(c, p, "bottom");

View file

@ -208,6 +208,14 @@ public class VecHelper {
Mth.clamp(vec.z, -maxLength, maxLength));
}
public static Vec3 componentMin(Vec3 vec1, Vec3 vec2) {
return new Vec3(Math.min(vec1.x, vec2.x), Math.min(vec1.y, vec2.y), Math.min(vec1.z, vec2.z));
}
public static Vec3 componentMax(Vec3 vec1, Vec3 vec2) {
return new Vec3(Math.max(vec1.x, vec2.x), Math.max(vec1.y, vec2.y), Math.max(vec1.z, vec2.z));
}
public static Vec3 project(Vec3 vec, Vec3 ontoVec) {
if (ontoVec.equals(Vec3.ZERO))
return Vec3.ZERO;

View file

@ -0,0 +1,6 @@
{
"parent": "block/cube_all",
"textures": {
"all": "create:block/copycat_base"
}
}

View file

@ -0,0 +1,33 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"1": "create:block/copycat_base",
"2": "create:block/copycat_base",
"particle": "create:block/copycat_base"
},
"elements": [
{
"from": [0, 0, 0],
"to": [16, 1, 16],
"faces": {
"north": {"uv": [0, 15, 16, 16], "texture": "#2"},
"east": {"uv": [0, 15, 16, 16], "texture": "#2"},
"south": {"uv": [0, 15, 16, 16], "texture": "#2"},
"west": {"uv": [0, 15, 16, 16], "texture": "#2"},
"down": {"uv": [0, 0, 16, 16], "texture": "#1"}
}
},
{
"from": [0, 1, 0],
"to": [16, 3, 16],
"faces": {
"north": {"uv": [0, 0, 16, 2], "texture": "#2"},
"east": {"uv": [0, 0, 16, 2], "texture": "#2"},
"south": {"uv": [0, 0, 16, 2], "texture": "#2"},
"west": {"uv": [0, 0, 16, 2], "texture": "#2"},
"up": {"uv": [0, 0, 16, 16], "texture": "#1"}
}
}
]
}

View file

@ -0,0 +1,51 @@
{
"credit": "Made with Blockbench",
"parent": "block/block",
"textures": {
"1": "create:block/copycat_base",
"2": "create:block/copycat_base",
"particle": "create:block/copycat_base"
},
"elements": [
{
"from": [0, 0, 4],
"to": [16, 4, 8],
"faces": {
"north": {"uv": [0, 12, 16, 16], "texture": "#1"},
"east": {"uv": [12, 12, 16, 16], "texture": "#2"},
"west": {"uv": [0, 12, 4, 16], "texture": "#2"},
"down": {"uv": [0, 12, 16, 16], "texture": "#1"}
}
},
{
"from": [0, 0, 8],
"to": [16, 4, 12],
"faces": {
"east": {"uv": [0, 12, 4, 16], "texture": "#2"},
"south": {"uv": [0, 12, 16, 16], "texture": "#1"},
"west": {"uv": [12, 12, 16, 16], "texture": "#2"},
"down": {"uv": [0, 0, 16, 4], "texture": "#1"}
}
},
{
"from": [0, 4, 8],
"to": [16, 8, 12],
"faces": {
"east": {"uv": [0, 0, 4, 4], "texture": "#2"},
"south": {"uv": [0, 0, 16, 4], "texture": "#1"},
"west": {"uv": [12, 0, 16, 4], "texture": "#2"},
"up": {"uv": [0, 12, 16, 16], "texture": "#1"}
}
},
{
"from": [0, 4, 4],
"to": [16, 8, 8],
"faces": {
"north": {"uv": [0, 0, 16, 4], "texture": "#1"},
"east": {"uv": [12, 0, 16, 4], "texture": "#2"},
"west": {"uv": [0, 0, 4, 4], "texture": "#2"},
"up": {"uv": [0, 0, 16, 4], "texture": "#1"}
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B