From 069d154396dcc65d5c91dd935b20d46596cba8c1 Mon Sep 17 00:00:00 2001 From: simibubi <31564874+simibubi@users.noreply.github.com> Date: Fri, 21 Oct 2022 21:58:30 +0200 Subject: [PATCH] Trapdoors everything - Added Copycat Panels and Copycat Steps --- src/generated/resources/.cache/cache | 52 ++- .../create/blockstates/copycat_base.json | 7 + .../create/blockstates/copycat_panel.json | 7 + .../create/blockstates/copycat_step.json | 7 + .../resources/assets/create/lang/en_ud.json | 3 + .../resources/assets/create/lang/en_us.json | 3 + .../assets/create/lang/unfinished/de_de.json | 5 +- .../assets/create/lang/unfinished/es_cl.json | 5 +- .../assets/create/lang/unfinished/es_es.json | 5 +- .../assets/create/lang/unfinished/fr_fr.json | 5 +- .../assets/create/lang/unfinished/it_it.json | 5 +- .../assets/create/lang/unfinished/ja_jp.json | 5 +- .../assets/create/lang/unfinished/ko_kr.json | 5 +- .../assets/create/lang/unfinished/nl_nl.json | 5 +- .../assets/create/lang/unfinished/pl_pl.json | 5 +- .../assets/create/lang/unfinished/pt_br.json | 5 +- .../assets/create/lang/unfinished/pt_pt.json | 5 +- .../assets/create/lang/unfinished/ro_ro.json | 5 +- .../assets/create/lang/unfinished/ru_ru.json | 5 +- .../assets/create/lang/unfinished/uk_ua.json | 5 +- .../assets/create/lang/unfinished/zh_cn.json | 5 +- .../assets/create/lang/unfinished/zh_tw.json | 5 +- .../create/models/item/copycat_panel.json | 3 + .../create/models/item/copycat_step.json | 3 + .../loot_tables/blocks/copycat_base.json | 20 + .../loot_tables/blocks/copycat_panel.json | 20 + .../loot_tables/blocks/copycat_step.json | 20 + .../create/tags/blocks/copycat_allow.json | 6 + .../data/create/tags/blocks/copycat_deny.json | 8 + .../data/create/tags/blocks/safe_nbt.json | 2 + .../minecraft/tags/blocks/mineable/axe.json | 2 + .../tags/blocks/mineable/pickaxe.json | 3 + .../java/com/simibubi/create/AllBlocks.java | 28 ++ .../java/com/simibubi/create/AllShapes.java | 4 + .../java/com/simibubi/create/AllTags.java | 7 + .../com/simibubi/create/AllTileEntities.java | 6 + .../bearing/BearingContraption.java | 12 +- .../structureMovement/bearing/SailBlock.java | 16 +- .../fluids/PipeAttachmentModel.java | 3 +- .../fluids/tank/FluidTankModel.java | 5 +- .../curiosities/deco/TrainTrapdoorBlock.java | 6 +- .../curiosities/frames/CopycatBlock.java | 365 ++++++++++++++++++ .../curiosities/frames/CopycatModel.java | 221 +++++++++++ .../curiosities/frames/CopycatPanelBlock.java | 206 ++++++++++ .../curiosities/frames/CopycatPanelModel.java | 68 ++++ .../curiosities/frames/CopycatStepBlock.java | 282 ++++++++++++++ .../curiosities/frames/CopycatStepModel.java | 87 +++++ .../curiosities/frames/CopycatTileEntity.java | 170 ++++++++ .../frames/WaterloggedCopycatBlock.java | 43 +++ .../girder/ConnectedGirderModel.java | 6 +- .../connected/BakedModelWrapperWithData.java | 9 +- .../foundation/block/connected/CTModel.java | 9 +- .../connected/ConnectedTextureBehaviour.java | 45 ++- .../connected/RotatedPillarCTBehaviour.java | 5 + .../foundation/block/render/QuadHelper.java | 14 + .../foundation/data/BuilderTransformers.java | 19 + .../create/foundation/utility/VecHelper.java | 8 + .../models/block/copycat_base/block.json | 6 + .../models/block/copycat_base/panel.json | 33 ++ .../models/block/copycat_base/step.json | 51 +++ .../create/textures/block/copycat_base.png | Bin 0 -> 265 bytes 61 files changed, 1917 insertions(+), 63 deletions(-) create mode 100644 src/generated/resources/assets/create/blockstates/copycat_base.json create mode 100644 src/generated/resources/assets/create/blockstates/copycat_panel.json create mode 100644 src/generated/resources/assets/create/blockstates/copycat_step.json create mode 100644 src/generated/resources/assets/create/models/item/copycat_panel.json create mode 100644 src/generated/resources/assets/create/models/item/copycat_step.json create mode 100644 src/generated/resources/data/create/loot_tables/blocks/copycat_base.json create mode 100644 src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json create mode 100644 src/generated/resources/data/create/loot_tables/blocks/copycat_step.json create mode 100644 src/generated/resources/data/create/tags/blocks/copycat_allow.json create mode 100644 src/generated/resources/data/create/tags/blocks/copycat_deny.json create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatBlock.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatModel.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelBlock.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelModel.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepBlock.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepModel.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/CopycatTileEntity.java create mode 100644 src/main/java/com/simibubi/create/content/curiosities/frames/WaterloggedCopycatBlock.java create mode 100644 src/main/resources/assets/create/models/block/copycat_base/block.json create mode 100644 src/main/resources/assets/create/models/block/copycat_base/panel.json create mode 100644 src/main/resources/assets/create/models/block/copycat_base/step.json create mode 100644 src/main/resources/assets/create/textures/block/copycat_base.png diff --git a/src/generated/resources/.cache/cache b/src/generated/resources/.cache/cache index c345e5268..10fd2ce98 100644 --- a/src/generated/resources/.cache/cache +++ b/src/generated/resources/.cache/cache @@ -62,6 +62,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 @@ -558,24 +561,24 @@ bf2b0310500213ff853c748c236eb5d01f61658e assets/create/blockstates/yellow_toolbo 5616dda664dd106d576848124fc0fc1de18d0fd3 assets/create/blockstates/yellow_valve_handle.json 7f39521b211441f5c3e06d60c5978cebe16cacfb assets/create/blockstates/zinc_block.json b7181bcd8182b2f17088e5aa881f374c9c65470c assets/create/blockstates/zinc_ore.json -f85edc574ee6de0de7693ffb031266643db6724a assets/create/lang/en_ud.json -c219c77242e645f32704201dd80e279b3759b794 assets/create/lang/en_us.json -cf37534c3f98098f42b181083fd7cc1063ac2bbb assets/create/lang/unfinished/de_de.json -83d427726fdc38ec3c5b8c3c0f6f87f49d3e5ff3 assets/create/lang/unfinished/es_cl.json -d21caeb0cbe871e38dc101c34ab89ece3cbe2127 assets/create/lang/unfinished/es_es.json -2215688baa2b0beffe0c19f71a3238df1d01b0c1 assets/create/lang/unfinished/fr_fr.json -79484f2c3eba2b40f5d82ffdc3abeb3d2e6962d2 assets/create/lang/unfinished/it_it.json -d659570c9dc89653f03cd4cc82ed50db443638d8 assets/create/lang/unfinished/ja_jp.json -03c30521d9b1bc7a6eb85d2a59a4c4676dca581e assets/create/lang/unfinished/ko_kr.json -3a56d579d022cc1b20746e9d3a1483e6fa8fb4be assets/create/lang/unfinished/nl_nl.json -d5bfeacb442236c8b075fddb41364f85c8cb7feb assets/create/lang/unfinished/pl_pl.json -0f3f51d065d896a7e3b4abd8c2801fa3e8fbd8c3 assets/create/lang/unfinished/pt_br.json -9f2ec0b2f8fa9b380c7edb56bfb806bcce621cce assets/create/lang/unfinished/pt_pt.json -1f88f0d91bdf5c68224cb65249f77272771939c9 assets/create/lang/unfinished/ro_ro.json -928ac3ad2ab5e7fa3d582b8b956258c110bea868 assets/create/lang/unfinished/ru_ru.json -ed29ef4ae8f3633533485d56f7fa8cb77b790a0a assets/create/lang/unfinished/uk_ua.json -e5cf7b657be816bc15b331dd058f7ccdabee8c14 assets/create/lang/unfinished/zh_cn.json -316dae07f95fb65c984fe7c424b566eb8ddba5f9 assets/create/lang/unfinished/zh_tw.json +5a971b8b9e5c42c6ffb3d40919f7e2c878eb10d6 assets/create/lang/en_ud.json +240eeda3e8c255d3c6f956b6976aaf7d777c5af3 assets/create/lang/en_us.json +2d9d88acc6611b38131cc3abcca3e73eaed20b18 assets/create/lang/unfinished/de_de.json +3c37dc0f6b0a50fe4a5c6ebf16c5d57d15ef95a4 assets/create/lang/unfinished/es_cl.json +7cc3b51abbe4123a03194e87c20832334fbb70a0 assets/create/lang/unfinished/es_es.json +c085d2a7a0cebe2cbc15a403f551680c06c42fca assets/create/lang/unfinished/fr_fr.json +4f5c9f5fed24d1e25fb901e289ee13148e52d194 assets/create/lang/unfinished/it_it.json +e780d3d95ed49fc4de49123e842ab4ed7d9fa046 assets/create/lang/unfinished/ja_jp.json +201b5578befd5666177172407e48c014d2a6fc8f assets/create/lang/unfinished/ko_kr.json +1980d6b9c90dc294e13ee79ea33f37bf8e17e192 assets/create/lang/unfinished/nl_nl.json +5f410564891fcc2eb4e471cfaacc3e582cd0384a assets/create/lang/unfinished/pl_pl.json +1995a20285f1aab0428c2ccecbc37d5b1bb026d1 assets/create/lang/unfinished/pt_br.json +f4b94a7fa0ff3934319ec2b7b784ebabf921c795 assets/create/lang/unfinished/pt_pt.json +14e743f1c308ce2cc26c9780445dd982b638808b assets/create/lang/unfinished/ro_ro.json +dae7635ac70929d8f4fc62bf863d53a199da099e assets/create/lang/unfinished/ru_ru.json +b6b17ca9c6dafaa818bd03c5aeb18f6b88467eee assets/create/lang/unfinished/uk_ua.json +9e2e281ffc80c7c577599b200a80c8cebdab25c7 assets/create/lang/unfinished/zh_cn.json +cf850c70ccd87d42f7674c2b8dcfb0bee2d0f854 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 @@ -1690,6 +1693,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 @@ -3438,6 +3443,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 @@ -5626,11 +5634,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 @@ -5725,8 +5735,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 -71480793b5e5ac5eb33c5271118c62227a2769d8 data/minecraft/tags/blocks/mineable/axe.json -77511f0fca91aa40c8b2566bf9bfb78964a56db3 data/minecraft/tags/blocks/mineable/pickaxe.json +52c7b4b803dd20f67ed43385a586fdb9d625d926 data/minecraft/tags/blocks/mineable/axe.json +0e6abdd34fa4feb2d524980717a1767e1bade134 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 diff --git a/src/generated/resources/assets/create/blockstates/copycat_base.json b/src/generated/resources/assets/create/blockstates/copycat_base.json new file mode 100644 index 000000000..739d7181a --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_base.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "create:block/copycat_base/block" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_panel.json b/src/generated/resources/assets/create/blockstates/copycat_panel.json new file mode 100644 index 000000000..2c8f02f06 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_panel.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/blockstates/copycat_step.json b/src/generated/resources/assets/create/blockstates/copycat_step.json new file mode 100644 index 000000000..2c8f02f06 --- /dev/null +++ b/src/generated/resources/assets/create/blockstates/copycat_step.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "minecraft:block/air" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/lang/en_ud.json b/src/generated/resources/assets/create/lang/en_ud.json index d57821dd5..b81beaaf3 100644 --- a/src/generated/resources/assets/create/lang/en_ud.json +++ b/src/generated/resources/assets/create/lang/en_ud.json @@ -63,6 +63,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", diff --git a/src/generated/resources/assets/create/lang/en_us.json b/src/generated/resources/assets/create/lang/en_us.json index f29227a7a..28f1c5000 100644 --- a/src/generated/resources/assets/create/lang/en_us.json +++ b/src/generated/resources/assets/create/lang/en_us.json @@ -66,6 +66,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/de_de.json b/src/generated/resources/assets/create/lang/unfinished/de_de.json index ec0ab8c0d..481fc99af 100644 --- a/src/generated/resources/assets/create/lang/unfinished/de_de.json +++ b/src/generated/resources/assets/create/lang/unfinished/de_de.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 842", + "_": "Missing Localizations: 845", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_cl.json b/src/generated/resources/assets/create/lang/unfinished/es_cl.json index b1cb4225f..c2c6af034 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_cl.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_cl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 988", + "_": "Missing Localizations: 991", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/es_es.json b/src/generated/resources/assets/create/lang/unfinished/es_es.json index 9866e0ed4..519d4146f 100644 --- a/src/generated/resources/assets/create/lang/unfinished/es_es.json +++ b/src/generated/resources/assets/create/lang/unfinished/es_es.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 8", + "_": "Missing Localizations: 11", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json index a40d4bfce..09db7b88a 100644 --- a/src/generated/resources/assets/create/lang/unfinished/fr_fr.json +++ b/src/generated/resources/assets/create/lang/unfinished/fr_fr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 2139", + "_": "Missing Localizations: 2142", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/it_it.json b/src/generated/resources/assets/create/lang/unfinished/it_it.json index 39c5e5ac9..fe86a13b9 100644 --- a/src/generated/resources/assets/create/lang/unfinished/it_it.json +++ b/src/generated/resources/assets/create/lang/unfinished/it_it.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 2", + "_": "Missing Localizations: 5", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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)", diff --git a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json index 29408f90f..36ab093e4 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ja_jp.json +++ b/src/generated/resources/assets/create/lang/unfinished/ja_jp.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 4", + "_": "Missing Localizations: 7", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "クリエイティブモーター", diff --git a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json index 92e403ed6..007566428 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ko_kr.json +++ b/src/generated/resources/assets/create/lang/unfinished/ko_kr.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 8", + "_": "Missing Localizations: 11", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "크리에이티브 모터", diff --git a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json index 319e3974f..94fef7ed7 100644 --- a/src/generated/resources/assets/create/lang/unfinished/nl_nl.json +++ b/src/generated/resources/assets/create/lang/unfinished/nl_nl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 2487", + "_": "Missing Localizations: 2490", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json index be600d683..cdabf61a7 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pl_pl.json +++ b/src/generated/resources/assets/create/lang/unfinished/pl_pl.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 12", + "_": "Missing Localizations: 15", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_br.json b/src/generated/resources/assets/create/lang/unfinished/pt_br.json index 4be946869..269e385d8 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_br.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_br.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 1331", + "_": "Missing Localizations: 1334", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json index a62924d83..1e1716d4f 100644 --- a/src/generated/resources/assets/create/lang/unfinished/pt_pt.json +++ b/src/generated/resources/assets/create/lang/unfinished/pt_pt.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 2196", + "_": "Missing Localizations: 2199", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json b/src/generated/resources/assets/create/lang/unfinished/ro_ro.json index 25aa3227a..dfaa0757e 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ro_ro.json +++ b/src/generated/resources/assets/create/lang/unfinished/ro_ro.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 655", + "_": "Missing Localizations: 658", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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", diff --git a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json index 28d2f0826..e5a5a62e5 100644 --- a/src/generated/resources/assets/create/lang/unfinished/ru_ru.json +++ b/src/generated/resources/assets/create/lang/unfinished/ru_ru.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 0", + "_": "Missing Localizations: 3", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "Творческий мотор", diff --git a/src/generated/resources/assets/create/lang/unfinished/uk_ua.json b/src/generated/resources/assets/create/lang/unfinished/uk_ua.json index 94152cfd6..1c2b02d45 100644 --- a/src/generated/resources/assets/create/lang/unfinished/uk_ua.json +++ b/src/generated/resources/assets/create/lang/unfinished/uk_ua.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 986", + "_": "Missing Localizations: 989", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "Творчий мотор", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json index f4be7ff19..2df513bed 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_cn.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_cn.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 0", + "_": "Missing Localizations: 3", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "创造马达", diff --git a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json index 1af6b480c..fa3911d7d 100644 --- a/src/generated/resources/assets/create/lang/unfinished/zh_tw.json +++ b/src/generated/resources/assets/create/lang/unfinished/zh_tw.json @@ -1,5 +1,5 @@ { - "_": "Missing Localizations: 8", + "_": "Missing Localizations: 11", "_": "->------------------------] Game Elements [------------------------<-", @@ -67,6 +67,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": "創造馬達", diff --git a/src/generated/resources/assets/create/models/item/copycat_panel.json b/src/generated/resources/assets/create/models/item/copycat_panel.json new file mode 100644 index 000000000..5772b8c88 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copycat_panel.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/copycat_base/panel" +} \ No newline at end of file diff --git a/src/generated/resources/assets/create/models/item/copycat_step.json b/src/generated/resources/assets/create/models/item/copycat_step.json new file mode 100644 index 000000000..dd2286908 --- /dev/null +++ b/src/generated/resources/assets/create/models/item/copycat_step.json @@ -0,0 +1,3 @@ +{ + "parent": "create:block/copycat_base/step" +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json new file mode 100644 index 000000000..3da3a59b4 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_base.json @@ -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" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json new file mode 100644 index 000000000..920edaf46 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_panel.json @@ -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" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json b/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json new file mode 100644 index 000000000..880a818c1 --- /dev/null +++ b/src/generated/resources/data/create/loot_tables/blocks/copycat_step.json @@ -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" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/copycat_allow.json b/src/generated/resources/data/create/tags/blocks/copycat_allow.json new file mode 100644 index 000000000..01825818a --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/copycat_allow.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "minecraft:barrel" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/copycat_deny.json b/src/generated/resources/data/create/tags/blocks/copycat_deny.json new file mode 100644 index 000000000..14671651f --- /dev/null +++ b/src/generated/resources/data/create/tags/blocks/copycat_deny.json @@ -0,0 +1,8 @@ +{ + "replace": false, + "values": [ + "#minecraft:cauldrons", + "#minecraft:saplings", + "#minecraft:climbable" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/create/tags/blocks/safe_nbt.json b/src/generated/resources/data/create/tags/blocks/safe_nbt.json index 3d607530a..d0e85fba3 100644 --- a/src/generated/resources/data/create/tags/blocks/safe_nbt.json +++ b/src/generated/resources/data/create/tags/blocks/safe_nbt.json @@ -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", diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json index 3dfa8509f..4bf141d4f 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -97,6 +97,8 @@ "create:rotation_speed_controller", "create:mechanical_arm", "create:railway_casing", + "create:copycat_step", + "create:copycat_panel", "create:content_observer", "create:stockpile_switch", "create:creative_crate", diff --git a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json index 3394d19b5..926638381 100644 --- a/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json +++ b/src/generated/resources/data/minecraft/tags/blocks/mineable/pickaxe.json @@ -124,6 +124,9 @@ "create:train_trapdoor", "create:framed_glass_door", "create:framed_glass_trapdoor", + "create:copycat_base", + "create:copycat_step", + "create:copycat_panel", "create:item_vault", "create:andesite_funnel", "create:andesite_belt_funnel", diff --git a/src/main/java/com/simibubi/create/AllBlocks.java b/src/main/java/com/simibubi/create/AllBlocks.java index 1fd9d6434..87a991379 100644 --- a/src/main/java/com/simibubi/create/AllBlocks.java +++ b/src/main/java/com/simibubi/create/AllBlocks.java @@ -139,6 +139,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; @@ -1629,6 +1633,30 @@ public class AllBlocks { .addLayer(() -> RenderType::cutoutMipped) .register(); + public static final BlockEntry 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 COPYCAT_STEP = + REGISTRATE.block("copycat_step", CopycatStepBlock::new) + .transform(BuilderTransformers.copycat()) + .onRegister(CreateRegistrate.blockModel(() -> CopycatStepModel::new)) + .item() + .transform(customItemModel("copycat_base", "step")) + .register(); + + public static final BlockEntry 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 ITEM_VAULT = REGISTRATE.block("item_vault", ItemVaultBlock::new) .initialProperties(SharedProperties::softMetal) .properties(p -> p.color(MaterialColor.TERRACOTTA_BLUE)) diff --git a/src/main/java/com/simibubi/create/AllShapes.java b/src/main/java/com/simibubi/create/AllShapes.java index 57ae5e08c..d00af352d 100644 --- a/src/main/java/com/simibubi/create/AllShapes.java +++ b/src/main/java/com/simibubi/create/AllShapes.java @@ -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(), @@ -121,6 +122,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), NIXIE_TUBE = shape(9, 0, 5, 15, 12, 11).add(1, 0, 5, 7, 12, 11) diff --git a/src/main/java/com/simibubi/create/AllTags.java b/src/main/java/com/simibubi/create/AllTags.java index facf15ed9..560454958 100644 --- a/src/main/java/com/simibubi/create/AllTags.java +++ b/src/main/java/com/simibubi/create/AllTags.java @@ -125,6 +125,8 @@ public class AllTags { WINDOWABLE, WRENCH_PICKUP, TREE_ATTACHMENTS, + COPYCAT_ALLOW, + COPYCAT_DENY, RELOCATION_NOT_SUPPORTED(FORGE), WG_STONE(FORGE), @@ -407,6 +409,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); diff --git a/src/main/java/com/simibubi/create/AllTileEntities.java b/src/main/java/com/simibubi/create/AllTileEntities.java index 3647ad732..47e9b54a6 100644 --- a/src/main/java/com/simibubi/create/AllTileEntities.java +++ b/src/main/java/com/simibubi/create/AllTileEntities.java @@ -137,6 +137,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; @@ -804,6 +805,11 @@ public class AllTileEntities { .validBlocks(AllBlocks.TRAIN_DOOR, AllBlocks.FRAMED_GLASS_DOOR) .register(); + public static final BlockEntityEntry UNIVERSAL_FRAME = Create.registrate() + .tileEntity("universal_frame", CopycatTileEntity::new) + .validBlocks(AllBlocks.COPYCAT_PANEL, AllBlocks.COPYCAT_STEP) + .register(); + public static final BlockEntityEntry FLAP_DISPLAY = Create.registrate() .tileEntity("flap_display", FlapDisplayTileEntity::new) .instance(() -> MechanicalCrafterInstance::new) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java index 788b111b7..b1a5d142a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/BearingContraption.java @@ -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 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 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); diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java index ee71a2dd5..3f81ad17c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/structureMovement/bearing/SailBlock.java @@ -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 directions = IPlacementHelper.orderedByDistanceExceptAxis(pos, hit, state.getValue(FACING).getAxis()); + List 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() diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java index bc6056670..5e143089a 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/PipeAttachmentModel.java @@ -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); diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java index e239afc29..c6b25049c 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/tank/FluidTankModel.java @@ -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 diff --git a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java b/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java index 7fbd3233b..339354b4c 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java +++ b/src/main/java/com/simibubi/create/content/curiosities/deco/TrainTrapdoorBlock.java @@ -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); diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatBlock.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatBlock.java new file mode 100644 index 000000000..b37a50e1b --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatBlock.java @@ -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, IWrenchable { + + public CopycatBlock(Properties pProperties) { + super(pProperties); + } + + @Nullable + @Override + public BlockEntityTicker getTicker(Level p_153212_, BlockState p_153213_, + BlockEntityType 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 getTileEntityClass() { + return CopycatTileEntity.class; + } + + @Override + public BlockEntityType getTileEntityType() { + return AllTileEntities.UNIVERSAL_FRAME.get(); + } + + // Connected Textures + + @Nullable + /** + * The wrapped blockstate at toPos. Wrapper guaranteed to be a block of this + * type
+ * 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); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatModel.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatModel.java new file mode 100644 index 000000000..1b20fe6cf --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatModel.java @@ -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 WRAPPED_DATA_PROPERTY = new ModelProperty<>(); + private static final ModelProperty 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 getQuads(BlockState state, Direction side, Random rand, IModelData extraData) { + List 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 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()]; + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelBlock.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelBlock.java new file mode 100644 index 000000000..679350113 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelBlock.java @@ -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 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 getItemPredicate() { + return AllBlocks.COPYCAT_PANEL::isIn; + } + + @Override + public Predicate getStatePredicate() { + return AllBlocks.COPYCAT_PANEL::has; + } + + @Override + public PlacementOffset getOffset(Player player, Level world, BlockState state, BlockPos pos, + BlockHitResult ray) { + List 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))); + } + } + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelModel.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelModel.java new file mode 100644 index 000000000..efaac4c3d --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatPanelModel.java @@ -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 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 templateQuads = model.getQuads(material, side, rand, wrappedData); + int size = templateQuads.size(); + + List 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; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepBlock.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepBlock.java new file mode 100644 index 000000000..34dd69ec7 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepBlock.java @@ -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 = 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 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 getItemPredicate() { + return AllBlocks.COPYCAT_STEP::isIn; + } + + @Override + public Predicate 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(); + } + + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepModel.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepModel.java new file mode 100644 index 000000000..a13ca5d38 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatStepModel.java @@ -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 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 templateQuads = model.getQuads(material, side, rand, wrappedData); + int size = templateQuads.size(); + AABB cube = new AABB(BlockPos.ZERO); + + List 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; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatTileEntity.java b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatTileEntity.java new file mode 100644 index 000000000..9b4d7cef4 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/CopycatTileEntity.java @@ -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 MATERIAL_PROPERTY = new ModelProperty<>(); + + @Override + public IModelData getModelData() { + return new ModelDataMap.Builder().withInitial(MATERIAL_PROPERTY, baseBlock) + .build(); + } + + @Override + public void addBehaviours(List behaviours) {} + + @Override + public void transform(StructureTransform transform) { + baseBlock = transform.apply(baseBlock); + notifyUpdate(); + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/frames/WaterloggedCopycatBlock.java b/src/main/java/com/simibubi/create/content/curiosities/frames/WaterloggedCopycatBlock.java new file mode 100644 index 000000000..169d73039 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/curiosities/frames/WaterloggedCopycatBlock.java @@ -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 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; + } + +} diff --git a/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java b/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java index 373800fd2..4c333dfcd 100644 --- a/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java +++ b/src/main/java/com/simibubi/create/content/curiosities/girder/ConnectedGirderModel.java @@ -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 diff --git a/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java b/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java index 2cc960565..3336098d9 100644 --- a/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java +++ b/src/main/java/com/simibubi/create/foundation/block/connected/BakedModelWrapperWithData.java @@ -16,14 +16,15 @@ public abstract class BakedModelWrapperWithData extends BakedModelWrapper IBogeyBlock.register(RegisteredObjects.getKeyOrThrow(block))); } + public static NonNullUnaryOperator> 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 NonNullUnaryOperator> trapdoor(boolean orientable) { return b -> b.blockstate((c, p) -> { ModelFile bottom = AssetLookup.partialBaseModel(c, p, "bottom"); diff --git a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java index ffb52b2b3..e92d79f31 100644 --- a/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java +++ b/src/main/java/com/simibubi/create/foundation/utility/VecHelper.java @@ -207,6 +207,14 @@ public class VecHelper { return new Vec3(Mth.clamp(vec.x, -maxLength, maxLength), Mth.clamp(vec.y, -maxLength, maxLength), 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)) diff --git a/src/main/resources/assets/create/models/block/copycat_base/block.json b/src/main/resources/assets/create/models/block/copycat_base/block.json new file mode 100644 index 000000000..ac8beca4d --- /dev/null +++ b/src/main/resources/assets/create/models/block/copycat_base/block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "create:block/copycat_base" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/copycat_base/panel.json b/src/main/resources/assets/create/models/block/copycat_base/panel.json new file mode 100644 index 000000000..50dc651f4 --- /dev/null +++ b/src/main/resources/assets/create/models/block/copycat_base/panel.json @@ -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"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/models/block/copycat_base/step.json b/src/main/resources/assets/create/models/block/copycat_base/step.json new file mode 100644 index 000000000..ed41c928a --- /dev/null +++ b/src/main/resources/assets/create/models/block/copycat_base/step.json @@ -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"} + } + } + ] +} \ No newline at end of file diff --git a/src/main/resources/assets/create/textures/block/copycat_base.png b/src/main/resources/assets/create/textures/block/copycat_base.png new file mode 100644 index 0000000000000000000000000000000000000000..7c2dd598cffbf0e2f75d61e397920e5f1343177d GIT binary patch literal 265 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJV{wqX6T`Z5GB1G~mUKs7M+SzC z{oH>NS%G}f0G|-oj_%4?OD1IHC9gfUGAJzA%Ec8ZlWt(T8c4C11o;L32LlEvZ)P{3 z5NCl$WHAE+-$4*&+%YlxEl@Da)5S4FBiOZ{o9}=DhttRE|H}MVa#egE9KFUQ!J64~ z_|WIzii3Oh_`jRF;mJ*z2Lg`roKfBivs<=Lk>++$t6!l1Um>S_uS4W}j*OCL>Ehcj y{EicroG`ncW5ek*p(=;kb-K3oA<-pMzcO5CXRc2>ySE-_D}$%2pUXO@geCw@wOY^s literal 0 HcmV?d00001