From 3621b15989d7ccab7e981f5e78b0fdf9be046490 Mon Sep 17 00:00:00 2001 From: stfwi Date: Sun, 8 Aug 2021 09:10:14 +0200 Subject: [PATCH] Initial 1.17 port. --- build.gradle | 89 +- gradle.properties | 7 +- gradle/wrapper/gradle-wrapper.jar | Bin 54708 -> 59536 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 55 +- gradlew.bat | 43 +- meta/update.json | 6 +- readme.md | 6 +- .../java/wile/engineersdecor/ModConfig.java | 1254 +++---- .../java/wile/engineersdecor/ModContent.java | 2820 +++++++------- .../engineersdecor/ModEngineersDecor.java | 267 +- .../engineersdecor/blocks/DecorBlock.java | 169 +- .../wile/engineersdecor/blocks/EdBreaker.java | 705 ++-- .../engineersdecor/blocks/EdCatwalkBlock.java | 269 +- .../blocks/EdCatwalkStairsBlock.java | 369 +- .../blocks/EdCatwalkTopAlignedBlock.java | 217 +- .../wile/engineersdecor/blocks/EdChair.java | 399 +- .../engineersdecor/blocks/EdChimneyBlock.java | 199 +- .../blocks/EdChimneyTrunkBlock.java | 73 +- .../blocks/EdCornerOrnamentedBlock.java | 143 +- .../blocks/EdCraftingTable.java | 3306 ++++++++--------- .../engineersdecor/blocks/EdDoorBlock.java | 31 - .../blocks/EdDoubleGateBlock.java | 321 +- .../wile/engineersdecor/blocks/EdDropper.java | 1937 +++++----- .../blocks/EdElectricalFurnace.java | 1668 +++++---- .../engineersdecor/blocks/EdFenceBlock.java | 59 +- .../blocks/EdFloorGratingBlock.java | 145 +- .../engineersdecor/blocks/EdFluidBarrel.java | 827 ++--- .../engineersdecor/blocks/EdFluidFunnel.java | 816 ++-- .../wile/engineersdecor/blocks/EdFreezer.java | 791 ++-- .../wile/engineersdecor/blocks/EdFurnace.java | 1859 +++++---- .../engineersdecor/blocks/EdGlassBlock.java | 107 +- .../engineersdecor/blocks/EdGroundBlock.java | 18 - .../engineersdecor/blocks/EdHatchBlock.java | 274 +- .../wile/engineersdecor/blocks/EdHopper.java | 1924 +++++----- .../blocks/EdHorizontalSupportBlock.java | 338 +- .../engineersdecor/blocks/EdLabeledCrate.java | 1254 +++---- .../engineersdecor/blocks/EdLadderBlock.java | 239 +- .../wile/engineersdecor/blocks/EdMilker.java | 1541 ++++---- .../blocks/EdMineralSmelter.java | 1167 +++--- .../engineersdecor/blocks/EdPipeValve.java | 551 ++- .../wile/engineersdecor/blocks/EdPlacer.java | 1651 ++++---- .../engineersdecor/blocks/EdRailingBlock.java | 196 +- .../engineersdecor/blocks/EdRoofBlock.java | 457 ++- .../engineersdecor/blocks/EdSlabBlock.java | 18 - .../blocks/EdSlabSliceBlock.java | 19 - .../engineersdecor/blocks/EdSolarPanel.java | 495 ++- .../engineersdecor/blocks/EdStairsBlock.java | 22 - .../blocks/EdStraightPoleBlock.java | 172 +- .../engineersdecor/blocks/EdTestBlock.java | 674 ++-- .../engineersdecor/blocks/EdTreeCutter.java | 544 ++- .../engineersdecor/blocks/EdWallBlock.java | 66 +- .../blocks/EdWasteIncinerator.java | 1307 +++---- .../engineersdecor/blocks/EdWindowBlock.java | 181 +- .../engineersdecor/blocks/IDecorBlock.java | 15 - .../detail/ExternalObjects.java | 22 - .../engineersdecor/detail/ModRenderers.java | 334 +- .../engineersdecor/detail/TreeCutting.java | 360 +- .../engineersdecor/eapi/jei/JEIPlugin.java | 188 +- .../wile/engineersdecor/items/EdItem.java | 92 +- .../libmc/blocks/SlabSliceBlock.java | 432 +-- .../libmc/blocks/StandardBlocks.java | 1025 ++--- .../libmc/blocks/StandardDoorBlock.java | 330 +- .../libmc/blocks/StandardEntityBlocks.java | 68 + .../libmc/blocks/StandardFenceBlock.java | 394 +- .../libmc/blocks/StandardStairsBlock.java | 112 +- .../libmc/blocks/VariantSlabBlock.java | 407 +- .../libmc/blocks/VariantWallBlock.java | 395 +- .../libmc/client/ContainerGui.java | 42 - .../libmc/datagen/AssetsDataGen.java | 48 - .../libmc/datagen/LootTableGen.java | 96 - .../libmc/detail/Auxiliaries.java | 896 +++-- .../engineersdecor/libmc/detail/Crafting.java | 364 ++ .../libmc/detail/DataFixing.java | 66 - .../engineersdecor/libmc/detail/Fluidics.java | 775 ++-- .../libmc/detail/Inventories.java | 1782 +++++---- .../libmc/detail/Networking.java | 618 +-- .../libmc/detail/OptionalRecipeCondition.java | 396 +- .../engineersdecor/libmc/detail/Overlay.java | 233 +- .../engineersdecor/libmc/detail/RfEnergy.java | 316 +- .../libmc/detail/RsSignals.java | 45 + .../libmc/detail/SidedProxy.java | 133 +- .../libmc/detail/TooltipDisplay.java | 233 +- .../engineersdecor/libmc/ui/Containers.java | 119 + .../wile/engineersdecor/libmc/ui/Guis.java | 322 ++ src/main/resources/META-INF/mods.toml | 6 +- .../blockstates/gas_concrete.json | 14 - .../blockstates/gas_concrete_slab.json | 16 - .../blockstates/gas_concrete_stairs.json | 44 - .../blockstates/gas_concrete_wall.json | 13 - .../blockstates/halfslab_gas_concrete.json | 19 - .../blockstates/treated_wood_side_table.json | 1 - .../assets/engineersdecor/lang/en_us.json | 10 - .../assets/engineersdecor/lang/es_ar.json | 10 - .../assets/engineersdecor/lang/es_cl.json | 10 - .../assets/engineersdecor/lang/es_ec.json | 10 - .../assets/engineersdecor/lang/es_es.json | 10 - .../assets/engineersdecor/lang/es_mx.json | 10 - .../assets/engineersdecor/lang/es_uy.json | 10 - .../assets/engineersdecor/lang/es_ve.json | 10 - .../assets/engineersdecor/lang/ru_ru.json | 10 - .../assets/engineersdecor/lang/zh_cn.json | 194 +- .../block/concrete/gas_concrete_model0.json | 1 - .../block/concrete/gas_concrete_model1.json | 1 - .../block/concrete/gas_concrete_model2.json | 1 - .../block/concrete/gas_concrete_model3.json | 1 - .../block/concrete/gas_concrete_model4.json | 1 - .../block/concrete/gas_concrete_model5.json | 1 - .../block/concrete/gas_concrete_model6.json | 1 - .../block/concrete/gas_concrete_model7.json | 1 - .../block/concrete/gas_concrete_stairs.json | 8 - .../concrete/gas_concrete_stairs_inner.json | 8 - .../concrete/gas_concrete_stairs_outer.json | 8 - .../concrete/gas_concrete_tile_model0.json | 1 - .../concrete/gas_concrete_wall_default.json | 7 - .../concrete/gas_concrete_wall_inventory.json | 7 - .../concrete/gas_concrete_wall_post.json | 7 - .../concrete/gas_concrete_wall_side.json | 7 - .../treated_wood_side_table_model.json | 207 -- .../gas_concrete_slab_s0v0_model.json | 1 - .../gas_concrete_slab_s0v1_model.json | 1 - .../gas_concrete_slab_s0v2_model.json | 1 - .../gas_concrete_slab_s0v3_model.json | 1 - .../gas_concrete_slab_s1v0_model.json | 1 - .../gas_concrete_slab_s1v1_model.json | 1 - .../gas_concrete_slab_s1v2_model.json | 1 - .../gas_concrete_slab_s1v3_model.json | 1 - .../gas_concrete_slab_s2v0_model.json | 1 - .../gas_concrete_slab_s2v1_model.json | 1 - .../gas_concrete_slab_s2v2_model.json | 1 - .../gas_concrete_slab_s2v3_model.json | 1 - .../halfslab_gas_concrete_s0_model.json | 1 - .../halfslab_gas_concrete_s1_model.json | 1 - .../halfslab_gas_concrete_s2_model.json | 1 - .../halfslab_gas_concrete_s3_model.json | 1 - .../halfslab_gas_concrete_s4_model.json | 1 - .../halfslab_gas_concrete_s5_model.json | 1 - .../halfslab_gas_concrete_s6_model.json | 1 - .../halfslab_gas_concrete_s7_model.json | 1 - .../halfslab_gas_concrete_s8_model.json | 1 - .../halfslab_gas_concrete_s9_model.json | 1 - .../halfslab_gas_concrete_sa_model.json | 1 - .../halfslab_gas_concrete_sb_model.json | 1 - .../halfslab_gas_concrete_sc_model.json | 1 - .../halfslab_gas_concrete_sd_model.json | 1 - .../halfslab_gas_concrete_se_model.json | 1 - .../models/item/gas_concrete.json | 1 - .../models/item/gas_concrete_slab.json | 1 - .../models/item/gas_concrete_stairs.json | 1 - .../models/item/gas_concrete_tile.json | 1 - .../models/item/gas_concrete_tile_slab.json | 1 - .../models/item/gas_concrete_tile_stairs.json | 1 - .../models/item/gas_concrete_wall.json | 1 - .../models/item/halfslab_gas_concrete.json | 1 - .../models/item/treated_wood_side_table.json | 1 - .../clinker_brick/clinker_brick_pole_side.png | Bin 443 -> 568 bytes ...inker_brick_sastor_corner_down_texture.png | Bin 748 -> 569 bytes ...inker_brick_sastor_corner_side_texture.png | Bin 726 -> 635 bytes ...clinker_brick_sastor_corner_up_texture.png | Bin 746 -> 621 bytes ...er_brick_sastor_downplate_side_texture.png | Bin 734 -> 576 bytes ...nker_brick_sastor_upplate_side_texture.png | Bin 699 -> 566 bytes ...inker_brick_sastor_upplate_top_texture.png | Bin 515 -> 515 bytes .../clinker_brick_stained_texture0.png | Bin 757 -> 785 bytes .../clinker_brick_stained_texture1.png | Bin 731 -> 771 bytes .../clinker_brick_stained_texture2.png | Bin 750 -> 782 bytes .../clinker_brick_stained_texture3.png | Bin 738 -> 790 bytes .../clinker_brick_stained_texture4.png | Bin 751 -> 802 bytes .../clinker_brick_stained_texture5.png | Bin 739 -> 796 bytes .../clinker_brick_stained_texture6.png | Bin 750 -> 787 bytes .../clinker_brick_stained_texture7.png | Bin 753 -> 793 bytes .../clinker_brick/clinker_brick_texture0.png | Bin 748 -> 641 bytes .../clinker_brick/clinker_brick_texture1.png | Bin 736 -> 652 bytes .../clinker_brick/clinker_brick_texture2.png | Bin 731 -> 666 bytes .../clinker_brick/clinker_brick_texture3.png | Bin 728 -> 602 bytes .../clinker_brick/clinker_brick_texture4.png | Bin 746 -> 624 bytes .../clinker_brick/clinker_brick_texture5.png | Bin 724 -> 592 bytes .../clinker_brick/clinker_brick_texture6.png | Bin 740 -> 633 bytes .../clinker_brick/clinker_brick_texture7.png | Bin 739 -> 619 bytes .../block/clinker_brick/clinker_brick_top.png | Bin 521 -> 570 bytes .../clinker_brick/clinker_brick_wall0.png | Bin 530 -> 625 bytes .../clinker_brick/clinker_brick_wall1.png | Bin 660 -> 564 bytes .../clinker_brick/clinker_brick_wall2.png | Bin 672 -> 653 bytes .../clinker_brick/clinker_brick_wall3.png | Bin 609 -> 659 bytes .../clinker_brick/clinker_brick_wall4.png | Bin 636 -> 623 bytes .../clinker_brick/clinker_brick_wall5.png | Bin 603 -> 611 bytes .../clinker_brick/clinker_brick_wall6.png | Bin 648 -> 645 bytes .../clinker_brick/clinker_brick_wall7.png | Bin 630 -> 636 bytes .../block/concrete/gas_concrete_texture0.png | Bin 601 -> 0 bytes .../block/concrete/gas_concrete_texture1.png | Bin 608 -> 0 bytes .../block/concrete/gas_concrete_texture2.png | Bin 609 -> 0 bytes .../block/concrete/gas_concrete_texture3.png | Bin 627 -> 0 bytes .../block/concrete/gas_concrete_texture4.png | Bin 609 -> 0 bytes .../block/concrete/gas_concrete_texture5.png | Bin 621 -> 0 bytes .../block/concrete/gas_concrete_texture6.png | Bin 630 -> 0 bytes .../block/concrete/gas_concrete_texture7.png | Bin 601 -> 0 bytes .../loot_tables/blocks/gas_concrete.json | 21 - .../blocks/gas_concrete_stairs.json | 21 - .../loot_tables/blocks/gas_concrete_wall.json | 21 - .../blocks/treated_wood_side_table.json | 21 - .../entries/buildingblocks/concrete.json | 6 - .../entries/buildingblocks/concrete.json | 6 - ....json => rebar_concrete_block_recipe.json} | 28 +- .../treated_wood_side_table_recipe.json | 55 - .../dependent/treated_wood_window_recipe.json | 2 +- .../independent/clinker_brick_recipe2.json | 30 - .../clinker_brick_stained_block_recipe.json | 2 +- .../gas_concrete_halfslab_recipe.json | 30 - ...as_concrete_halfslab_recipe_decompose.json | 30 - .../independent/gas_concrete_slab_recipe.json | 29 - .../gas_concrete_slab_recipe_decompose.json | 28 - .../gas_concrete_stairs_recipe.json | 29 - .../gas_concrete_stairs_recipe_decompose.json | 30 - .../independent/gas_concrete_wall_recipe.json | 31 - .../gas_concrete_wall_recipe_decompose.json | 30 - .../independent/iron_inset_light_recipe.json | 6 +- .../independent/panzerglass_block_recipe.json | 4 +- .../rebar_concrete_block_recipe.json | 30 - .../steel_framed_window_recipe.json | 4 +- .../tags/blocks/brick_blocks.json | 7 - .../engineersdecor/tags/blocks/dirts.json | 7 - .../tags/blocks/luminescent_blocks.json | 7 - .../tags/blocks/plain_glass_blocks.json | 22 - .../tags/blocks/plain_glass_panes.json | 22 - .../data/engineersdecor/tags/items/dirts.json | 7 - .../tags/items/luminescent_blocks.json | 7 - .../tags/items/plain_glass_blocks.json | 22 - .../tags/items/plain_glass_panes.json | 22 - .../forge/{tags => tags_}/blocks/dirt.json | 0 .../forge/{tags => tags_}/items/dirt.json | 0 .../{tags => tags_}/blocks/climbable.json | 0 .../{tags => tags_}/blocks/doors.json | 0 .../{tags => tags_}/blocks/planks.json | 0 .../{tags => tags_}/blocks/slabs.json | 1 - .../{tags => tags_}/blocks/stairs.json | 1 - .../{tags => tags_}/blocks/walls.json | 3 +- .../{tags => tags_}/blocks/wither_immune.json | 0 .../{tags => tags_}/blocks/wooden_doors.json | 0 .../{tags => tags_}/items/doors.json | 0 .../{tags => tags_}/items/slabs.json | 1 - .../{tags => tags_}/items/stairs.json | 3 +- .../{tags => tags_}/items/walls.json | 3 +- .../{tags => tags_}/items/wooden_doors.json | 0 242 files changed, 21371 insertions(+), 22684 deletions(-) delete mode 100644 src/main/java/wile/engineersdecor/blocks/EdDoorBlock.java delete mode 100644 src/main/java/wile/engineersdecor/blocks/EdGroundBlock.java delete mode 100644 src/main/java/wile/engineersdecor/blocks/EdSlabBlock.java delete mode 100644 src/main/java/wile/engineersdecor/blocks/EdSlabSliceBlock.java delete mode 100644 src/main/java/wile/engineersdecor/blocks/EdStairsBlock.java delete mode 100644 src/main/java/wile/engineersdecor/blocks/IDecorBlock.java delete mode 100644 src/main/java/wile/engineersdecor/detail/ExternalObjects.java create mode 100644 src/main/java/wile/engineersdecor/libmc/blocks/StandardEntityBlocks.java delete mode 100644 src/main/java/wile/engineersdecor/libmc/client/ContainerGui.java delete mode 100644 src/main/java/wile/engineersdecor/libmc/datagen/AssetsDataGen.java delete mode 100644 src/main/java/wile/engineersdecor/libmc/datagen/LootTableGen.java create mode 100644 src/main/java/wile/engineersdecor/libmc/detail/Crafting.java delete mode 100644 src/main/java/wile/engineersdecor/libmc/detail/DataFixing.java create mode 100644 src/main/java/wile/engineersdecor/libmc/detail/RsSignals.java create mode 100644 src/main/java/wile/engineersdecor/libmc/ui/Containers.java create mode 100644 src/main/java/wile/engineersdecor/libmc/ui/Guis.java delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/gas_concrete.json delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/gas_concrete_slab.json delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/gas_concrete_stairs.json delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/gas_concrete_wall.json delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/halfslab_gas_concrete.json delete mode 100644 src/main/resources/assets/engineersdecor/blockstates/treated_wood_side_table.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model0.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model1.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model2.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model3.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model4.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model5.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model6.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_model7.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_stairs.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_stairs_inner.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_stairs_outer.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_tile_model0.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_wall_default.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_wall_inventory.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_wall_post.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/concrete/gas_concrete_wall_side.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/furniture/treated_wood_side_table_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s0v0_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s0v1_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s0v2_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s0v3_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s1v0_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s1v1_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s1v2_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s1v3_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s2v0_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s2v1_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s2v2_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/gas_concrete_slab_s2v3_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s0_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s1_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s2_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s3_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s4_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s5_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s6_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s7_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s8_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_s9_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_sa_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_sb_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_sc_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_sd_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/block/slab/specific/halfslab_gas_concrete_se_model.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_slab.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_stairs.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_tile.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_tile_slab.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_tile_stairs.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/gas_concrete_wall.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/halfslab_gas_concrete.json delete mode 100644 src/main/resources/assets/engineersdecor/models/item/treated_wood_side_table.json delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture0.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture1.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture2.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture3.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture4.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture5.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture6.png delete mode 100644 src/main/resources/assets/engineersdecor/textures/block/concrete/gas_concrete_texture7.png delete mode 100644 src/main/resources/data/engineersdecor/loot_tables/blocks/gas_concrete.json delete mode 100644 src/main/resources/data/engineersdecor/loot_tables/blocks/gas_concrete_stairs.json delete mode 100644 src/main/resources/data/engineersdecor/loot_tables/blocks/gas_concrete_wall.json delete mode 100644 src/main/resources/data/engineersdecor/loot_tables/blocks/treated_wood_side_table.json rename src/main/resources/data/engineersdecor/recipes/dependent/{gas_concrete_block_recipe.json => rebar_concrete_block_recipe.json} (55%) delete mode 100644 src/main/resources/data/engineersdecor/recipes/dependent/treated_wood_side_table_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/clinker_brick_recipe2.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_halfslab_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_halfslab_recipe_decompose.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_slab_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_slab_recipe_decompose.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_stairs_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_stairs_recipe_decompose.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_wall_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/gas_concrete_wall_recipe_decompose.json delete mode 100644 src/main/resources/data/engineersdecor/recipes/independent/rebar_concrete_block_recipe.json delete mode 100644 src/main/resources/data/engineersdecor/tags/blocks/brick_blocks.json delete mode 100644 src/main/resources/data/engineersdecor/tags/blocks/dirts.json delete mode 100644 src/main/resources/data/engineersdecor/tags/blocks/luminescent_blocks.json delete mode 100644 src/main/resources/data/engineersdecor/tags/blocks/plain_glass_blocks.json delete mode 100644 src/main/resources/data/engineersdecor/tags/blocks/plain_glass_panes.json delete mode 100644 src/main/resources/data/engineersdecor/tags/items/dirts.json delete mode 100644 src/main/resources/data/engineersdecor/tags/items/luminescent_blocks.json delete mode 100644 src/main/resources/data/engineersdecor/tags/items/plain_glass_blocks.json delete mode 100644 src/main/resources/data/engineersdecor/tags/items/plain_glass_panes.json rename src/main/resources/data/forge/{tags => tags_}/blocks/dirt.json (100%) rename src/main/resources/data/forge/{tags => tags_}/items/dirt.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/climbable.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/doors.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/planks.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/slabs.json (89%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/stairs.json (88%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/walls.json (59%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/wither_immune.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/blocks/wooden_doors.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/items/doors.json (100%) rename src/main/resources/data/minecraft/{tags => tags_}/items/slabs.json (88%) rename src/main/resources/data/minecraft/{tags => tags_}/items/stairs.json (70%) rename src/main/resources/data/minecraft/{tags => tags_}/items/walls.json (59%) rename src/main/resources/data/minecraft/{tags => tags_}/items/wooden_doors.json (100%) diff --git a/build.gradle b/build.gradle index 26fa61c..da6dec1 100644 --- a/build.gradle +++ b/build.gradle @@ -1,20 +1,18 @@ // @file build.gradle // Engineer's decor mod gradle build. -import net.minecraftforge.gradle.common.task.SignJar buildscript { repositories { - maven { url = 'https://files.minecraftforge.net/maven' } - jcenter() - mavenCentral() + maven { url = 'https://maven.minecraftforge.net' } + mavenCentral() } dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true + classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true } } apply plugin: 'net.minecraftforge.gradle' apply plugin: 'eclipse' apply plugin: 'maven-publish' -sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' +java.toolchain.languageVersion = JavaLanguageVersion.of(16) //---------------------------------------------------------------------------------------------------------------------- version = "${version_engineersdecor}" group = "wile.engineersdecor" @@ -23,51 +21,40 @@ archivesBaseName = "engineersdecor-${version_minecraft}" repositories { maven { name = "Progwml6 maven"; url = "https://dvs1.progwml6.com/files/maven/" } // JEI files maven { name = "ModMaven"; url = "https://modmaven.k-4u.nl" } // JEI files, fallback + flatDir { dir 'libs' } // Mod jar dependencies in ./libs } minecraft { // mappings channel: 'snapshot', version: "${version_fml_mappings}" - mappings channel: "official", version: "1.16.5" + mappings channel: "official", version: "1.17.1" // accessTransformer = file('build/resources/main/META-INF/accesstransformer.cfg') runs { client { workingDirectory project.file('run') property 'forge.logging.markers', '' // SCAN,REGISTRIES,REGISTRYDUMP - property 'forge.logging.console.level', 'debug' - mods { - engineersdecor { - source sourceSets.main - } - } + property 'forge.logging.console.level', 'info' + mods { engineersdecor { source sourceSets.main } } } server { workingDirectory project.file('run') property 'forge.logging.markers', '' // SCAN,REGISTRIES,REGISTRYDUMP - property 'forge.logging.console.level', 'debug' - mods { - engineersdecor { - source sourceSets.main - } - } - } - data { - workingDirectory project.file('run') - property 'forge.logging.markers', '' // SCAN,REGISTRIES,REGISTRYDUMP - property 'forge.logging.console.level', 'debug' - args '--mod', 'engineersdecor', '--all', '--output', file('src/generated/resources/') - mods { - engineersdecor { - source sourceSets.main - } - } + property 'forge.logging.console.level', 'info' + mods { engineersdecor { source sourceSets.main } } } + // data { + // workingDirectory project.file('run') + // property 'forge.logging.markers', '' // SCAN,REGISTRIES,REGISTRYDUMP + // property 'forge.logging.console.level', 'info' + // args '--mod', 'engineersdecor', '--all', '--output', file('src/generated/resources/') + // mods { engineersdecor { source sourceSets.main } } + // } } } dependencies { minecraft "net.minecraftforge:forge:${version_forge_minecraft}" - compileOnly fg.deobf("mezz.jei:jei-${version_jei}:api") - runtimeOnly fg.deobf("mezz.jei:jei-${version_jei}") + //compileOnly fg.deobf("mezz.jei:jei-${version_jei}:api") + //runtimeOnly fg.deobf("mezz.jei:jei-${version_jei}") } processResources { @@ -89,25 +76,29 @@ jar { } } -def reobfFile = file("$buildDir/reobfJar/output.jar") -def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar' } +sourceSets.main.resources { srcDir 'src/generated/resources' } // Include datagen resources +jar.finalizedBy('reobfJar') -task signJar(type: SignJar, dependsOn: jar) { - onlyIf { project.hasProperty("keystore_file") } - if(project.hasProperty("keystore_file")) { - keyStore = project.getProperty("keystore_file") - alias = project.getProperty("keystore_alias") - storePass = project.getProperty("keystore_pass") - keyPass = project.getProperty("keystore_keypass") - inputFile = jar.archivePath - outputFile = jar.archivePath - } else { - logger.warn("[WARNING] Signing skipped.") - } -} -build.dependsOn signJar +// import net.minecraftforge.gradle.common.task.SignJar +// def reobfFile = file("$buildDir/reobfJar/output.jar") +// def reobfArtifact = artifacts.add('default', reobfFile) { type 'jar'; builtBy 'reobfJar' } + +// task signJar(type: SignJar, dependsOn: jar) { +// onlyIf { project.hasProperty("keystore_file") } +// if(project.hasProperty("keystore_file")) { +// keyStore = project.getProperty("keystore_file") +// alias = project.getProperty("keystore_alias") +// storePass = project.getProperty("keystore_pass") +// keyPass = project.getProperty("keystore_keypass") +// inputFile = jar.archivePath +// outputFile = jar.archivePath +// } else { +// logger.warn("[WARNING] Signing skipped.") +// } +// } +// build.dependsOn signJar publishing { - publications { mavenJava(MavenPublication) { artifact reobfArtifact } } + publications { mavenJava(MavenPublication) { artifact jar } } repositories { maven { url "file:///${project.projectDir}/mcmodsrepo" } } } diff --git a/gradle.properties b/gradle.properties index 84161e9..ca1f441 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,8 +1,7 @@ # @file gradle.properties org.gradle.daemon=false org.gradle.jvmargs=-Xmx8G -version_minecraft=1.16.4 -version_forge_minecraft=1.16.4-35.1.10 -version_fml_mappings=20201028-1.16.3 +version_minecraft=1.17.1 +version_forge_minecraft=1.17.1-37.0.17 version_jei=1.16.4:7.6.1.63 -version_engineersdecor=1.1.15-b1 +version_engineersdecor=1.1.17-b1 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7a3265ee94c0ab25cf079ac8ccdf87f41d455d42..7454180f2ae8848c63b8b4dea2cb829da983f2fa 100644 GIT binary patch literal 59536 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 QuEJmfE|#`Dqx|px0L@K;Y5)KL literal 54708 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

_x$+l{{cH8$W#CT diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 1d5b29f..0595cf7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions-snapshots/gradle-7.2-20210702220150+0000-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip diff --git a/gradlew b/gradlew index cccdd3d..744e882 100644 --- a/gradlew +++ b/gradlew @@ -1,5 +1,21 @@ #!/usr/bin/env sh +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + ############################################################################## ## ## Gradle start up script for UN*X @@ -28,7 +44,7 @@ APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" @@ -56,7 +72,7 @@ case "`uname`" in Darwin* ) darwin=true ;; - MINGW* ) + MSYS* | MINGW* ) msys=true ;; NONSTOP* ) @@ -66,6 +82,7 @@ esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then @@ -109,10 +126,11 @@ if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath @@ -138,19 +156,19 @@ if $cygwin ; then else eval `echo args$i`="\"$arg\"" fi - i=$((i+1)) + i=`expr $i + 1` done case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi @@ -159,14 +177,9 @@ save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } -APP_ARGS=$(save "$@") +APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" -fi - exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d..ac1b06f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/meta/update.json b/meta/update.json index 4eb0c35..f770ec3 100644 --- a/meta/update.json +++ b/meta/update.json @@ -1,6 +1,6 @@ { "homepage": "https://www.curseforge.com/minecraft/mc-mods/engineers-decor/", - "1.16.4": { + "1.17.1": { "1.1.14": "[R] Release build v1.1.14.", "1.1.14-b3": "[A] Spanish language support added (PR#180, thx FrannDzs).", "1.1.14-b2": "[F] Block Placer: Attempt circumventing external placement prevention.", @@ -39,7 +39,7 @@ "1.1.2-b1": "[U] Ported to MC1.16.2." }, "promos": { - "1.16.4-recommended": "1.1.14", - "1.16.4-latest": "1.1.14" + "1.17.1-recommended": "1.1.14", + "1.17.1-latest": "1.1.14" } } \ No newline at end of file diff --git a/readme.md b/readme.md index 253aac8..683817d 100644 --- a/readme.md +++ b/readme.md @@ -11,7 +11,11 @@ Mod sources for Minecraft version 1.16.x. ## Version history - ~ v1.1.15-b1 [F] + ~ v1.1.17-b1 [U] Initial MC 1.17.1 port. + [M] Clinker Brick textures adapted to contemporary MC textures. + [D] Gas Concrete dropped (Rebar Concrete suffices for texture variation). + [D] Treated Wood Side Table dropped. + [M] Updated zh_cn (PR#183, Lyaiya). - v1.1.14 [R] Release build v1.1.14. diff --git a/src/main/java/wile/engineersdecor/ModConfig.java b/src/main/java/wile/engineersdecor/ModConfig.java index 4aad364..2827384 100644 --- a/src/main/java/wile/engineersdecor/ModConfig.java +++ b/src/main/java/wile/engineersdecor/ModConfig.java @@ -1,773 +1,481 @@ -/* - * @file ModConfig.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Main class for module settings. Handles reading and - * saving the config file. - */ -package wile.engineersdecor; - -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.block.Block; -import net.minecraft.item.Item; -import net.minecraftforge.common.ForgeConfigSpec; -import org.apache.commons.lang3.tuple.Pair; -import org.apache.logging.log4j.Logger; -import wile.engineersdecor.blocks.*; -import wile.engineersdecor.libmc.blocks.StandardBlocks; -import wile.engineersdecor.libmc.detail.Auxiliaries; -import wile.engineersdecor.libmc.detail.OptionalRecipeCondition; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.HashSet; - -public class ModConfig -{ - //-------------------------------------------------------------------------------------------------------------------- - private static final Logger LOGGER = ModEngineersDecor.logger(); - private static final String MODID = ModEngineersDecor.MODID; - public static final CommonConfig COMMON; - public static final ServerConfig SERVER; - public static final ClientConfig CLIENT; - public static final ForgeConfigSpec COMMON_CONFIG_SPEC; - public static final ForgeConfigSpec SERVER_CONFIG_SPEC; - public static final ForgeConfigSpec CLIENT_CONFIG_SPEC; - - static { - final Pair common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new); - COMMON_CONFIG_SPEC = common_.getRight(); - COMMON = common_.getLeft(); - final Pair server_ = (new ForgeConfigSpec.Builder()).configure(ServerConfig::new); - SERVER_CONFIG_SPEC = server_.getRight(); - SERVER = server_.getLeft(); - final Pair client_ = (new ForgeConfigSpec.Builder()).configure(ClientConfig::new); - CLIENT_CONFIG_SPEC = client_.getRight(); - CLIENT = client_.getLeft(); - } - - //-------------------------------------------------------------------------------------------------------------------- - - public static class ClientConfig - { - public final ForgeConfigSpec.BooleanValue without_tooltips; - public final ForgeConfigSpec.BooleanValue without_ters; - - ClientConfig(ForgeConfigSpec.Builder builder) - { - builder.comment("Settings not loaded on servers.") - .push("client"); - // --- OPTOUTS ------------------------------------------------------------ - { - builder.comment("Opt-out settings") - .push("optout"); - without_tooltips = builder - .translation(MODID + ".config.without_tooltips") - .comment("Disable CTRL-SHIFT item tooltip display.") - .define("without_tooltips", false); - without_ters = builder - .translation(MODID + ".config.without_ters") - .comment("Disable all TERs (tile entity renderers).") - .define("without_ters", false); - } - builder.pop(); - } - } - - //-------------------------------------------------------------------------------------------------------------------- - - public static class CommonConfig - { - // Optout - public final ForgeConfigSpec.ConfigValue pattern_excludes; - public final ForgeConfigSpec.ConfigValue pattern_includes; - // MISC - public final ForgeConfigSpec.BooleanValue with_creative_mode_device_drops; - public final ForgeConfigSpec.BooleanValue with_experimental; - public final ForgeConfigSpec.BooleanValue with_config_logging; - public final ForgeConfigSpec.BooleanValue with_debug_logging; - - CommonConfig(ForgeConfigSpec.Builder builder) - { - builder.comment("Settings affecting the logical server side.") - .push("server"); - // --- OPTOUTS ------------------------------------------------------------ - { - builder.comment("Opt-out settings") - .push("optout"); - pattern_excludes = builder - .translation(MODID + ".config.pattern_excludes") - .comment("Opt-out any block by its registry name ('*' wildcard matching, " - + "comma separated list, whitespaces ignored. You must match the whole name, " - + "means maybe add '*' also at the begin and end. Example: '*wood*,*steel*' " - + "excludes everything that has 'wood' or 'steel' in the registry name. " - + "The matching result is also traced in the log file. ") - .define("pattern_excludes", ""); - pattern_includes = builder - .translation(MODID + ".config.pattern_includes") - .comment("Prevent blocks from being opt'ed by registry name ('*' wildcard matching, " - + "comma separated list, whitespaces ignored. Evaluated before all other opt-out checks. " - + "You must match the whole name, means maybe add '*' also at the begin and end. Example: " - + "'*wood*,*steel*' includes everything that has 'wood' or 'steel' in the registry name." - + "The matching result is also traced in the log file.") - .define("pattern_includes", ""); - builder.pop(); - } - // --- MISC --------------------------------------------------------------- - { - builder.comment("Miscellaneous settings") - .push("miscellaneous"); - with_experimental = builder - .translation(MODID + ".config.with_experimental") - .comment("Enables experimental features. Use at own risk.") - .define("with_experimental", false); - with_creative_mode_device_drops = builder - .translation(MODID + ".config.with_creative_mode_device_drops") - .comment("Enable that devices are dropped as item also in creative mode, allowing " + - " to relocate them with contents and settings.") - .define("with_creative_mode_device_drops", false); - with_config_logging = builder - .translation(MODID + ".config.with_debug_logging") - .comment("Enable detailed logging of the config values and resulting calculations in each mod feature config.") - .define("with_debug_logging", false); - with_debug_logging = builder - .translation(MODID + ".config.with_debug_logging") - .comment("Enable debug log messages for trouble shooting. Don't activate if not really needed, this can spam the log file.") - .define("with_debug_logging", false); - builder.pop(); - } - } - } - - //-------------------------------------------------------------------------------------------------------------------- - - public static class ServerConfig - { - // Optout - public final ForgeConfigSpec.BooleanValue without_chair_sitting; - public final ForgeConfigSpec.BooleanValue without_mob_chair_sitting; - public final ForgeConfigSpec.BooleanValue without_ladder_speed_boost; - public final ForgeConfigSpec.BooleanValue without_crafting_table_history; - - /// ---------- @todo: remove these settings for MC1.17 / 1.16.5 - public final ForgeConfigSpec.ConfigValue pattern_excludes; - public final ForgeConfigSpec.ConfigValue pattern_includes; - public final ForgeConfigSpec.BooleanValue without_clinker_bricks; - public final ForgeConfigSpec.BooleanValue without_slag_bricks; - public final ForgeConfigSpec.BooleanValue without_rebar_concrete; - public final ForgeConfigSpec.BooleanValue without_gas_concrete; - public final ForgeConfigSpec.BooleanValue without_walls; - public final ForgeConfigSpec.BooleanValue without_stairs; - public final ForgeConfigSpec.BooleanValue without_panzer_glass; - public final ForgeConfigSpec.BooleanValue without_ladders; - public final ForgeConfigSpec.BooleanValue without_treated_wood_furniture; - public final ForgeConfigSpec.BooleanValue without_metal_furniture; - public final ForgeConfigSpec.BooleanValue without_windows; - public final ForgeConfigSpec.BooleanValue without_light_sources; - public final ForgeConfigSpec.BooleanValue without_slabs; - public final ForgeConfigSpec.BooleanValue without_halfslabs; - public final ForgeConfigSpec.BooleanValue without_poles; - public final ForgeConfigSpec.BooleanValue without_hsupports; - public final ForgeConfigSpec.BooleanValue without_sign_plates; - public final ForgeConfigSpec.BooleanValue without_floor_grating; - public final ForgeConfigSpec.BooleanValue without_crafting_table; - public final ForgeConfigSpec.BooleanValue without_lab_furnace; - public final ForgeConfigSpec.BooleanValue without_electrical_furnace; - public final ForgeConfigSpec.BooleanValue without_valves; - public final ForgeConfigSpec.BooleanValue without_waste_incinerator; - public final ForgeConfigSpec.BooleanValue without_factory_dropper; - public final ForgeConfigSpec.BooleanValue without_factory_hopper; - public final ForgeConfigSpec.BooleanValue without_factory_placer; - public final ForgeConfigSpec.BooleanValue without_block_breaker; - public final ForgeConfigSpec.BooleanValue without_solar_panel; - public final ForgeConfigSpec.BooleanValue without_fluid_funnel; - public final ForgeConfigSpec.BooleanValue without_mineral_smelter; - public final ForgeConfigSpec.BooleanValue without_milking_machine; - public final ForgeConfigSpec.BooleanValue without_tree_cutter; - public final ForgeConfigSpec.BooleanValue without_labeled_crate; - public final ForgeConfigSpec.BooleanValue without_fences; - /// ----------------------- - - // Misc - public final ForgeConfigSpec.BooleanValue without_direct_slab_pickup; - // Tweaks - public final ForgeConfigSpec.IntValue furnace_smelting_speed_percent; - public final ForgeConfigSpec.IntValue furnace_fuel_efficiency_percent; - public final ForgeConfigSpec.IntValue furnace_boost_energy_consumption; - public final ForgeConfigSpec.ConfigValue furnace_accepted_heaters; - public final ForgeConfigSpec.IntValue e_furnace_speed_percent; - public final ForgeConfigSpec.IntValue e_furnace_power_consumption; - public final ForgeConfigSpec.IntValue small_solar_panel_peak_production; - public final ForgeConfigSpec.BooleanValue e_furnace_automatic_pulling; - public final ForgeConfigSpec.DoubleValue chair_mob_sitting_probability_percent; - public final ForgeConfigSpec.DoubleValue chair_mob_standup_probability_percent; - public final ForgeConfigSpec.BooleanValue without_crafting_mouse_scrolling; - public final ForgeConfigSpec.IntValue pipevalve_max_flowrate; - public final ForgeConfigSpec.IntValue pipevalve_redstone_gain; - public final ForgeConfigSpec.IntValue block_breaker_power_consumption; - public final ForgeConfigSpec.IntValue block_breaker_reluctance; - public final ForgeConfigSpec.IntValue block_breaker_min_breaking_time; - public final ForgeConfigSpec.BooleanValue block_breaker_requires_power; - public final ForgeConfigSpec.IntValue tree_cutter_energy_consumption; - public final ForgeConfigSpec.IntValue tree_cutter_cutting_time_needed; - public final ForgeConfigSpec.BooleanValue tree_cutter_requires_power; - public final ForgeConfigSpec.IntValue milking_machine_energy_consumption; - public final ForgeConfigSpec.IntValue milking_machine_milking_delay; - - ServerConfig(ForgeConfigSpec.Builder builder) - { - builder.comment("Settings affecting the logical server side.") - .push("server"); - // --- OPTOUTS ------------------------------------------------------------ - { - builder.comment("Server dev opt-out settings !WARNING THE OPT-OUTs will be moved to common-config.toml in the next MC version!") - .push("optout"); - pattern_excludes = builder - .translation(MODID + ".config.pattern_excludes") - .comment("Opt-out any block by its registry name ('*' wildcard matching, " - + "comma separated list, whitespaces ignored. You must match the whole name, " - + "means maybe add '*' also at the begin and end. Example: '*wood*,*steel*' " - + "excludes everything that has 'wood' or 'steel' in the registry name. " - + "The matching result is also traced in the log file. ") - .define("pattern_excludes", ""); - pattern_includes = builder - .translation(MODID + ".config.pattern_includes") - .comment("Prevent blocks from being opt'ed by registry name ('*' wildcard matching, " - + "comma separated list, whitespaces ignored. Evaluated before all other opt-out checks. " - + "You must match the whole name, means maybe add '*' also at the begin and end. Example: " - + "'*wood*,*steel*' includes everything that has 'wood' or 'steel' in the registry name." - + "The matching result is also traced in the log file.") - .define("pattern_includes", ""); - without_clinker_bricks = builder - .translation(MODID + ".config.without_clinker_bricks") - .comment("Disable clinker bricks and derived blocks.") - .define("without_clinker_bricks", false); - without_slag_bricks = builder - .translation(MODID + ".config.without_slag_bricks") - .comment("Disable slag bricks and derived blocks.") - .define("without_slag_bricks", false); - without_rebar_concrete = builder - .translation(MODID + ".config.without_rebar_concrete") - .comment("Disable rebar concrete and derived blocks.") - .define("without_rebar_concrete", false); - without_gas_concrete = builder - .translation(MODID + ".config.without_gas_concrete") - .comment("Disable gas concrete and derived blocks.") - .define("without_gas_concrete", false); - without_walls = builder - .translation(MODID + ".config.without_walls") - .comment("Disable all mod wall blocks.") - .define("without_walls", false); - without_stairs = builder - .translation(MODID + ".config.without_stairs") - .comment("Disable all mod stairs blocks.") - .define("without_stairs", false); - without_panzer_glass = builder - .translation(MODID + ".config.without_panzer_glass") - .comment("Disable panzer glass and derived blocks.") - .define("without_panzer_glass", false); - without_crafting_table = builder - .translation(MODID + ".config.without_crafting_table") - .comment("Disable crafting table.") - .define("without_crafting_table", false); - without_lab_furnace = builder - .translation(MODID + ".config.without_lab_furnace") - .comment("Disable small lab furnace.") - .define("without_lab_furnace", false); - without_electrical_furnace = builder - .translation(MODID + ".config.without_electrical_furnace") - .comment("Disable small electrical pass-through furnace.") - .define("without_electrical_furnace", false); - without_treated_wood_furniture = builder - .translation(MODID + ".config.without_treated_wood_furniture") - .comment("Disable treated wood table, stool, windowsill, etc.") - .define("without_treated_wood_furniture", false); - without_metal_furniture = builder - .translation(MODID + ".config.without_metal_furniture") - .comment("Disable metal tables, etc.") - .define("without_metal_furniture", false); - without_windows = builder - .translation(MODID + ".config.without_windows") - .comment("Disable treated wood window, etc.") - .define("without_windows", false); - without_light_sources = builder - .translation(MODID + ".config.without_light_sources") - .comment("Disable light sources") - .define("without_light_sources", false); - without_ladders = builder - .translation(MODID + ".config.without_ladders") - .comment("Disable ladders") - .define("without_ladders", false); - without_chair_sitting = builder - .translation(MODID + ".config.without_chair_sitting") - .comment("Disable possibility to sit on stools and chairs.") - .define("without_chair_sitting", false); - without_mob_chair_sitting = builder - .translation(MODID + ".config.without_mob_chair_sitting") - .comment("Disable that mobs will sit on chairs and stools.") - .define("without_mob_chair_sitting", false); - without_ladder_speed_boost = builder - .translation(MODID + ".config.without_ladder_speed_boost") - .comment("Disable the speed boost of ladders in this mod.") - .define("without_ladder_speed_boost", false); - without_crafting_table_history = builder - .translation(MODID + ".config.without_crafting_table_history") - .comment("Disable history refabrication feature of the crafting table.") - .define("without_crafting_table_history", false); - without_valves = builder - .translation(MODID + ".config.without_valves") - .comment("Disable check valve, and redstone controlled valves.") - .define("without_valves", false); - without_waste_incinerator = builder - .translation(MODID + ".config.without_waste_incinerator") - .comment("Disable item disposal/trash/void incinerator device.") - .define("without_waste_incinerator", false); - without_sign_plates = builder - .translation(MODID + ".config.without_sign_plates") - .comment("Disable decorative sign plates (caution, hazards, etc).") - .define("without_sign_plates", false); - without_floor_grating = builder - .translation(MODID + ".config.without_floor_grating") - .comment("Disable floor gratings.") - .define("without_floor_grating", false); - without_factory_dropper = builder - .translation(MODID + ".config.without_factory_dropper") - .comment("Disable the factory dropper.") - .define("without_factory_dropper", false); - without_factory_hopper = builder - .translation(MODID + ".config.without_factory_hopper") - .comment("Disable the factory hopper.") - .define("without_factory_hopper", false); - without_factory_placer = builder - .translation(MODID + ".config.without_factory_placer") - .comment("Disable the factory placer.") - .define("without_factory_placer", false); - without_block_breaker = builder - .translation(MODID + ".config.without_block_breaker") - .comment("Disable the small block breaker.") - .define("without_block_breaker", false); - without_solar_panel = builder - .translation(MODID + ".config.without_solar_panel") - .comment("Disable the small solar panel.") - .define("without_solar_panel", false); - without_fluid_funnel = builder - .translation(MODID + ".config.without_fluid_funnel") - .comment("Disable the small fluid collection funnel.") - .define("without_fluid_funnel", false); - without_mineral_smelter = builder - .translation(MODID + ".config.without_mineral_smelter") - .comment("Disable the small mineral smelter.") - .define("without_mineral_smelter", false); - without_milking_machine = builder - .translation(MODID + ".config.without_milking_machine") - .comment("Disable the small milking machine.") - .define("without_milking_machine", false); - without_tree_cutter = builder - .translation(MODID + ".config.without_tree_cutter") - .comment("Disable the small tree cutter.") - .define("without_tree_cutter", false); - without_labeled_crate = builder - .translation(MODID + ".config.without_labeled_crate") - .comment("Disable labeled crate.") - .define("without_labeled_crate", false); - without_slabs = builder - .translation(MODID + ".config.without_slabs") - .comment("Disable horizontal half-block slab.") - .define("without_slabs", false); - without_halfslabs = builder - .translation(MODID + ".config.without_halfslabs") - .comment("Disable stackable 1/8 block slices.") - .define("without_halfslabs", false); - without_poles = builder - .translation(MODID + ".config.without_poles") - .comment("Disable poles of any material.") - .define("without_poles", false); - without_hsupports = builder - .translation(MODID + ".config.without_hsupports") - .comment("Disable horizontal supports like the double-T support.") - .define("without_hsupports", false); - without_fences = builder - .translation(MODID + ".config.without_fences") - .comment("Disable all fences and fence gates.") - .define("without_fences", false); - builder.pop(); - } - // --- MISC --------------------------------------------------------------- - { - builder.comment("Miscellaneous settings") - .push("miscellaneous"); - without_direct_slab_pickup = builder - .translation(MODID + ".config.without_direct_slab_pickup") - .comment("Disable directly picking up layers from slabs and slab " + - " slices by left clicking while looking up/down.") - .define("without_direct_slab_pickup", false); - builder.pop(); - } - // --- TWEAKS ------------------------------------------------------------- - { - builder.comment("Tweaks") - .push("tweaks"); - furnace_smelting_speed_percent = builder - .translation(MODID + ".config.furnace_smelting_speed_percent") - .comment("Defines, in percent, how fast the lab furnace smelts compared to " + - "a vanilla furnace. 100% means vanilla furnace speed, 150% means the " + - "lab furnace is faster. The value can be changed on-the-fly for tuning.") - .defineInRange("furnace_smelting_speed_percent", 130, 50, 800); - furnace_fuel_efficiency_percent = builder - .translation(MODID + ".config.furnace_fuel_efficiency_percent") - .comment("Defines, in percent, how fuel efficient the lab furnace is, compared " + - "to a vanilla furnace. 100% means vanilla furnace consumiton, 200% means " + - "the lab furnace needs about half the fuel of a vanilla furnace, " + - "The value can be changed on-the-fly for tuning.") - .defineInRange("furnace_fuel_efficiency_percent", 100, 50, 400); - furnace_boost_energy_consumption = builder - .translation(MODID + ".config.furnace_boost_energy_consumption") - .comment("Defines the energy consumption (per tick) for speeding up the smelting process. " + - "If IE is installed, an external heater has to be inserted into an auxiliary slot " + - "of the lab furnace. The power source needs to be able to provide at least 4 times " + - "this consumption (fixed threshold value). The value can be changed on-the-fly for tuning. " + - "The default value corresponds to the IE heater consumption.") - .defineInRange("furnace_boost_energy_consumption", 24, 2, 1024); - furnace_accepted_heaters = builder - .translation(MODID + ".config.furnace_accepted_heaters") - .comment("Defines (as comma separated list of full registry names) which items are allowed as external " + - "heaters in the Aux slot for powered speed boosting.") - .define("furnace_accepted_heaters", "immersiveengineering:furnace_heater"); - chair_mob_sitting_probability_percent = builder - .translation(MODID + ".config.chair_mob_sitting_probability_percent") - .comment("Defines, in percent, how high the probability is that a mob sits on a chair " + - "when colliding with it. Can be changed on-the-fly for tuning.") - .defineInRange("chair_mob_sitting_probability_percent", 10.0, 0.0, 80.0); - chair_mob_standup_probability_percent = builder - .translation(MODID + ".config.chair_mob_standup_probability_percent") - .comment("Defines, in percent, probable it is that a mob leaves a chair when sitting " + - "on it. The 'dice is rolled' about every 20 ticks. There is also a minimum " + - "Sitting time of about 3s. The config value can be changed on-the-fly for tuning.") - .defineInRange("chair_mob_standup_probability_percent", 1.0, 1e-3, 10.0); - without_crafting_mouse_scrolling = builder - .translation(MODID + ".config.without_crafting_mouse_scrolling") - .comment("Disables increasing/decreasing the crafting grid items by scrolling over the crafting result slot.") - .define("without_crafting_mouse_scrolling", false); - pipevalve_max_flowrate = builder - .translation(MODID + ".config.pipevalve_max_flowrate") - .comment("Defines how many millibuckets can be transferred (per tick) through the valves. " + - "That is technically the 'storage size' specified for blocks that want to fill " + - "fluids into the valve (the valve has no container and forward that to the output " + - "block), The value can be changed on-the-fly for tuning. ") - .defineInRange("pipevalve_max_flowrate", 1000, 1, 32000); - pipevalve_redstone_gain = builder - .translation(MODID + ".config.pipevalve_redstone_gain") - .comment("Defines how many millibuckets per redstone signal strength can be transferred per tick " + - "through the analog redstone controlled valves. Note: power 0 is always off, power 15 is always " + - "the max flow rate. Between power 1 and 14 this scaler will result in a flow = 'redstone slope' * 'current redstone power'. " + - "The value can be changed on-the-fly for tuning. ") - .defineInRange("pipevalve_redstone_gain", 20, 1, 32000); - e_furnace_speed_percent = builder - .translation(MODID + ".config.e_furnace_speed_percent") - .comment("Defines, in percent, how fast the electrical furnace smelts compared to " + - "a vanilla furnace. 100% means vanilla furnace speed, 150% means the " + - "electrical furnace is faster. The value can be changed on-the-fly for tuning.") - .defineInRange("e_furnace_speed_percent", EdElectricalFurnace.ElectricalFurnaceTileEntity.DEFAULT_SPEED_PERCENT, 50, 800); - e_furnace_power_consumption = builder - .translation(MODID + ".config.e_furnace_power_consumption") - .comment("Defines how much RF per tick the the electrical furnace consumed (average) for smelting. " + - "The feeders transferring items from/to adjacent have this consumption/8 for each stack transaction. " + - "The default value is only slightly higher than a furnace with an IE external heater (and no burning fuel inside)." + - "The config value can be changed on-the-fly for tuning.") - .defineInRange("e_furnace_power_consumption", EdElectricalFurnace.ElectricalFurnaceTileEntity.DEFAULT_ENERGY_CONSUMPTION, 8, 4096); - e_furnace_automatic_pulling = builder - .translation(MODID + ".config.e_furnace_automatic_pulling") - .comment("Defines if the electrical furnace automatically pulls items from an inventory at the input side." + - "The config value can be changed on-the-fly for tuning.") - .define("e_furnace_automatic_pulling", false); - small_solar_panel_peak_production = builder - .translation(MODID + ".config.small_solar_panel_peak_production") - .comment("Defines the peak power production (at noon) of the Small Solar Panel. " + - "Note that the agerage power is much less, as no power is produced at all during the night, " + - "and the power curve is nonlinear rising/falling during the day. Bad weather conditions also " + - "decrease the production. The config value can be changed on-the-fly for tuning.") - .defineInRange("small_solar_panel_peak_production", EdSolarPanel.SolarPanelTileEntity.DEFAULT_PEAK_POWER, 2, 4096); - block_breaker_power_consumption = builder - .translation(MODID + ".config.block_breaker_power_consumption") - .comment("Defines how much RF power the Small Block Breaker requires to magnificently increase the processing speed. " + - "The config value can be changed on-the-fly for tuning.") - .defineInRange("block_breaker_power_consumption", EdBreaker.BreakerTileEntity.DEFAULT_BOOST_ENERGY, 4, 1024); - block_breaker_reluctance = builder - .translation(MODID + ".config.block_breaker_reluctance") - .comment("Defines how much time the Small Block Breaker needs per block hardness, " + - "means: 'reluctance' * hardness + min_time, you change the 'reluctance' here." + - "The unit is ticks/hardness. " + "The config value can be changed on-the-fly for tuning.") - .defineInRange("block_breaker_reluctance", EdBreaker.BreakerTileEntity.DEFAULT_BREAKING_RELUCTANCE, 5, 50); - block_breaker_min_breaking_time = builder - .translation(MODID + ".config.block_breaker_min_breaking_time") - .comment("Defines how much time the Small Block Breaker needs at least, better said it's an offset: " + - "'reluctance' * hardness + min_time, you change the 'min_time' here, value " + - "in ticks." + "The config value can be changed on-the-fly for tuning.") - .defineInRange("block_breaker_min_breaking_time", EdBreaker.BreakerTileEntity.DEFAULT_MIN_BREAKING_TIME, 10, 100); - block_breaker_requires_power = builder - .translation(MODID + ".config.block_breaker_requires_power") - .comment("Defines if the Small Block Breaker does not work without RF power.") - .define("block_breaker_requires_power", false); - tree_cutter_energy_consumption = builder - .translation(MODID + ".config.tree_cutter_energy_consumption") - .comment("Defines how much RF power the Small Tree Cutter requires to magnificently increase the processing speed. " + - "The config value can be changed on-the-fly for tuning.") - .defineInRange("tree_cutter_energy_consumption", EdTreeCutter.TreeCutterTileEntity.DEFAULT_BOOST_ENERGY, 4, 1024); - tree_cutter_cutting_time_needed = builder - .translation(MODID + ".config.tree_cutter_cutting_time_needed") - .comment("Defines how much time the Small Tree Cutter needs to cut a tree without RF power. " + - "The value is in seconds. With energy it is 6 times faster. " + - "The config value can be changed on-the-fly for tuning.") - .defineInRange("tree_cutter_cutting_time_needed", EdTreeCutter.TreeCutterTileEntity.DEFAULT_CUTTING_TIME_NEEDED, 10, 240); - tree_cutter_requires_power = builder - .translation(MODID + ".config.tree_cutter_requires_power") - .comment("Defines if the Small Tree Cutter does not work without RF power.") - .define("tree_cutter_requires_power", false); - milking_machine_energy_consumption = builder - .translation(MODID + ".config.milking_machine_energy_consumption") - .comment("Defines how much time the Small Milking Machine needs work. " + - "Note this is a permanent standby power, not only when the device does something. " + - "Use zero to disable energy dependency and energy handling of the machine. " + - "The config value can be changed on-the-fly for tuning.") - .defineInRange("milking_machine_energy_consumption", EdMilker.MilkerTileEntity.DEFAULT_ENERGY_CONSUMPTION, 0, 1024); - milking_machine_milking_delay = builder - .translation(MODID + ".config.milking_machine_milking_delay") - .comment("Defines (for each individual cow) the minimum time between milking." ) - .defineInRange("milking_machine_milking_delay", EdMilker.MilkerTileEntity.DEFAULT_MILKING_DELAY_PER_COW, 1000, 24000); - builder.pop(); - } - } - } - - //-------------------------------------------------------------------------------------------------------------------- - // Optout checks - //-------------------------------------------------------------------------------------------------------------------- - - public static final boolean isOptedOut(final @Nullable Block block) - { return isOptedOut(block.asItem()); } - - public static final boolean isOptedOut(final @Nullable Item item) - { return (item!=null) && optouts_.contains(item.getRegistryName().getPath()); } - - public static boolean withExperimental() - { return with_experimental_features_; } - - public static boolean withoutRecipes() - { return false; } - - public static boolean withDebug() - { return with_debug_logs_; } - - //-------------------------------------------------------------------------------------------------------------------- - // Cache - //-------------------------------------------------------------------------------------------------------------------- - - private static final CompoundNBT server_config_ = new CompoundNBT(); - private static HashSet optouts_ = new HashSet<>(); - private static boolean with_experimental_features_ = false; - private static boolean with_config_logging_ = false; - private static boolean with_debug_logs_ = false; - public static boolean immersiveengineering_installed = false; - public static boolean without_direct_slab_pickup = false; - public static boolean with_creative_mode_device_drops = false; - - public static final CompoundNBT getServerConfig() // config that may be synchronized from server to client via net pkg. - { return server_config_; } - - private static final void updateOptouts() - { - final ArrayList includes = new ArrayList<>(); - final ArrayList excludes = new ArrayList<>(); - { - String inc = COMMON.pattern_includes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); - if(COMMON.pattern_includes.get() != inc) COMMON.pattern_includes.set(inc); - String[] incl = inc.split(","); - for(int i=0; i< incl.length; ++i) { - incl[i] = incl[i].replaceAll("[*]", ".*?"); - if(!incl[i].isEmpty()) includes.add(incl[i]); - } - } - { - String exc = COMMON.pattern_excludes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); - String[] excl = exc.split(","); - for(int i=0; i< excl.length; ++i) { - excl[i] = excl[i].replaceAll("[*]", ".*?"); - if(!excl[i].isEmpty()) excludes.add(excl[i]); - } - } - if(SERVER_CONFIG_SPEC.isLoaded()) { - /// @todo: remove for MC1.17/1.16.5 - String inc = SERVER.pattern_includes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); - String[] incl = inc.split(","); - for(int i=0; i< incl.length; ++i) { - incl[i] = incl[i].replaceAll("[*]", ".*?"); - if(!incl[i].isEmpty()) includes.add(incl[i]); - } - } - if(SERVER_CONFIG_SPEC.isLoaded()) { - /// @todo: remove for MC1.17/1.16.5 - String exc = SERVER.pattern_excludes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); - String[] excl = exc.split(","); - for(int i=0; i< excl.length; ++i) { - excl[i] = excl[i].replaceAll("[*]", ".*?"); - if(!excl[i].isEmpty()) excludes.add(excl[i]); - } - } - if(!excludes.isEmpty()) log("Config pattern excludes: '" + String.join(",", excludes) + "'"); - if(!includes.isEmpty()) log("Config pattern includes: '" + String.join(",", includes) + "'"); - { - HashSet optouts = new HashSet<>(); - ModContent.getRegisteredItems().stream().filter((item)->(item!=null)).forEach( - e -> optouts.add(e.getRegistryName().getPath()) - ); - ModContent.getRegisteredBlocks().stream().filter((Block block) -> { - if(block==null) return true; - if(block==ModContent.SIGN_MODLOGO) return true; - try { - if(!with_experimental_features_) { - if(block instanceof Auxiliaries.IExperimentalFeature) return true; - if(ModContent.isExperimentalBlock(block)) return true; - } - // Hard IE dependent blocks - if(!immersiveengineering_installed) { - if((block instanceof IDecorBlock) && ((((IDecorBlock)block).config() & DecorBlock.CFG_HARD_IE_DEPENDENT)!=0)) return true; - if((block instanceof DecorBlock.Normal) && ((((DecorBlock.Normal)block).config & DecorBlock.CFG_HARD_IE_DEPENDENT)!=0)) return true; - if((block instanceof StandardBlocks.BaseBlock) && ((((StandardBlocks.BaseBlock)block).config & DecorBlock.CFG_HARD_IE_DEPENDENT)!=0)) return true; - } - // Force-include/exclude pattern matching - final String rn = block.getRegistryName().getPath(); - try { - for(String e : includes) { - if(rn.matches(e)) { - log("Optout force include: "+rn); - return false; - } - } - for(String e : excludes) { - if(rn.matches(e)) { - log("Optout force exclude: "+rn); - return true; - } - } - } catch(Throwable ex) { - LOGGER.error("optout include pattern failed, disabling."); - includes.clear(); - excludes.clear(); - } - // Early non-opt out type based evaluation - if(SERVER==null) return false; - if(block instanceof EdCraftingTable.CraftingTableBlock) return SERVER.without_crafting_table.get(); - if(block instanceof EdElectricalFurnace.ElectricalFurnaceBlock) return SERVER.without_electrical_furnace.get(); - if((block instanceof EdFurnace.FurnaceBlock)&&(!(block instanceof EdElectricalFurnace.ElectricalFurnaceBlock))) return SERVER.without_lab_furnace.get(); - if(block instanceof EdWasteIncinerator.WasteIncineratorBlock) return SERVER.without_waste_incinerator.get(); - if(block instanceof EdDropper.DropperBlock) return SERVER.without_factory_dropper.get(); - if(block instanceof EdPlacer.PlacerBlock) return SERVER.without_factory_placer.get(); - if(block instanceof EdBreaker.BreakerBlock) return SERVER.without_block_breaker.get(); - if(block instanceof EdSlabSliceBlock) return SERVER.without_halfslabs.get(); - if(block instanceof EdLadderBlock) return SERVER.without_ladders.get(); - if(block instanceof EdWindowBlock) return SERVER.without_windows.get(); - if(block instanceof EdPipeValve.PipeValveBlock) return SERVER.without_valves.get(); - if(block instanceof EdHorizontalSupportBlock) return SERVER.without_hsupports.get(); - if(block instanceof EdFloorGratingBlock) return SERVER.without_floor_grating.get(); - if(block instanceof EdHopper.HopperBlock) return SERVER.without_factory_hopper.get(); - if(block instanceof EdFluidFunnel.FluidFunnelBlock) return SERVER.without_fluid_funnel.get(); - if(block instanceof EdSolarPanel.SolarPanelBlock) return SERVER.without_solar_panel.get(); - if(block instanceof EdMineralSmelter.MineralSmelterBlock) return SERVER.without_mineral_smelter.get(); - if(block instanceof EdMilker.MilkerBlock) return SERVER.without_milking_machine.get(); - if(block instanceof EdTreeCutter.TreeCutterBlock) return SERVER.without_tree_cutter.get(); - if(block instanceof EdLabeledCrate.LabeledCrateBlock) return SERVER.without_labeled_crate.get(); - // Type based evaluation where later filters may match, too - if(SERVER.without_slabs.get()&&(block instanceof EdSlabBlock)) return true; - if(SERVER.without_stairs.get()&&(block instanceof EdStairsBlock)) return true; - if(SERVER.without_walls.get()&&(block instanceof EdWallBlock)) return true; - if(SERVER.without_poles.get()&&(block instanceof EdStraightPoleBlock)) return true; - // String matching based evaluation - if(SERVER.without_clinker_bricks.get()&&(rn.startsWith("clinker_brick_"))) return true; - if(SERVER.without_slag_bricks.get()&&rn.startsWith("slag_brick_")) return true; - if(SERVER.without_rebar_concrete.get()&&rn.startsWith("rebar_concrete")) return true; - if(SERVER.without_gas_concrete.get()&&rn.startsWith("gas_concrete")) return true; - if(SERVER.without_panzer_glass.get()&&rn.startsWith("panzerglass_")) return true; - if(SERVER.without_light_sources.get()&&rn.endsWith("_light")) return true; - if(SERVER.without_sign_plates.get()&&rn.startsWith("sign_")) return true; - if(SERVER.without_treated_wood_furniture.get()) { - if(block instanceof EdChair.ChairBlock) return true; - if(rn.equals("treated_wood_table")) return true; - if(rn.equals("treated_wood_stool")) return true; - if(rn.equals("treated_wood_windowsill")) return true; - if(rn.equals("treated_wood_broad_windowsill")) return true; - if(rn.equals("treated_wood_side_table")) return true; - } - if(SERVER.without_metal_furniture.get()) { - if(rn.equals("steel_table")) return true; - } - if(SERVER.without_fences.get()) { - if(block instanceof EdFenceBlock) return true; - if(block instanceof EdDoubleGateBlock) return true; - } - } catch(Exception ex) { - LOGGER.error("Exception evaluating the optout config: '"+ex.getMessage()+"'"); - } - return false; - }).forEach( - e -> optouts.add(e.getRegistryName().getPath()) - ); - optouts_ = optouts; - } - OptionalRecipeCondition.on_config(withExperimental(), withoutRecipes(), ModConfig::isOptedOut, ModConfig::isOptedOut); - } - - public static final void apply() - { - with_config_logging_ = COMMON.with_config_logging.get(); - with_experimental_features_ = COMMON.with_experimental.get(); - with_debug_logs_ = COMMON.with_debug_logging.get(); - if(with_experimental_features_) LOGGER.info("Config: EXPERIMENTAL FEATURES ENABLED."); - if(with_debug_logs_) LOGGER.info("Config: DEBUG LOGGING ENABLED, WARNING, THIS MAY SPAM THE LOG."); - immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering"); - updateOptouts(); - if(!SERVER_CONFIG_SPEC.isLoaded()) return; - without_direct_slab_pickup = SERVER.without_direct_slab_pickup.get(); - // ----------------------------------------------------------------------------------------------------------------- - EdChair.on_config(SERVER.without_chair_sitting.get(), SERVER.without_mob_chair_sitting.get(), SERVER.chair_mob_sitting_probability_percent.get(), SERVER.chair_mob_standup_probability_percent.get()); - EdLadderBlock.on_config(SERVER.without_ladder_speed_boost.get()); - EdSlabBlock.on_config(!SERVER.without_direct_slab_pickup.get()); - EdSlabSliceBlock.on_config(!SERVER.without_direct_slab_pickup.get()); - EdLabeledCrate.on_config(false); - EdCraftingTable.on_config(SERVER.without_crafting_table_history.get(), false, SERVER.without_crafting_mouse_scrolling.get()); - EdFluidBarrel.on_config(12000, 1000); - EdFluidFunnel.on_config(with_experimental_features_); - EdPipeValve.on_config(SERVER.pipevalve_max_flowrate.get(), SERVER.pipevalve_redstone_gain.get()); - EdHopper.on_config(); - EdDropper.on_config(true); - EdPlacer.on_config(); - EdBreaker.on_config(SERVER.block_breaker_power_consumption.get(), SERVER.block_breaker_reluctance.get(), SERVER.block_breaker_min_breaking_time.get(), SERVER.block_breaker_requires_power.get()); - EdTreeCutter.on_config(SERVER.tree_cutter_energy_consumption.get(), SERVER.tree_cutter_cutting_time_needed.get(), SERVER.tree_cutter_requires_power.get()); - EdFurnace.on_config(SERVER.furnace_smelting_speed_percent.get(), SERVER.furnace_fuel_efficiency_percent.get(), SERVER.furnace_boost_energy_consumption.get(), SERVER.furnace_accepted_heaters.get()); - EdElectricalFurnace.on_config(SERVER.e_furnace_speed_percent.get(), SERVER.e_furnace_power_consumption.get(), SERVER.e_furnace_automatic_pulling.get()); - EdSolarPanel.on_config(SERVER.small_solar_panel_peak_production.get()); - EdMilker.on_config(SERVER.milking_machine_energy_consumption.get(), SERVER.milking_machine_milking_delay.get()); - EdFreezer.on_config(92, 2); - EdMineralSmelter.on_config(92, 2); - EdWasteIncinerator.on_config(8); - // ----------------------------------------------------------------------------------------------------------------- - { - // Check if the config is already synchronized or has to be synchronised. - server_config_.putBoolean("tree_cutter_requires_power", SERVER.tree_cutter_requires_power.get()); - server_config_.putBoolean("block_breaker_requires_power", SERVER.block_breaker_requires_power.get()); - { - String s = String.join(",", optouts_); - server_config_.putString("optout", s); - if(!s.isEmpty()) log("Opt-outs:" + s); - } - } - } - - public static final void log(String config_message) - { - if(!with_config_logging_) return; - LOGGER.info(config_message); - } - -} +/* + * @file ModConfig.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Main class for module settings. Handles reading and + * saving the config file. + */ +package wile.engineersdecor; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraftforge.common.ForgeConfigSpec; +import org.apache.commons.lang3.tuple.Pair; +import wile.engineersdecor.blocks.*; +import wile.engineersdecor.libmc.blocks.SlabSliceBlock; +import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.blocks.VariantSlabBlock; +import wile.engineersdecor.libmc.detail.Auxiliaries; +import wile.engineersdecor.libmc.detail.OptionalRecipeCondition; + +import javax.annotation.Nullable; +import java.util.*; + + +public class ModConfig +{ + //-------------------------------------------------------------------------------------------------------------------- + private static final String MODID = ModEngineersDecor.MODID; + public static final CommonConfig COMMON; + public static final ServerConfig SERVER; + public static final ForgeConfigSpec COMMON_CONFIG_SPEC; + public static final ForgeConfigSpec SERVER_CONFIG_SPEC; + + static { + final Pair common_ = (new ForgeConfigSpec.Builder()).configure(CommonConfig::new); + COMMON_CONFIG_SPEC = common_.getRight(); + COMMON = common_.getLeft(); + final Pair server_ = (new ForgeConfigSpec.Builder()).configure(ServerConfig::new); + SERVER_CONFIG_SPEC = server_.getRight(); + SERVER = server_.getLeft(); + } + + //-------------------------------------------------------------------------------------------------------------------- + + public static class CommonConfig + { + // Optout + public final ForgeConfigSpec.ConfigValue pattern_excludes; + public final ForgeConfigSpec.ConfigValue pattern_includes; + // MISC + public final ForgeConfigSpec.BooleanValue with_creative_mode_device_drops; + public final ForgeConfigSpec.BooleanValue with_experimental; + public final ForgeConfigSpec.BooleanValue with_config_logging; + public final ForgeConfigSpec.BooleanValue with_debug_logging; + + CommonConfig(ForgeConfigSpec.Builder builder) + { + builder.comment("Settings affecting the logical server side.") + .push("server"); + // --- OPTOUTS ------------------------------------------------------------ + { + builder.comment("Opt-out settings") + .push("optout"); + pattern_excludes = builder + .translation(MODID + ".config.pattern_excludes") + .comment("Opt-out any block by its registry name ('*' wildcard matching, " + + "comma separated list, whitespaces ignored. You must match the whole name, " + + "means maybe add '*' also at the begin and end. Example: '*wood*,*steel*' " + + "excludes everything that has 'wood' or 'steel' in the registry name. " + + "The matching result is also traced in the log file. ") + .define("pattern_excludes", ""); + pattern_includes = builder + .translation(MODID + ".config.pattern_includes") + .comment("Prevent blocks from being opt'ed by registry name ('*' wildcard matching, " + + "comma separated list, whitespaces ignored. Evaluated before all other opt-out checks. " + + "You must match the whole name, means maybe add '*' also at the begin and end. Example: " + + "'*wood*,*steel*' includes everything that has 'wood' or 'steel' in the registry name." + + "The matching result is also traced in the log file.") + .define("pattern_includes", ""); + builder.pop(); + } + // --- MISC --------------------------------------------------------------- + { + builder.comment("Miscellaneous settings") + .push("miscellaneous"); + with_experimental = builder + .translation(MODID + ".config.with_experimental") + .comment("Enables experimental features. Use at own risk.") + .define("with_experimental", false); + with_creative_mode_device_drops = builder + .translation(MODID + ".config.with_creative_mode_device_drops") + .comment("Enable that devices are dropped as item also in creative mode, allowing " + + " to relocate them with contents and settings.") + .define("with_creative_mode_device_drops", false); + with_config_logging = builder + .translation(MODID + ".config.with_debug_logging") + .comment("Enable detailed logging of the config values and resulting calculations in each mod feature config.") + .define("with_debug_logging", false); + with_debug_logging = builder + .translation(MODID + ".config.with_debug_logging") + .comment("Enable debug log messages for trouble shooting. Don't activate if not really needed, this can spam the log file.") + .define("with_debug_logging", false); + builder.pop(); + } + } + } + + //-------------------------------------------------------------------------------------------------------------------- + + public static class ServerConfig + { + // Optout + public final ForgeConfigSpec.BooleanValue without_chair_sitting; + public final ForgeConfigSpec.BooleanValue without_mob_chair_sitting; + public final ForgeConfigSpec.BooleanValue without_ladder_speed_boost; + public final ForgeConfigSpec.BooleanValue without_crafting_table_history; + // Misc + public final ForgeConfigSpec.BooleanValue without_direct_slab_pickup; + // Tweaks + public final ForgeConfigSpec.IntValue furnace_smelting_speed_percent; + public final ForgeConfigSpec.IntValue furnace_fuel_efficiency_percent; + public final ForgeConfigSpec.IntValue furnace_boost_energy_consumption; + public final ForgeConfigSpec.ConfigValue furnace_accepted_heaters; + public final ForgeConfigSpec.IntValue e_furnace_speed_percent; + public final ForgeConfigSpec.IntValue e_furnace_power_consumption; + public final ForgeConfigSpec.IntValue small_solar_panel_peak_production; + public final ForgeConfigSpec.BooleanValue e_furnace_automatic_pulling; + public final ForgeConfigSpec.DoubleValue chair_mob_sitting_probability_percent; + public final ForgeConfigSpec.DoubleValue chair_mob_standup_probability_percent; + public final ForgeConfigSpec.BooleanValue without_crafting_mouse_scrolling; + public final ForgeConfigSpec.IntValue pipevalve_max_flowrate; + public final ForgeConfigSpec.IntValue pipevalve_redstone_gain; + public final ForgeConfigSpec.IntValue block_breaker_power_consumption; + public final ForgeConfigSpec.IntValue block_breaker_reluctance; + public final ForgeConfigSpec.IntValue block_breaker_min_breaking_time; + public final ForgeConfigSpec.BooleanValue block_breaker_requires_power; + public final ForgeConfigSpec.IntValue tree_cutter_energy_consumption; + public final ForgeConfigSpec.IntValue tree_cutter_cutting_time_needed; + public final ForgeConfigSpec.BooleanValue tree_cutter_requires_power; + public final ForgeConfigSpec.IntValue milking_machine_energy_consumption; + public final ForgeConfigSpec.IntValue milking_machine_milking_delay; + + ServerConfig(ForgeConfigSpec.Builder builder) + { + builder.comment("Settings affecting the logical server side.") + .push("server"); + // --- OPTOUTS ------------------------------------------------------------ + { + builder.comment("Server dev opt-out settings !WARNING THE OPT-OUTs will be moved to common-config.toml in the next MC version!") + .push("optout"); + without_chair_sitting = builder + .translation(MODID + ".config.without_chair_sitting") + .comment("Disable possibility to sit on stools and chairs.") + .define("without_chair_sitting", false); + without_mob_chair_sitting = builder + .translation(MODID + ".config.without_mob_chair_sitting") + .comment("Disable that mobs will sit on chairs and stools.") + .define("without_mob_chair_sitting", false); + without_ladder_speed_boost = builder + .translation(MODID + ".config.without_ladder_speed_boost") + .comment("Disable the speed boost of ladders in this mod.") + .define("without_ladder_speed_boost", false); + without_crafting_table_history = builder + .translation(MODID + ".config.without_crafting_table_history") + .comment("Disable history refabrication feature of the crafting table.") + .define("without_crafting_table_history", false); + builder.pop(); + } + // --- MISC --------------------------------------------------------------- + { + builder.comment("Miscellaneous settings") + .push("miscellaneous"); + without_direct_slab_pickup = builder + .translation(MODID + ".config.without_direct_slab_pickup") + .comment("Disable directly picking up layers from slabs and slab " + + " slices by left clicking while looking up/down.") + .define("without_direct_slab_pickup", false); + builder.pop(); + } + // --- TWEAKS ------------------------------------------------------------- + { + builder.comment("Tweaks") + .push("tweaks"); + furnace_smelting_speed_percent = builder + .translation(MODID + ".config.furnace_smelting_speed_percent") + .comment("Defines, in percent, how fast the lab furnace smelts compared to " + + "a vanilla furnace. 100% means vanilla furnace speed, 150% means the " + + "lab furnace is faster. The value can be changed on-the-fly for tuning.") + .defineInRange("furnace_smelting_speed_percent", 130, 50, 800); + furnace_fuel_efficiency_percent = builder + .translation(MODID + ".config.furnace_fuel_efficiency_percent") + .comment("Defines, in percent, how fuel efficient the lab furnace is, compared " + + "to a vanilla furnace. 100% means vanilla furnace consumiton, 200% means " + + "the lab furnace needs about half the fuel of a vanilla furnace, " + + "The value can be changed on-the-fly for tuning.") + .defineInRange("furnace_fuel_efficiency_percent", 100, 50, 400); + furnace_boost_energy_consumption = builder + .translation(MODID + ".config.furnace_boost_energy_consumption") + .comment("Defines the energy consumption (per tick) for speeding up the smelting process. " + + "If IE is installed, an external heater has to be inserted into an auxiliary slot " + + "of the lab furnace. The power source needs to be able to provide at least 4 times " + + "this consumption (fixed threshold value). The value can be changed on-the-fly for tuning. " + + "The default value corresponds to the IE heater consumption.") + .defineInRange("furnace_boost_energy_consumption", 24, 2, 1024); + furnace_accepted_heaters = builder + .translation(MODID + ".config.furnace_accepted_heaters") + .comment("Defines (as comma separated list of full registry names) which items are allowed as external " + + "heaters in the Aux slot for powered speed boosting.") + .define("furnace_accepted_heaters", "immersiveengineering:furnace_heater"); + chair_mob_sitting_probability_percent = builder + .translation(MODID + ".config.chair_mob_sitting_probability_percent") + .comment("Defines, in percent, how high the probability is that a mob sits on a chair " + + "when colliding with it. Can be changed on-the-fly for tuning.") + .defineInRange("chair_mob_sitting_probability_percent", 10.0, 0.0, 80.0); + chair_mob_standup_probability_percent = builder + .translation(MODID + ".config.chair_mob_standup_probability_percent") + .comment("Defines, in percent, probable it is that a mob leaves a chair when sitting " + + "on it. The 'dice is rolled' about every 20 ticks. There is also a minimum " + + "Sitting time of about 3s. The config value can be changed on-the-fly for tuning.") + .defineInRange("chair_mob_standup_probability_percent", 1.0, 1e-3, 10.0); + without_crafting_mouse_scrolling = builder + .translation(MODID + ".config.without_crafting_mouse_scrolling") + .comment("Disables increasing/decreasing the crafting grid items by scrolling over the crafting result slot.") + .define("without_crafting_mouse_scrolling", false); + pipevalve_max_flowrate = builder + .translation(MODID + ".config.pipevalve_max_flowrate") + .comment("Defines how many millibuckets can be transferred (per tick) through the valves. " + + "That is technically the 'storage size' specified for blocks that want to fill " + + "fluids into the valve (the valve has no container and forward that to the output " + + "block), The value can be changed on-the-fly for tuning. ") + .defineInRange("pipevalve_max_flowrate", 1000, 1, 32000); + pipevalve_redstone_gain = builder + .translation(MODID + ".config.pipevalve_redstone_gain") + .comment("Defines how many millibuckets per redstone signal strength can be transferred per tick " + + "through the analog redstone controlled valves. Note: power 0 is always off, power 15 is always " + + "the max flow rate. Between power 1 and 14 this scaler will result in a flow = 'redstone slope' * 'current redstone power'. " + + "The value can be changed on-the-fly for tuning. ") + .defineInRange("pipevalve_redstone_gain", 20, 1, 32000); + e_furnace_speed_percent = builder + .translation(MODID + ".config.e_furnace_speed_percent") + .comment("Defines, in percent, how fast the electrical furnace smelts compared to " + + "a vanilla furnace. 100% means vanilla furnace speed, 150% means the " + + "electrical furnace is faster. The value can be changed on-the-fly for tuning.") + .defineInRange("e_furnace_speed_percent", EdElectricalFurnace.ElectricalFurnaceTileEntity.DEFAULT_SPEED_PERCENT, 50, 800); + e_furnace_power_consumption = builder + .translation(MODID + ".config.e_furnace_power_consumption") + .comment("Defines how much RF per tick the the electrical furnace consumed (average) for smelting. " + + "The feeders transferring items from/to adjacent have this consumption/8 for each stack transaction. " + + "The default value is only slightly higher than a furnace with an IE external heater (and no burning fuel inside)." + + "The config value can be changed on-the-fly for tuning.") + .defineInRange("e_furnace_power_consumption", EdElectricalFurnace.ElectricalFurnaceTileEntity.DEFAULT_ENERGY_CONSUMPTION, 8, 4096); + e_furnace_automatic_pulling = builder + .translation(MODID + ".config.e_furnace_automatic_pulling") + .comment("Defines if the electrical furnace automatically pulls items from an inventory at the input side." + + "The config value can be changed on-the-fly for tuning.") + .define("e_furnace_automatic_pulling", false); + small_solar_panel_peak_production = builder + .translation(MODID + ".config.small_solar_panel_peak_production") + .comment("Defines the peak power production (at noon) of the Small Solar Panel. " + + "Note that the agerage power is much less, as no power is produced at all during the night, " + + "and the power curve is nonlinear rising/falling during the day. Bad weather conditions also " + + "decrease the production. The config value can be changed on-the-fly for tuning.") + .defineInRange("small_solar_panel_peak_production", EdSolarPanel.DEFAULT_PEAK_POWER, 2, 4096); + block_breaker_power_consumption = builder + .translation(MODID + ".config.block_breaker_power_consumption") + .comment("Defines how much RF power the Small Block Breaker requires to magnificently increase the processing speed. " + + "The config value can be changed on-the-fly for tuning.") + .defineInRange("block_breaker_power_consumption", EdBreaker.DEFAULT_BOOST_ENERGY, 4, 1024); + block_breaker_reluctance = builder + .translation(MODID + ".config.block_breaker_reluctance") + .comment("Defines how much time the Small Block Breaker needs per block hardness, " + + "means: 'reluctance' * hardness + min_time, you change the 'reluctance' here." + + "The unit is ticks/hardness. " + "The config value can be changed on-the-fly for tuning.") + .defineInRange("block_breaker_reluctance", EdBreaker.DEFAULT_BREAKING_RELUCTANCE, 5, 50); + block_breaker_min_breaking_time = builder + .translation(MODID + ".config.block_breaker_min_breaking_time") + .comment("Defines how much time the Small Block Breaker needs at least, better said it's an offset: " + + "'reluctance' * hardness + min_time, you change the 'min_time' here, value " + + "in ticks." + "The config value can be changed on-the-fly for tuning.") + .defineInRange("block_breaker_min_breaking_time", EdBreaker.DEFAULT_MIN_BREAKING_TIME, 10, 100); + block_breaker_requires_power = builder + .translation(MODID + ".config.block_breaker_requires_power") + .comment("Defines if the Small Block Breaker does not work without RF power.") + .define("block_breaker_requires_power", false); + tree_cutter_energy_consumption = builder + .translation(MODID + ".config.tree_cutter_energy_consumption") + .comment("Defines how much RF power the Small Tree Cutter requires to magnificently increase the processing speed. " + + "The config value can be changed on-the-fly for tuning.") + .defineInRange("tree_cutter_energy_consumption", EdTreeCutter.TreeCutterTileEntity.DEFAULT_BOOST_ENERGY, 4, 1024); + tree_cutter_cutting_time_needed = builder + .translation(MODID + ".config.tree_cutter_cutting_time_needed") + .comment("Defines how much time the Small Tree Cutter needs to cut a tree without RF power. " + + "The value is in seconds. With energy it is 6 times faster. " + + "The config value can be changed on-the-fly for tuning.") + .defineInRange("tree_cutter_cutting_time_needed", EdTreeCutter.TreeCutterTileEntity.DEFAULT_CUTTING_TIME_NEEDED, 10, 240); + tree_cutter_requires_power = builder + .translation(MODID + ".config.tree_cutter_requires_power") + .comment("Defines if the Small Tree Cutter does not work without RF power.") + .define("tree_cutter_requires_power", false); + milking_machine_energy_consumption = builder + .translation(MODID + ".config.milking_machine_energy_consumption") + .comment("Defines how much time the Small Milking Machine needs work. " + + "Note this is a permanent standby power, not only when the device does something. " + + "Use zero to disable energy dependency and energy handling of the machine. " + + "The config value can be changed on-the-fly for tuning.") + .defineInRange("milking_machine_energy_consumption", EdMilker.DEFAULT_ENERGY_CONSUMPTION, 0, 1024); + milking_machine_milking_delay = builder + .translation(MODID + ".config.milking_machine_milking_delay") + .comment("Defines (for each individual cow) the minimum time between milking." ) + .defineInRange("milking_machine_milking_delay", EdMilker.DEFAULT_MILKING_DELAY_PER_COW, 1000, 24000); + builder.pop(); + } + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // Optout checks + //-------------------------------------------------------------------------------------------------------------------- + + public static boolean isOptedOut(final @Nullable Block block) + { return isOptedOut(block.asItem()); } + + public static boolean isOptedOut(final @Nullable Item item) + { return (item!=null) && optouts_.contains(item.getRegistryName().getPath()); } + + public static boolean withExperimental() + { return with_experimental_features_; } + + public static boolean withoutRecipes() + { return false; } + + public static boolean withDebug() + { return with_debug_logs_; } + + public static boolean withDebugLogging() + { return with_experimental_features_ && with_config_logging_; } + + //-------------------------------------------------------------------------------------------------------------------- + // Cache + //-------------------------------------------------------------------------------------------------------------------- + + private static final CompoundTag server_config_ = new CompoundTag(); + private static HashSet optouts_ = new HashSet<>(); + private static boolean with_experimental_features_ = false; + private static boolean with_config_logging_ = false; + private static boolean with_debug_logs_ = false; + public static boolean immersiveengineering_installed = false; + public static boolean without_direct_slab_pickup = false; + public static boolean with_creative_mode_device_drops = false; + + public static CompoundTag getServerConfig() // config that may be synchronized from server to client via net pkg. + { return server_config_; } + + private static void updateOptouts() + { + final ArrayList includes = new ArrayList<>(); + final ArrayList excludes = new ArrayList<>(); + { + String inc = COMMON.pattern_includes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); + if(!COMMON.pattern_includes.get().equals(inc)) COMMON.pattern_includes.set(inc); + String[] incl = inc.split(","); + for(int i=0; i< incl.length; ++i) { + incl[i] = incl[i].replaceAll("[*]", ".*?"); + if(!incl[i].isEmpty()) includes.add(incl[i]); + } + } + { + String exc = COMMON.pattern_excludes.get().toLowerCase().replaceAll(MODID+":", "").replaceAll("[^*_,a-z0-9]", ""); + String[] excl = exc.split(","); + for(int i=0; i< excl.length; ++i) { + excl[i] = excl[i].replaceAll("[*]", ".*?"); + if(!excl[i].isEmpty()) excludes.add(excl[i]); + } + } + if(!excludes.isEmpty()) log("Config pattern excludes: '" + String.join(",", excludes) + "'"); + if(!includes.isEmpty()) log("Config pattern includes: '" + String.join(",", includes) + "'"); + { + HashSet optouts = new HashSet<>(); + ModContent.getRegisteredItems().stream().filter(Objects::nonNull).forEach( + e -> optouts.add(e.getRegistryName().getPath()) + ); + ModContent.getRegisteredBlocks().stream().filter((Block block) -> { + if(block==null) return true; + if(block==ModContent.SIGN_MODLOGO) return true; + try { + if(!with_experimental_features_) { + if(block instanceof Auxiliaries.IExperimentalFeature) return true; + if(ModContent.isExperimentalBlock(block)) return true; + } + // Hard IE dependent blocks + if(!immersiveengineering_installed) { + if((block instanceof StandardBlocks.IStandardBlock) && ((((StandardBlocks.IStandardBlock)block).config() & DecorBlock.CFG_HARD_IE_DEPENDENT)!=0)) return true; + } + // Force-include/exclude pattern matching + final String rn = block.getRegistryName().getPath(); + try { + for(String e : includes) { + if(rn.matches(e)) { + log("Optout force include: "+rn); + return false; + } + } + for(String e : excludes) { + if(rn.matches(e)) { + log("Optout force exclude: "+rn); + return true; + } + } + } catch(Throwable ex) { + Auxiliaries.logger().error("optout include pattern failed, disabling."); + includes.clear(); + excludes.clear(); + } + } catch(Exception ex) { + Auxiliaries.logger().error("Exception evaluating the optout config: '"+ex.getMessage()+"'"); + } + return false; + }).forEach( + e -> optouts.add(e.getRegistryName().getPath()) + ); + optouts_ = optouts; + } + OptionalRecipeCondition.on_config(withExperimental(), withoutRecipes(), ModConfig::isOptedOut, ModConfig::isOptedOut); + } + + public static void apply() + { + with_config_logging_ = COMMON.with_config_logging.get(); + with_experimental_features_ = COMMON.with_experimental.get(); + with_debug_logs_ = COMMON.with_debug_logging.get(); + if(with_experimental_features_) Auxiliaries.logger().info("Config: EXPERIMENTAL FEATURES ENABLED."); + if(with_debug_logs_) Auxiliaries.logger().info("Config: DEBUG LOGGING ENABLED, WARNING, THIS MAY SPAM THE LOG."); + immersiveengineering_installed = Auxiliaries.isModLoaded("immersiveengineering"); + updateOptouts(); + if(!SERVER_CONFIG_SPEC.isLoaded()) return; + without_direct_slab_pickup = SERVER.without_direct_slab_pickup.get(); + // ----------------------------------------------------------------------------------------------------------------- + EdChair.on_config(SERVER.without_chair_sitting.get(), SERVER.without_mob_chair_sitting.get(), SERVER.chair_mob_sitting_probability_percent.get(), SERVER.chair_mob_standup_probability_percent.get()); + EdLadderBlock.on_config(SERVER.without_ladder_speed_boost.get()); + VariantSlabBlock.on_config(!SERVER.without_direct_slab_pickup.get()); + SlabSliceBlock.on_config(!SERVER.without_direct_slab_pickup.get()); + EdLabeledCrate.on_config(false); + EdCraftingTable.on_config(SERVER.without_crafting_table_history.get(), false, SERVER.without_crafting_mouse_scrolling.get()); + EdFluidBarrel.on_config(12000, 1000); + EdFluidFunnel.on_config(with_experimental_features_); + EdPipeValve.on_config(SERVER.pipevalve_max_flowrate.get(), SERVER.pipevalve_redstone_gain.get()); + EdHopper.on_config(); + EdDropper.on_config(true); + EdPlacer.on_config(); + EdBreaker.on_config(SERVER.block_breaker_power_consumption.get(), SERVER.block_breaker_reluctance.get(), SERVER.block_breaker_min_breaking_time.get(), SERVER.block_breaker_requires_power.get()); + EdTreeCutter.on_config(SERVER.tree_cutter_energy_consumption.get(), SERVER.tree_cutter_cutting_time_needed.get(), SERVER.tree_cutter_requires_power.get()); + EdFurnace.on_config(SERVER.furnace_smelting_speed_percent.get(), SERVER.furnace_fuel_efficiency_percent.get(), SERVER.furnace_boost_energy_consumption.get(), SERVER.furnace_accepted_heaters.get()); + EdElectricalFurnace.on_config(SERVER.e_furnace_speed_percent.get(), SERVER.e_furnace_power_consumption.get(), SERVER.e_furnace_automatic_pulling.get()); + EdSolarPanel.on_config(SERVER.small_solar_panel_peak_production.get(), 64000, 1024); + EdMilker.on_config(SERVER.milking_machine_energy_consumption.get(), SERVER.milking_machine_milking_delay.get()); + EdFreezer.on_config(92, 2); + EdMineralSmelter.on_config(92, 2); + EdWasteIncinerator.on_config(8); + // ----------------------------------------------------------------------------------------------------------------- + { + // Check if the config is already synchronized or has to be synchronised. + server_config_.putBoolean("tree_cutter_requires_power", SERVER.tree_cutter_requires_power.get()); + server_config_.putBoolean("block_breaker_requires_power", SERVER.block_breaker_requires_power.get()); + { + String s = String.join(",", optouts_); + server_config_.putString("optout", s); + if(!s.isEmpty()) log("Opt-outs:" + s); + } + } + } + + public static void log(String config_message) + { + if(!with_config_logging_) return; + Auxiliaries.logger().info(config_message); + } + +} diff --git a/src/main/java/wile/engineersdecor/ModContent.java b/src/main/java/wile/engineersdecor/ModContent.java index 13e1910..01dd603 100644 --- a/src/main/java/wile/engineersdecor/ModContent.java +++ b/src/main/java/wile/engineersdecor/ModContent.java @@ -1,1470 +1,1350 @@ -/* - * @file ModContent.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Definition and initialisation of blocks of this - * module, along with their tile entities if applicable. - * - * Note: Straight forward definition of different blocks/entities - * to make recipes, models and texture definitions easier. - */ -package wile.engineersdecor; - -import net.minecraft.block.BlockState; -import net.minecraft.util.SoundEvents; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.shapes.IBooleanFunction; -import net.minecraft.world.IBlockReader; -import net.minecraft.block.material.MaterialColor; -import net.minecraft.block.Block; -import net.minecraft.block.SoundType; -import net.minecraft.block.material.Material; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.item.Item; -import net.minecraft.item.BlockItem; -import net.minecraft.entity.EntityClassification; -import net.minecraft.entity.EntityType; -import net.minecraft.inventory.container.ContainerType; -import net.minecraft.util.ResourceLocation; -import net.minecraft.util.Direction; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.shapes.VoxelShape; -import net.minecraft.util.math.shapes.VoxelShapes; -import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.RenderTypeLookup; -import net.minecraft.client.gui.ScreenManager; -import net.minecraftforge.common.ToolType; -import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.fml.client.registry.RenderingRegistry; -import net.minecraftforge.fml.client.registry.ClientRegistry; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import org.apache.commons.lang3.ArrayUtils; -import wile.engineersdecor.blocks.*; -import wile.engineersdecor.blocks.EdFurnace.FurnaceBlock; -import wile.engineersdecor.blocks.EdFurnace.FurnaceContainer; -import wile.engineersdecor.blocks.EdFurnace.FurnaceGui; -import wile.engineersdecor.blocks.EdFurnace.FurnaceTileEntity; -import wile.engineersdecor.items.EdItem; -import wile.engineersdecor.libmc.blocks.StandardBlocks; -import wile.engineersdecor.libmc.blocks.StandardBlocks.IStandardBlock; -import wile.engineersdecor.libmc.detail.Auxiliaries; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; -import java.util.Collections; -import javax.annotation.Nonnull; - - -import net.minecraft.block.AbstractBlock; - -@SuppressWarnings("unused") -public class ModContent -{ - private static final String MODID = ModEngineersDecor.MODID; - - //-------------------------------------------------------------------------------------------------------------------- - - private static Boolean disallowSpawn(BlockState state, IBlockReader reader, BlockPos pos, EntityType entity) { return false; } - - //-------------------------------------------------------------------------------------------------------------------- - // Blocks - //-------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal CLINKER_BRICK_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_block")); - - public static final EdSlabBlock CLINKER_BRICK_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_slab")); - - public static final EdStairsBlock CLINKER_BRICK_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - CLINKER_BRICK_BLOCK.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stairs")); - - public static final EdWallBlock CLINKER_BRICK_WALL = (EdWallBlock)(new EdWallBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_wall")); - - public static final DecorBlock.Normal CLINKER_BRICK_STAINED_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_block")); - - public static final EdSlabBlock CLINKER_BRICK_STAINED_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_slab")); - - public static final EdStairsBlock CLINKER_BRICK_STAINED_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - CLINKER_BRICK_BLOCK.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_stairs")); - - public static final EdCornerOrnamentedBlock CLINKER_BRICK_SASTOR_CORNER = (EdCornerOrnamentedBlock)(new EdCornerOrnamentedBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), - new Block[]{CLINKER_BRICK_BLOCK, CLINKER_BRICK_STAINED_BLOCK, CLINKER_BRICK_SLAB, CLINKER_BRICK_STAIRS, CLINKER_BRICK_STAINED_SLAB, CLINKER_BRICK_STAINED_STAIRS} - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_sastor_corner_block")); - - public static final DecorBlock.HorizontalWaterLoggable CLINKER_BRICK_RECESSED = (DecorBlock.HorizontalWaterLoggable)(new DecorBlock.HorizontalWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), - new AxisAlignedBB[] { - Auxiliaries.getPixeledAABB( 3,0, 0, 13,16, 1), - Auxiliaries.getPixeledAABB( 0,0, 1, 16,16,11), - Auxiliaries.getPixeledAABB( 4,0,11, 12,16,13) - } - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_recessed")); - - public static final DecorBlock.HorizontalWaterLoggable CLINKER_BRICK_SASTOR_VERTICAL_SLOTTED = (DecorBlock.HorizontalWaterLoggable)(new DecorBlock.HorizontalWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), - new AxisAlignedBB[] { - Auxiliaries.getPixeledAABB( 3,0, 0, 13,16, 1), - Auxiliaries.getPixeledAABB( 3,0,15, 13,16,16), - Auxiliaries.getPixeledAABB( 0,0, 1, 16,16,15) - } - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_vertically_slit")); - - public static final DecorBlock.HorizontalWaterLoggable CLINKER_BRICK_VERTICAL_SLAB_STRUCTURED = (DecorBlock.HorizontalWaterLoggable)(new DecorBlock.HorizontalWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), - new AxisAlignedBB[] { - Auxiliaries.getPixeledAABB( 0,0, 0, 16,16, 8), - } - )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_vertical_slab_structured")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal SLAG_BRICK_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "slag_brick_block")); - - public static final EdSlabBlock SLAG_BRICK_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "slag_brick_slab")); - - public static final EdStairsBlock SLAG_BRICK_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - SLAG_BRICK_BLOCK.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "slag_brick_stairs")); - - public static final EdWallBlock SLAG_BRICK_WALL = (EdWallBlock)(new EdWallBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "slag_brick_wall")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal REBAR_CONCRETE_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete")); - - public static final EdSlabBlock REBAR_CONCRETE_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_slab")); - - public static final EdStairsBlock REBAR_CONCRETE_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - REBAR_CONCRETE_BLOCK.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_stairs")); - - public static final EdWallBlock REBAR_CONCRETE_WALL = (EdWallBlock)(new EdWallBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_wall")); - - public static final EdSlabSliceBlock HALFSLAB_REBARCONCRETE = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "halfslab_rebar_concrete")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal GAS_CONCRETE_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(1.5f, 10f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "gas_concrete")); - - public static final EdSlabBlock GAS_CONCRETE_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(1.5f, 10f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "gas_concrete_slab")); - - public static final EdStairsBlock GAS_CONCRETE_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - REBAR_CONCRETE_BLOCK.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(1.5f, 10f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "gas_concrete_stairs")); - - public static final EdWallBlock GAS_CONCRETE_WALL = (EdWallBlock)(new EdWallBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(1.5f, 10f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "gas_concrete_wall")); - - public static final EdSlabSliceBlock HALFSLAB_GASCONCRETE = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(1.5f, 10f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "halfslab_gas_concrete")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal REBAR_CONCRETE_TILE = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile")); - - public static final EdSlabBlock REBAR_CONCRETE_TILE_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile_slab")); - - public static final EdStairsBlock REBAR_CONCRETE_TILE_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - REBAR_CONCRETE_TILE.defaultBlockState(), - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile_stairs")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdGlassBlock PANZERGLASS_BLOCK = (EdGlassBlock)(new EdGlassBlock( - DecorBlock.CFG_TRANSLUCENT, - AbstractBlock.Properties.of(Material.GLASS, MaterialColor.NONE).strength(0.7f, 2000f).sound(SoundType.METAL).noOcclusion().isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "panzerglass_block")); - - public static final EdSlabBlock PANZERGLASS_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_TRANSLUCENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(0.7f, 2000f).sound(SoundType.METAL).noOcclusion().isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "panzerglass_slab")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF = (EdRoofBlock)(new EdRoofBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof")); - - public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF_METALIZED = (EdRoofBlock)(new EdRoofBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_metallized")); - - public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF_SKYLIGHT = (EdRoofBlock)(new EdRoofBlock( - DecorBlock.CFG_TRANSLUCENT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_skylight")); - - public static final EdChimneyTrunkBlock DARK_CERAMIC_SHINGLE_ROOF_CHIMNEYTRUNK = (EdChimneyTrunkBlock)(new EdChimneyTrunkBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn), - VoxelShapes.create(Auxiliaries.getPixeledAABB(3, 0, 3, 13, 16, 13)), - VoxelShapes.create(Auxiliaries.getPixeledAABB(5, 0, 5, 11, 16, 11)) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_chimneytrunk")); - - public static final EdChimneyTrunkBlock DARK_CERAMIC_SHINGLE_ROOF_WIRECONDUIT = (EdChimneyTrunkBlock)(new EdChimneyTrunkBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn), - VoxelShapes.join( - VoxelShapes.create(Auxiliaries.getPixeledAABB(3, 0, 3, 13, 13, 13)), - VoxelShapes.create(Auxiliaries.getPixeledAABB(5, 13, 5, 11, 16, 11)), - IBooleanFunction.OR - ), - VoxelShapes.join( - VoxelShapes.create(Auxiliaries.getPixeledAABB(5, 0, 5, 11, 15, 11)), - VoxelShapes.create(Auxiliaries.getPixeledAABB(7, 15, 7, 9, 16, 9)), - IBooleanFunction.OR - ) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_wireconduit")); - - public static final EdChimneyBlock DARK_CERAMIC_SHINGLE_ROOF_CHIMNEY = (EdChimneyBlock)(new EdChimneyBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 6f).sound(SoundType.STONE).dynamicShape().isValidSpawn(ModContent::disallowSpawn), - Auxiliaries.getPixeledAABB(3, 0, 3, 13, 6, 13) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_chimney")); - - public static final DecorBlock.Normal DARK_CERAMIC_SHINGLE_ROOF_BLOCK = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_block")); - - public static final EdSlabBlock DARK_CERAMIC_SHINGLE_ROOF_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_slab")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdGroundBlock DENSE_GRIT_SAND = (EdGroundBlock)(new EdGroundBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.DIRT, MaterialColor.DIRT).strength(0.5f, 3f).sound(SoundType.GRAVEL).harvestTool(ToolType.SHOVEL) - )).setRegistryName(new ResourceLocation(MODID, "dense_grit_sand_block")); - - public static final EdGroundBlock DENSE_GRIT_DIRT = (EdGroundBlock)(new EdGroundBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.DIRT, MaterialColor.DIRT).strength(0.5f, 3f).sound(SoundType.GRAVEL).harvestTool(ToolType.SHOVEL) - )).setRegistryName(new ResourceLocation(MODID, "dense_grit_dirt_block")); - - public static final EdSlabSliceBlock HALFSLAB_DARK_CERAMIC_SHINGLE_ROOF = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 15f).sound(SoundType.STONE) - )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_slabslice")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdLadderBlock METAL_RUNG_LADDER = (EdLadderBlock)(new EdLadderBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.0f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "metal_rung_ladder")); - - public static final EdLadderBlock METAL_RUNG_STEPS = (EdLadderBlock)(new EdLadderBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.0f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "metal_rung_steps")); - - public static final EdLadderBlock TREATED_WOOD_LADDER = (EdLadderBlock)(new EdLadderBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.0f, 8f).sound(SoundType.WOOD).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_ladder")); - - public static final EdHatchBlock IRON_HATCH = (EdHatchBlock)(new EdHatchBlock( - DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 2000f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0.5,1,0, 15.5,3,14), - Auxiliaries.getPixeledAABB(0.5,1,0, 15.5,14.,2) - )).setRegistryName(new ResourceLocation(MODID, "iron_hatch")); - - public static final EdDoorBlock METAL_SLIDING_DOOR = (EdDoorBlock)(new EdDoorBlock( - DecorBlock.CFG_TRANSLUCENT|DecorBlock.CFG_HORIZIONTAL, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.5f, 8f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(15, 0.0,6, 16,16.0,10), - Auxiliaries.getPixeledAABB( 0,15.5,6, 16,16.0,10), - }, - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(15, 0.0,6, 16,16.0,10), - Auxiliaries.getPixeledAABB( 0, 0.0,6, 16, 0.3,10), - }, - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 0,0,7, 16,16,9) - }, - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 0,0,7, 16,16,9) - }, - SoundEvents.IRON_DOOR_OPEN, SoundEvents.IRON_DOOR_CLOSE - )).setRegistryName(new ResourceLocation(MODID, "metal_sliding_door")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.Normal OLD_INDUSTRIAL_PLANKS = (DecorBlock.Normal)(new DecorBlock.Normal( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) - )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_planks")); - - public static final EdSlabBlock OLD_INDUSTRIAL_SLAB = (EdSlabBlock)(new EdSlabBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) - )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_slab")); - - public static final EdStairsBlock OLD_INDUSTRIAL_STAIRS = (EdStairsBlock)(new EdStairsBlock( - DecorBlock.CFG_DEFAULT, - OLD_INDUSTRIAL_PLANKS.defaultBlockState(), - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) - )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_stairs")); - - public static final EdSlabSliceBlock OLD_INDUSTRIAL_SLABSLICE = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_slabslice")); - - public static final EdDoorBlock OLD_INDUSTRIAL_WOOD_DOOR = (EdDoorBlock)(new EdDoorBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(15,0, 0, 16,16,16), - Auxiliaries.getPixeledAABB( 0,0,13, 16,16,16), - SoundEvents.WOODEN_DOOR_OPEN, SoundEvents.WOODEN_DOOR_CLOSE - )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_door")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.WaterLoggable TREATED_WOOD_TABLE = (DecorBlock.WaterLoggable)(new DecorBlock.WaterLoggable( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(1,0,1, 15,15.9,15) - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_table")); - - public static final EdChair.ChairBlock TREATED_WOOD_STOOL = (EdChair.ChairBlock)(new EdChair.ChairBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(4,7,4, 12,8.8,12), - Auxiliaries.getPixeledAABB(7,0,7, 9,7,9), - Auxiliaries.getPixeledAABB(4,0,7, 12,1,9), - Auxiliaries.getPixeledAABB(7,0,4, 9,1,12), - } - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_stool")); - - public static final DecorBlock.WaterLoggable TREATED_WOOD_SIDE_TABLE = (DecorBlock.WaterLoggable)(new DecorBlock.WaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 2,15, 2, 14,16,14), - Auxiliaries.getPixeledAABB( 3,15, 1, 13,16, 2), - Auxiliaries.getPixeledAABB( 3,15,14, 13,16,15), - Auxiliaries.getPixeledAABB( 1,15, 3, 2,16,13), - Auxiliaries.getPixeledAABB(14,15, 3, 15,16,13), - Auxiliaries.getPixeledAABB( 3,14, 3, 13,15,13), - Auxiliaries.getPixeledAABB( 7, 3, 7, 9,12, 9), - Auxiliaries.getPixeledAABB( 2, 0, 7, 14, 1, 9), - Auxiliaries.getPixeledAABB( 7, 0, 2, 9, 1,14) - } - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_side_table")); - - public static final DecorBlock.DirectedWaterLoggable TREATED_WOOD_WINDOWSILL = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(0.5,15,10.5, 15.5,16,16) - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_windowsill")); - - public static final DecorBlock.DirectedWaterLoggable TREATED_WOOD_BROAD_WINDOWSILL = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_FACING_PLACEMENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(0,14.5,4, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_broad_windowsill")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.DirectedWaterLoggable INSET_LIGHT_IRON = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), - Auxiliaries.getPixeledAABB(5.2,5.2,0, 10.8,10.8,0.3) - )).setRegistryName(new ResourceLocation(MODID, "iron_inset_light")); - - public static final DecorBlock.DirectedWaterLoggable FLOOR_EDGE_LIGHT_IRON = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), - Auxiliaries.getPixeledAABB(5,0,0, 11,2,0.5) - )).setRegistryName(new ResourceLocation(MODID, "iron_floor_edge_light")); - - public static final DecorBlock.DirectedWaterLoggable CEILING_EDGE_LIGHT_IRON = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 0,15.5,0, 16,16,2.0), - Auxiliaries.getPixeledAABB( 0,14.0,0, 16,16,0.5), - Auxiliaries.getPixeledAABB( 0,14.0,0, 1,16,2.0), - Auxiliaries.getPixeledAABB(15,14.0,0, 16,16,2.0), - } - )).setRegistryName(new ResourceLocation(MODID, "iron_ceiling_edge_light")); - - public static final DecorBlock.DirectedWaterLoggable BULB_LIGHT_IRON = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(6.5,6.5,1, 9.5,9.5,4), - Auxiliaries.getPixeledAABB(6.0,6.0,0, 10.0,10.0,1.0) - } - )).setRegistryName(new ResourceLocation(MODID, "iron_bulb_light")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.WaterLoggable STEEL_TABLE = (DecorBlock.WaterLoggable)(new DecorBlock.WaterLoggable( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "steel_table")); - - public static final EdFloorGratingBlock STEEL_FLOOR_GRATING = (EdFloorGratingBlock)(new EdFloorGratingBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,14,0, 16,15.5,16) - )).setRegistryName(new ResourceLocation(MODID, "steel_floor_grating")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdWindowBlock TREATED_WOOD_WINDOW = (EdWindowBlock)(new EdWindowBlock( - DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 8f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,7, 16,16,9) - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_window")); - - public static final EdWindowBlock STEEL_FRAMED_WINDOW = (EdWindowBlock)(new EdWindowBlock( - DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,7.5, 16,16,8.5) - )).setRegistryName(new ResourceLocation(MODID, "steel_framed_window")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdStraightPoleBlock TREATED_WOOD_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), - null - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole")); - - public static final EdStraightPoleBlock TREATED_WOOD_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), - TREATED_WOOD_POLE - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole_head")); - - public static final EdStraightPoleBlock TREATED_WOOD_POLE_SUPPORT = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), - TREATED_WOOD_POLE - )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole_support")); - - public static final EdStraightPoleBlock THIN_STEEL_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(6,6,0, 10,10,16), - null - )).setRegistryName(new ResourceLocation(MODID, "thin_steel_pole")); - - public static final EdStraightPoleBlock THIN_STEEL_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(6,6,0, 10,10,16), - THIN_STEEL_POLE - )).setRegistryName(new ResourceLocation(MODID, "thin_steel_pole_head")); - - public static final EdStraightPoleBlock THICK_STEEL_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(5,5,0, 11,11,16), - null - )).setRegistryName(new ResourceLocation(MODID, "thick_steel_pole")); - - public static final EdStraightPoleBlock THICK_STEEL_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(5,5,0, 11,11,16), - THICK_STEEL_POLE - )).setRegistryName(new ResourceLocation(MODID, "thick_steel_pole_head")); - - public static final EdHorizontalSupportBlock STEEL_DOUBLE_T_SUPPORT = (EdHorizontalSupportBlock)(new EdHorizontalSupportBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB( 5,11,0, 11,16,16), // main beam - Auxiliaries.getPixeledAABB(10,11,5, 16,16,11), // east beam (also for west 180deg) - Auxiliaries.getPixeledAABB( 6, 0,6, 10,16,10), // down thin - Auxiliaries.getPixeledAABB( 5, 0,5, 11,16,11) // down thick - )).setRegistryName(new ResourceLocation(MODID, "steel_double_t_support")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final DecorBlock.DirectedWaterLoggable SIGN_MODLOGO = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1000f).sound(SoundType.WOOD).lightLevel((state)->1).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,15.6, 16,16,16.0) - )).setRegistryName(new ResourceLocation(MODID, "sign_decor")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_HOTWIRE = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_hotwire")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_DANGER = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_danger")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_DEFENSE = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_defense")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_FACTORY_AREA = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_factoryarea")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_EXIT = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(3,7,15.6, 13,13,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_exit")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_RADIOACTIVE = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_radioactive")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_LASER = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_laser")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_CAUTION = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_caution")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_MAGIC_HAZARD = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_magichazard")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_FIRE_HAZARD = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_firehazard")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_HOT_SURFACE = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_hotsurface")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_MAGNETIC_FIELD = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_magneticfield")); - - public static final DecorBlock.DirectedWaterLoggable SIGN_FROST_WARNING = (DecorBlock.DirectedWaterLoggable)(new DecorBlock.DirectedWaterLoggable( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), - Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) - )).setRegistryName(new ResourceLocation(MODID, "sign_frost")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdCraftingTable.CraftingTableBlock CRAFTING_TABLE = (EdCraftingTable.CraftingTableBlock)(new EdCraftingTable.CraftingTableBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 12f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(0,15,0, 16,16,16), - Auxiliaries.getPixeledAABB(1, 0,1, 15,16,15) - } - )).setRegistryName(new ResourceLocation(MODID, "metal_crafting_table")); - - public static final FurnaceBlock SMALL_LAB_FURNACE = (FurnaceBlock)(new FurnaceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 12f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(1,0,1, 15, 1,15), - Auxiliaries.getPixeledAABB(0,1,1, 16,16,16), - } - )).setRegistryName(new ResourceLocation(MODID, "small_lab_furnace")); - - public static final EdElectricalFurnace.ElectricalFurnaceBlock SMALL_ELECTRICAL_FURNACE = (EdElectricalFurnace.ElectricalFurnaceBlock)(new EdElectricalFurnace.ElectricalFurnaceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(0, 0,0, 16,11,16), - Auxiliaries.getPixeledAABB(1,11,0, 15,12,16), - Auxiliaries.getPixeledAABB(2,12,0, 14,13,16), - Auxiliaries.getPixeledAABB(3,13,0, 13,14,16), - Auxiliaries.getPixeledAABB(4,14,0, 12,16,16), - } - )).setRegistryName(new ResourceLocation(MODID, "small_electrical_furnace")); - - public static final EdDropper.DropperBlock FACTORY_DROPPER = (EdDropper.DropperBlock)(new EdDropper.DropperBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,1, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "factory_dropper")); - - public static final EdPlacer.PlacerBlock FACTORY_PLACER = (EdPlacer.PlacerBlock)(new EdPlacer.PlacerBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(0,0,2, 16,16,16), - Auxiliaries.getPixeledAABB( 0,0,0, 1,16, 2), - Auxiliaries.getPixeledAABB(15,0,0,16,16, 2) - } - )).setRegistryName(new ResourceLocation(MODID, "factory_placer")); - - public static final EdBreaker.BreakerBlock SMALL_BLOCK_BREAKER = (EdBreaker.BreakerBlock)(new EdBreaker.BreakerBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(1,0,0, 15, 4, 7), - Auxiliaries.getPixeledAABB(1,0,7, 15,12,16), - Auxiliaries.getPixeledAABB(0,0,0, 1, 5, 4), - Auxiliaries.getPixeledAABB(0,0,4, 1,12,16), - Auxiliaries.getPixeledAABB(15,0,0, 16, 5, 4), - Auxiliaries.getPixeledAABB(15,0,4, 16,12,16) - } - )).setRegistryName(new ResourceLocation(MODID, "small_block_breaker")); - - public static final EdHopper.HopperBlock FACTORY_HOPPER = (EdHopper.HopperBlock)(new EdHopper.HopperBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(),()->{ - final AxisAlignedBB[] down_aabbs = new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 5, 0, 5, 11, 1,11), - Auxiliaries.getPixeledAABB( 4, 1, 4, 12, 7,12), - Auxiliaries.getPixeledAABB( 2, 7, 2, 14,10,14), - Auxiliaries.getPixeledAABB( 0,10, 0, 16,16,16), - Auxiliaries.getPixeledAABB( 0, 4, 5, 2,10,11), - Auxiliaries.getPixeledAABB(14, 4, 5, 16,10,11), - Auxiliaries.getPixeledAABB( 5, 4, 0, 11,10, 2), - Auxiliaries.getPixeledAABB( 5, 4,14, 11,10,16), - }; - final AxisAlignedBB[] up_aabbs = new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 5,15, 5, 11,16,11), - Auxiliaries.getPixeledAABB( 4,14, 4, 12, 9,12), - Auxiliaries.getPixeledAABB( 2, 9, 2, 14, 6,14), - Auxiliaries.getPixeledAABB( 0, 6, 0, 16, 0,16), - Auxiliaries.getPixeledAABB( 0,12, 5, 2, 6,11), - Auxiliaries.getPixeledAABB(14,12, 5, 16, 6,11), - Auxiliaries.getPixeledAABB( 5,12, 0, 11, 6, 2), - Auxiliaries.getPixeledAABB( 5,12,14, 11, 6,16), - }; - final AxisAlignedBB[] north_aabbs = new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 5, 0, 5, 11, 1,11), - Auxiliaries.getPixeledAABB( 4, 1, 4, 12, 7,12), - Auxiliaries.getPixeledAABB( 2, 7, 2, 14,10,14), - Auxiliaries.getPixeledAABB( 0,10, 0, 16,16,16), - Auxiliaries.getPixeledAABB( 0, 4, 5, 2,10,11), - Auxiliaries.getPixeledAABB(14, 4, 5, 16,10,11), - Auxiliaries.getPixeledAABB( 5, 1, 0, 11, 7, 4), - Auxiliaries.getPixeledAABB( 5, 4,14, 11,10,16), - }; - return new ArrayList(Arrays.asList( - Auxiliaries.getUnionShape(down_aabbs), - Auxiliaries.getUnionShape(up_aabbs), - Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.NORTH, false)), - Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.SOUTH, false)), - Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.WEST, false)), - Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.EAST, false)), - VoxelShapes.block(), - VoxelShapes.block() - )); - } - )).setRegistryName(new ResourceLocation(MODID, "factory_hopper")); - - public static final EdWasteIncinerator.WasteIncineratorBlock SMALL_WASTE_INCINERATOR = (EdWasteIncinerator.WasteIncineratorBlock)(new EdWasteIncinerator.WasteIncineratorBlock( - DecorBlock.CFG_DEFAULT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL), - Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "small_waste_incinerator")); - - public static final EdMineralSmelter.MineralSmelterBlock SMALL_MINERAL_SMELTER = (EdMineralSmelter.MineralSmelterBlock)(new EdMineralSmelter.MineralSmelterBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9) - )).setRegistryName(new ResourceLocation(MODID, "small_mineral_smelter")); - - public static final EdFreezer.FreezerBlock SMALL_FREEZER = (EdFreezer.FreezerBlock)(new EdFreezer.FreezerBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9) - )).setRegistryName(new ResourceLocation(MODID, "small_freezer")); - - public static final EdSolarPanel.SolarPanelBlock SMALL_SOLAR_PANEL = (EdSolarPanel.SolarPanelBlock)(new EdSolarPanel.SolarPanelBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(0,0,0, 16,2,16), - Auxiliaries.getPixeledAABB(6,1.5,3, 10,10.5,13), - } - )).setRegistryName(new ResourceLocation(MODID, "small_solar_panel")); - - public static final EdMilker.MilkerBlock SMALL_MILKING_MACHINE = (EdMilker.MilkerBlock)(new EdMilker.MilkerBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 1, 1,0, 15,14,10), - Auxiliaries.getPixeledAABB( 0,14,0, 16,16,13), - Auxiliaries.getPixeledAABB( 0, 0,0, 16, 1,13), - Auxiliaries.getPixeledAABB( 0, 1,1, 1,14,11), - Auxiliaries.getPixeledAABB(15, 1,1, 16,14,11) - } - )).setRegistryName(new ResourceLocation(MODID, "small_milking_machine")); - - public static final EdTreeCutter.TreeCutterBlock SMALL_TREE_CUTTER = (EdTreeCutter.TreeCutterBlock)(new EdTreeCutter.TreeCutterBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB( 0,0, 0, 16,3,16), - Auxiliaries.getPixeledAABB( 0,3, 0, 3,8,16), - Auxiliaries.getPixeledAABB( 3,7, 0, 5,8,16), - Auxiliaries.getPixeledAABB(15,0, 0, 16,6,16), - Auxiliaries.getPixeledAABB( 0,0,13, 16,8,16), - Auxiliaries.getPixeledAABB( 5,6,12, 16,8,13), - } - )).setRegistryName(new ResourceLocation(MODID, "small_tree_cutter")); - - public static final EdPipeValve.PipeValveBlock STRAIGHT_CHECK_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, - EdPipeValve.CFG_CHECK_VALVE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), - Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), - Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), - Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), - } - )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve")); - - public static final EdPipeValve.PipeValveBlock STRAIGHT_REDSTONE_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - EdPipeValve.CFG_REDSTONE_CONTROLLED_VALVE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), - Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), - Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), - Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), - } - )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve_redstone")); - - public static final EdPipeValve.PipeValveBlock STRAIGHT_REDSTONE_ANALOG_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - EdPipeValve.CFG_REDSTONE_CONTROLLED_VALVE|EdPipeValve.CFG_ANALOG_VALVE, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), - Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), - Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), - Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), - } - )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve_redstone_analog")); - - public static final EdFluidBarrel.FluidBarrelBlock FLUID_BARREL = (EdFluidBarrel.FluidBarrelBlock)(new EdFluidBarrel.FluidBarrelBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(2, 0,0, 14, 1,16), - Auxiliaries.getPixeledAABB(1, 1,0, 15, 2,16), - Auxiliaries.getPixeledAABB(0, 2,0, 16,14,16), - Auxiliaries.getPixeledAABB(1,14,0, 15,15,16), - Auxiliaries.getPixeledAABB(2,15,0, 14,16,16), - } - )).setRegistryName(new ResourceLocation(MODID, "fluid_barrel")); - - public static final EdFluidFunnel.FluidFunnelBlock SMALL_FLUID_FUNNEL = (EdFluidFunnel.FluidFunnelBlock)(new EdFluidFunnel.FluidFunnelBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[]{ - Auxiliaries.getPixeledAABB(0, 0,0, 16,14,16), - Auxiliaries.getPixeledAABB(1,14,1, 15,15,15), - Auxiliaries.getPixeledAABB(0,15,0, 16,16,16) - } - )).setRegistryName(new ResourceLocation(MODID, "small_fluid_funnel")); - - public static final EdLabeledCrate.LabeledCrateBlock LABELED_CRATE = (EdLabeledCrate.LabeledCrateBlock)(new EdLabeledCrate.LabeledCrateBlock( - DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(0.5f, 32f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "labeled_crate")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdSlabSliceBlock HALFSLAB_TREATEDWOOD = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 4f).sound(SoundType.WOOD).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_treated_wood")); - - public static final EdSlabSliceBlock HALFSLAB_SHEETMETALIRON = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_iron")); - - public static final EdSlabSliceBlock HALFSLAB_SHEETMETALSTEEL = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_steel")); - - public static final EdSlabSliceBlock HALFSLAB_SHEETMETALCOPPER = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_copper")); - - public static final EdSlabSliceBlock HALFSLAB_SHEETMETALGOLD = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_gold")); - - public static final EdSlabSliceBlock HALFSLAB_SHEETMETALALUMINIUM = (EdSlabSliceBlock)(new EdSlabSliceBlock( - DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() - )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_aluminum")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdFenceBlock STEEL_MESH_FENCE = (EdFenceBlock)(new EdFenceBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - 1.5, 16, 0.25, 0, 16, 16 - )).setRegistryName(new ResourceLocation(MODID, "steel_mesh_fence")); - - public static final EdDoubleGateBlock STEEL_MESH_FENCE_GATE = (EdDoubleGateBlock)(new EdDoubleGateBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,6.5, 16,16,9.5) - )).setRegistryName(new ResourceLocation(MODID, "steel_mesh_fence_gate")); - - public static final EdRailingBlock STEEL_RAILING = (EdRailingBlock)(new EdRailingBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 10f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,0, 0, 0,0), - Auxiliaries.getPixeledAABB(0,0,0, 16,15.9,1) - )).setRegistryName(new ResourceLocation(MODID, "steel_railing")); - - public static final EdCatwalkBlock STEEL_CATWALK = (EdCatwalkBlock)(new EdCatwalkBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - Auxiliaries.getPixeledAABB(0,0,0, 16, 2,16), - Auxiliaries.getPixeledAABB(0,0,0, 16,15.9, 1), - STEEL_RAILING - )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk")); - - public static final EdCatwalkTopAlignedBlock STEEL_CATWALK_TOP_ALIGNED = (EdCatwalkTopAlignedBlock)(new EdCatwalkTopAlignedBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new VoxelShape[]{ - VoxelShapes.create(Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16)), // only base - Auxiliaries.getUnionShape( // base with thick pole - Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16), - Auxiliaries.getPixeledAABB(5, 0,5, 11,15, 11) - ), - Auxiliaries.getUnionShape( // base with thin pole - Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16), - Auxiliaries.getPixeledAABB(6, 0,6, 10,15, 10) - ), - Auxiliaries.getUnionShape( // structure frame-like - Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 2,16), - Auxiliaries.getPixeledAABB( 0,14, 0, 16, 16,16), - Auxiliaries.getPixeledAABB( 0, 0, 0, 1, 16, 1), - Auxiliaries.getPixeledAABB(15, 0, 0, 16, 16, 1), - Auxiliaries.getPixeledAABB(15, 0,15, 16, 16,16), - Auxiliaries.getPixeledAABB( 0, 0,15, 1, 16,16) - ) - } - )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk_ta")); - - public static final EdCatwalkStairsBlock STEEL_CATWALK_STAIRS = (EdCatwalkStairsBlock)(new EdCatwalkStairsBlock( - DecorBlock.CFG_CUTOUT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), - new AxisAlignedBB[] { // base - Auxiliaries.getPixeledAABB( 1, 2, 8, 15, 4, 16), - Auxiliaries.getPixeledAABB( 1,10, 0, 15, 12, 8), - }, - new AxisAlignedBB[] { // railing left - Auxiliaries.getPixeledAABB(0.4, 0, 15, 0.6, 15, 16), - Auxiliaries.getPixeledAABB(0.4, 1, 14, 0.6, 16, 15), - Auxiliaries.getPixeledAABB(0.4, 2, 13, 0.6, 17, 14), - Auxiliaries.getPixeledAABB(0.4, 3, 12, 0.6, 18, 13), - Auxiliaries.getPixeledAABB(0.4, 4, 11, 0.6, 19, 12), - Auxiliaries.getPixeledAABB(0.4, 5, 10, 0.6, 20, 11), - Auxiliaries.getPixeledAABB(0.4, 6, 9, 0.6, 21, 10), - Auxiliaries.getPixeledAABB(0.4, 7, 8, 0.6, 22, 9), - Auxiliaries.getPixeledAABB(0.4, 8, 7, 0.6, 23, 8), - Auxiliaries.getPixeledAABB(0.4, 9, 6, 0.6, 24, 7), - Auxiliaries.getPixeledAABB(0.4, 10, 5, 0.6, 25, 6), - Auxiliaries.getPixeledAABB(0.4, 11, 4, 0.6, 26, 5), - Auxiliaries.getPixeledAABB(0.4, 12, 3, 0.6, 27, 4), - Auxiliaries.getPixeledAABB(0.4, 13, 2, 0.6, 28, 3), - Auxiliaries.getPixeledAABB(0.4, 14, 1, 0.6, 29, 2), - Auxiliaries.getPixeledAABB(0.4, 15, 0, 0.6, 30, 1) - } - )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk_stairs")); - - // ------------------------------------------------------------------------------------------------------------------- - - public static final EdTestBlock.TestBlock TEST_BLOCK = (EdTestBlock.TestBlock)(new EdTestBlock.TestBlock( - DecorBlock.CFG_LOOK_PLACEMENT, - AbstractBlock.Properties.of(Material.METAL, MaterialColor.METAL).strength(0f, 32000f).sound(SoundType.METAL), - Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) - )).setRegistryName(new ResourceLocation(MODID, "test_block")); - - // ------------------------------------------------------------------------------------------------------------------- - - private static final Block modBlocks[] = { - CRAFTING_TABLE, - LABELED_CRATE, - SMALL_LAB_FURNACE, - SMALL_ELECTRICAL_FURNACE, - FACTORY_HOPPER, - FACTORY_DROPPER, - FACTORY_PLACER, - SMALL_BLOCK_BREAKER, - SMALL_TREE_CUTTER, - SMALL_SOLAR_PANEL, - SMALL_WASTE_INCINERATOR, - SMALL_MINERAL_SMELTER, - SMALL_FREEZER, - SMALL_MILKING_MACHINE, - FLUID_BARREL, - STRAIGHT_CHECK_VALVE, - STRAIGHT_REDSTONE_VALVE, - STRAIGHT_REDSTONE_ANALOG_VALVE, - SMALL_FLUID_FUNNEL, - DENSE_GRIT_SAND, - DENSE_GRIT_DIRT, - CLINKER_BRICK_BLOCK, - CLINKER_BRICK_SLAB, - CLINKER_BRICK_STAIRS, - CLINKER_BRICK_WALL, - CLINKER_BRICK_SASTOR_CORNER, - CLINKER_BRICK_STAINED_BLOCK, - CLINKER_BRICK_STAINED_SLAB, - CLINKER_BRICK_STAINED_STAIRS, - CLINKER_BRICK_SASTOR_VERTICAL_SLOTTED, - CLINKER_BRICK_RECESSED, - CLINKER_BRICK_VERTICAL_SLAB_STRUCTURED, - SLAG_BRICK_BLOCK, - SLAG_BRICK_SLAB, - SLAG_BRICK_STAIRS, - SLAG_BRICK_WALL, - REBAR_CONCRETE_BLOCK, - REBAR_CONCRETE_SLAB, - REBAR_CONCRETE_STAIRS, - REBAR_CONCRETE_WALL, - REBAR_CONCRETE_TILE, - REBAR_CONCRETE_TILE_SLAB, - REBAR_CONCRETE_TILE_STAIRS, - GAS_CONCRETE_BLOCK, - GAS_CONCRETE_SLAB, - GAS_CONCRETE_STAIRS, - GAS_CONCRETE_WALL, - HALFSLAB_REBARCONCRETE, - HALFSLAB_GASCONCRETE, - HALFSLAB_TREATEDWOOD, - HALFSLAB_SHEETMETALIRON, - HALFSLAB_SHEETMETALSTEEL, - HALFSLAB_SHEETMETALCOPPER, - HALFSLAB_SHEETMETALGOLD, - HALFSLAB_SHEETMETALALUMINIUM, - PANZERGLASS_BLOCK, - PANZERGLASS_SLAB, - DARK_CERAMIC_SHINGLE_ROOF, - DARK_CERAMIC_SHINGLE_ROOF_METALIZED, - DARK_CERAMIC_SHINGLE_ROOF_SKYLIGHT, - DARK_CERAMIC_SHINGLE_ROOF_CHIMNEYTRUNK, - DARK_CERAMIC_SHINGLE_ROOF_WIRECONDUIT, - DARK_CERAMIC_SHINGLE_ROOF_BLOCK, - DARK_CERAMIC_SHINGLE_ROOF_SLAB, - HALFSLAB_DARK_CERAMIC_SHINGLE_ROOF, - DARK_CERAMIC_SHINGLE_ROOF_CHIMNEY, - METAL_RUNG_LADDER, - METAL_RUNG_STEPS, - TREATED_WOOD_LADDER, - METAL_SLIDING_DOOR, - IRON_HATCH, - OLD_INDUSTRIAL_PLANKS, - OLD_INDUSTRIAL_SLAB, - OLD_INDUSTRIAL_STAIRS, - OLD_INDUSTRIAL_SLABSLICE, - OLD_INDUSTRIAL_WOOD_DOOR, - TREATED_WOOD_TABLE, - TREATED_WOOD_STOOL, - TREATED_WOOD_SIDE_TABLE, - TREATED_WOOD_WINDOWSILL, - TREATED_WOOD_BROAD_WINDOWSILL, - TREATED_WOOD_WINDOW, - STEEL_FRAMED_WINDOW, - STEEL_TABLE, - INSET_LIGHT_IRON, - FLOOR_EDGE_LIGHT_IRON, - CEILING_EDGE_LIGHT_IRON, - BULB_LIGHT_IRON, - STEEL_FLOOR_GRATING, - STEEL_MESH_FENCE, - STEEL_MESH_FENCE_GATE, - STEEL_CATWALK, - STEEL_RAILING, - STEEL_CATWALK_TOP_ALIGNED, - STEEL_CATWALK_STAIRS, - TREATED_WOOD_POLE, - TREATED_WOOD_POLE_HEAD, - TREATED_WOOD_POLE_SUPPORT, - THIN_STEEL_POLE, - THIN_STEEL_POLE_HEAD, - THICK_STEEL_POLE, - THICK_STEEL_POLE_HEAD, - STEEL_DOUBLE_T_SUPPORT, - SIGN_HOTWIRE, - SIGN_DANGER, - SIGN_DEFENSE, - SIGN_FACTORY_AREA, - SIGN_EXIT, - SIGN_RADIOACTIVE, - SIGN_LASER, - SIGN_CAUTION, - SIGN_MAGIC_HAZARD, - SIGN_FIRE_HAZARD, - SIGN_HOT_SURFACE, - SIGN_MAGNETIC_FIELD, - SIGN_FROST_WARNING, - SIGN_MODLOGO, - }; - - private static final Block devBlocks[] = { - TEST_BLOCK - }; - - //-------------------------------------------------------------------------------------------------------------------- - // Tile entities bound exclusively to the blocks above - //-------------------------------------------------------------------------------------------------------------------- - - public static final TileEntityType TET_CRAFTING_TABLE = TileEntityType.Builder - .of(EdCraftingTable.CraftingTableTileEntity::new, CRAFTING_TABLE) - .build(null) - .setRegistryName(MODID, "te_treated_wood_crafting_table"); - - public static final TileEntityType TET_LABELED_CRATE = TileEntityType.Builder - .of(EdLabeledCrate.LabeledCrateTileEntity::new, LABELED_CRATE) - .build(null) - .setRegistryName(MODID, "te_labeled_crate"); - - public static final TileEntityType TET_SMALL_LAB_FURNACE = TileEntityType.Builder - .of(FurnaceTileEntity::new, SMALL_LAB_FURNACE) - .build(null) - .setRegistryName(MODID, "te_small_lab_furnace"); - - public static final TileEntityType TET_SMALL_ELECTRICAL_FURNACE = TileEntityType.Builder - .of(EdElectricalFurnace.ElectricalFurnaceTileEntity::new, SMALL_ELECTRICAL_FURNACE) - .build(null) - .setRegistryName(MODID, "te_small_electrical_furnace"); - - public static final TileEntityType TET_FACTORY_DROPPER = TileEntityType.Builder - .of(EdDropper.DropperTileEntity::new, FACTORY_DROPPER) - .build(null) - .setRegistryName(MODID, "te_factory_dropper"); - - public static final TileEntityType TET_FACTORY_PLACER = TileEntityType.Builder - .of(EdPlacer.PlacerTileEntity::new, FACTORY_PLACER) - .build(null) - .setRegistryName(MODID, "te_factory_placer"); - - public static final TileEntityType TET_SMALL_BLOCK_BREAKER = TileEntityType.Builder - .of(EdBreaker.BreakerTileEntity::new, SMALL_BLOCK_BREAKER) - .build(null) - .setRegistryName(MODID, "te_small_block_breaker"); - - public static final TileEntityType TET_FACTORY_HOPPER = TileEntityType.Builder - .of(EdHopper.HopperTileEntity::new, FACTORY_HOPPER) - .build(null) - .setRegistryName(MODID, "te_factory_hopper"); - - public static final TileEntityType TET_WASTE_INCINERATOR = TileEntityType.Builder - .of(EdWasteIncinerator.WasteIncineratorTileEntity::new, SMALL_WASTE_INCINERATOR) - .build(null) - .setRegistryName(MODID, "te_small_waste_incinerator"); - - public static final TileEntityType TET_STRAIGHT_PIPE_VALVE = TileEntityType.Builder - .of(EdPipeValve.PipeValveTileEntity::new, STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE) - .build(null) - .setRegistryName(MODID, "te_pipe_valve"); - - public static final TileEntityType TET_FLUID_BARREL = TileEntityType.Builder - .of(EdFluidBarrel.FluidBarrelTileEntity::new, FLUID_BARREL) - .build(null) - .setRegistryName(MODID, "te_fluid_barrel"); - - public static final TileEntityType TET_SMALL_FLUID_FUNNEL = TileEntityType.Builder - .of(EdFluidFunnel.FluidFunnelTileEntity::new, SMALL_FLUID_FUNNEL) - .build(null) - .setRegistryName(MODID, "te_small_fluid_funnel"); - - public static final TileEntityType TET_MINERAL_SMELTER = TileEntityType.Builder - .of(EdMineralSmelter.MineralSmelterTileEntity::new, SMALL_MINERAL_SMELTER) - .build(null) - .setRegistryName(MODID, "te_small_mineral_smelter"); - - public static final TileEntityType TET_FREEZER = TileEntityType.Builder - .of(EdFreezer.FreezerTileEntity::new, SMALL_FREEZER) - .build(null) - .setRegistryName(MODID, "te_small_freezer"); - - public static final TileEntityType TET_SMALL_SOLAR_PANEL = TileEntityType.Builder - .of(EdSolarPanel.SolarPanelTileEntity::new, SMALL_SOLAR_PANEL) - .build(null) - .setRegistryName(MODID, "te_small_solar_panel"); - - public static final TileEntityType TET_SMALL_MILKING_MACHINE = TileEntityType.Builder - .of(EdMilker.MilkerTileEntity::new, SMALL_MILKING_MACHINE) - .build(null) - .setRegistryName(MODID, "te_small_milking_machine"); - - public static final TileEntityType TET_SMALL_TREE_CUTTER = TileEntityType.Builder - .of(EdTreeCutter.TreeCutterTileEntity::new, SMALL_TREE_CUTTER) - .build(null) - .setRegistryName(MODID, "te_small_tree_cutter"); - - public static final TileEntityType TET_TEST_BLOCK = TileEntityType.Builder - .of(EdTestBlock.TestTileEntity::new, TEST_BLOCK) - .build(null) - .setRegistryName(MODID, "te_test_block"); - - private static final TileEntityType tile_entity_types[] = { - TET_CRAFTING_TABLE, - TET_LABELED_CRATE, - TET_SMALL_LAB_FURNACE, - TET_SMALL_ELECTRICAL_FURNACE, - TET_FACTORY_HOPPER, - TET_FACTORY_DROPPER, - TET_FACTORY_PLACER, - TET_SMALL_BLOCK_BREAKER, - TET_SMALL_TREE_CUTTER, - TET_WASTE_INCINERATOR, - TET_MINERAL_SMELTER, - TET_FREEZER, - TET_SMALL_SOLAR_PANEL, - TET_SMALL_MILKING_MACHINE, - TET_STRAIGHT_PIPE_VALVE, - TET_FLUID_BARREL, - TET_SMALL_FLUID_FUNNEL, - TET_TEST_BLOCK - }; - - //-------------------------------------------------------------------------------------------------------------------- - // Items - //-------------------------------------------------------------------------------------------------------------------- - - private static Item.Properties default_item_properties() - { return (new Item.Properties()).tab(ModEngineersDecor.ITEMGROUP); } - - public static final EdItem METAL_BAR_ITEM = (EdItem)((new EdItem(default_item_properties()).setRegistryName(MODID, "metal_bar"))); - - private static final EdItem modItems[] = { - METAL_BAR_ITEM - }; - - //-------------------------------------------------------------------------------------------------------------------- - // Entities bound exclusively to the blocks above - //-------------------------------------------------------------------------------------------------------------------- - - @SuppressWarnings("unchecked") - public static final EntityType ET_CHAIR = (EntityType)( - EntityType.Builder - .of(EdChair.EntityChair::new, EntityClassification.MISC) - .fireImmune().sized(1e-3f, 1e-3f).noSave() - .setShouldReceiveVelocityUpdates(false).setUpdateInterval(4) - .setCustomClientFactory(EdChair.EntityChair::customClientFactory) - .build(new ResourceLocation(MODID, "et_chair").toString()) - .setRegistryName(new ResourceLocation(MODID, "et_chair")) - ); - - private static final EntityType entity_types[] = { - ET_CHAIR - }; - - //-------------------------------------------------------------------------------------------------------------------- - // Container registration - //-------------------------------------------------------------------------------------------------------------------- - - public static final ContainerType CT_TREATED_WOOD_CRAFTING_TABLE; - public static final ContainerType CT_FACTORY_DROPPER; - public static final ContainerType CT_FACTORY_PLACER; - public static final ContainerType CT_FACTORY_HOPPER; - public static final ContainerType CT_SMALL_LAB_FURNACE; - public static final ContainerType CT_SMALL_ELECTRICAL_FURNACE; - public static final ContainerType CT_WASTE_INCINERATOR; - public static final ContainerType CT_LABELED_CRATE; - - static { - CT_TREATED_WOOD_CRAFTING_TABLE = (new ContainerType(EdCraftingTable.CraftingTableUiContainer::new)); - CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(MODID,"ct_treated_wood_crafting_table"); - CT_FACTORY_DROPPER = (new ContainerType(EdDropper.DropperUiContainer::new)); - CT_FACTORY_DROPPER.setRegistryName(MODID,"ct_factory_dropper"); - CT_FACTORY_PLACER = (new ContainerType(EdPlacer.PlacerContainer::new)); - CT_FACTORY_PLACER.setRegistryName(MODID,"ct_factory_placer"); - CT_FACTORY_HOPPER = (new ContainerType(EdHopper.HopperContainer::new)); - CT_FACTORY_HOPPER.setRegistryName(MODID,"ct_factory_hopper"); - CT_SMALL_LAB_FURNACE = (new ContainerType(FurnaceContainer::new)); - CT_SMALL_LAB_FURNACE.setRegistryName(MODID,"ct_small_lab_furnace"); - CT_SMALL_ELECTRICAL_FURNACE = (new ContainerType(EdElectricalFurnace.ElectricalFurnaceContainer::new)); - CT_SMALL_ELECTRICAL_FURNACE.setRegistryName(MODID,"ct_small_electrical_furnace"); - CT_WASTE_INCINERATOR = (new ContainerType(EdWasteIncinerator.WasteIncineratorContainer::new)); - CT_WASTE_INCINERATOR.setRegistryName(MODID,"ct_small_waste_incinerator"); - CT_LABELED_CRATE = (new ContainerType(EdLabeledCrate.LabeledCrateContainer::new)); - CT_LABELED_CRATE.setRegistryName(MODID,"ct_labeled_crate"); - } - - private static final ContainerType container_types[] = { - CT_TREATED_WOOD_CRAFTING_TABLE, - CT_LABELED_CRATE, - CT_FACTORY_DROPPER, - CT_FACTORY_PLACER, - CT_FACTORY_HOPPER, - CT_SMALL_LAB_FURNACE, - CT_SMALL_ELECTRICAL_FURNACE, - CT_WASTE_INCINERATOR - }; - - //-------------------------------------------------------------------------------------------------------------------- - // Initialisation events - //-------------------------------------------------------------------------------------------------------------------- - - private static ArrayList registeredBlocks = new ArrayList<>(); - - public static ArrayList allBlocks() - { - ArrayList blocks = new ArrayList<>(); - Collections.addAll(blocks, modBlocks); - Collections.addAll(blocks, devBlocks); - return blocks; - } - - @SuppressWarnings("deprecation") - public static boolean isExperimentalBlock(Block block) - { return ArrayUtils.contains(devBlocks, block) || ((block instanceof IDecorBlock) && ((((IDecorBlock)block).config() & DecorBlock.CFG_EXPERIMENTAL))!=0); } - - @Nonnull - public static List getRegisteredBlocks() - { return Collections.unmodifiableList(registeredBlocks); } - - @Nonnull - public static List getRegisteredItems() - { return new ArrayList<>(); } - - public static final void registerBlocks(final RegistryEvent.Register event) - { - boolean ie_available = Auxiliaries.isModLoaded("immersiveengineering"); - if(ie_available) { - Auxiliaries.logInfo("Immersive Engineering also installed ..."); - registeredBlocks.addAll(allBlocks()); - } else { - registeredBlocks.addAll(allBlocks().stream() - .filter(block-> - ((!(block instanceof IDecorBlock)) || ((((IDecorBlock)block).config() & DecorBlock.CFG_HARD_IE_DEPENDENT)==0)) - ) - .collect(Collectors.toList()) - ); - } - for(Block e:registeredBlocks) event.getRegistry().register(e); - Auxiliaries.logInfo("Registered " + Integer.toString(registeredBlocks.size()) + " blocks."); - } - - public static final void registerBlockItems(final RegistryEvent.Register event) - { - int n = 0; - for(Block e:registeredBlocks) { - ResourceLocation rl = e.getRegistryName(); - if(rl == null) continue; - if(e instanceof StandardBlocks.IBlockItemFactory) { - event.getRegistry().register(((StandardBlocks.IBlockItemFactory)e).getBlockItem(e, (new Item.Properties().tab(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl)); - } else { - event.getRegistry().register(new BlockItem(e, (new Item.Properties().tab(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl)); - } - ++n; - } - } - - public static final void registerItems(final RegistryEvent.Register event) - { for(Item e:modItems) event.getRegistry().register(e); } - - public static final void registerTileEntities(final RegistryEvent.Register> event) - { - int n_registered = 0; - for(final TileEntityType e:tile_entity_types) { - event.getRegistry().register(e); - ++n_registered; - } - Auxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " tile entities."); - } - - public static final void registerEntities(final RegistryEvent.Register> event) - { - int n_registered = 0; - for(final EntityType e:entity_types) { - if((e==ET_CHAIR) && (!registeredBlocks.contains(TREATED_WOOD_STOOL))) continue; - event.getRegistry().register(e); - ++n_registered; - } - Auxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " entities bound to blocks."); - } - - public static final void registerContainers(final RegistryEvent.Register> event) - { - int n_registered = 0; - for(final ContainerType e:container_types) { - event.getRegistry().register(e); - ++n_registered; - } - Auxiliaries.logInfo("Registered " + Integer.toString(n_registered) + " containers bound to tile entities."); - } - - @OnlyIn(Dist.CLIENT) - public static final void registerContainerGuis(final FMLClientSetupEvent event) - { - ScreenManager.register(CT_TREATED_WOOD_CRAFTING_TABLE, EdCraftingTable.CraftingTableGui::new); - ScreenManager.register(CT_LABELED_CRATE, EdLabeledCrate.LabeledCrateGui::new); - ScreenManager.register(CT_FACTORY_DROPPER, EdDropper.DropperGui::new); - ScreenManager.register(CT_FACTORY_PLACER, EdPlacer.PlacerGui::new); - ScreenManager.register(CT_FACTORY_HOPPER, EdHopper.HopperGui::new); - ScreenManager.register(CT_SMALL_LAB_FURNACE, FurnaceGui::new); - ScreenManager.register(CT_SMALL_ELECTRICAL_FURNACE, EdElectricalFurnace.ElectricalFurnaceGui::new); - ScreenManager.register(CT_WASTE_INCINERATOR, EdWasteIncinerator.WasteIncineratorGui::new); - } - - @OnlyIn(Dist.CLIENT) - @SuppressWarnings("unchecked") - public static final void registerTileEntityRenderers(final FMLClientSetupEvent event) - { - ClientRegistry.bindTileEntityRenderer( - (TileEntityType)TET_CRAFTING_TABLE, - wile.engineersdecor.detail.ModRenderers.CraftingTableTer::new - ); - ClientRegistry.bindTileEntityRenderer( - (TileEntityType)TET_LABELED_CRATE, - wile.engineersdecor.detail.ModRenderers.DecorLabeledCrateTer::new - ); - } - - @OnlyIn(Dist.CLIENT) - public static final void processContentClientSide(final FMLClientSetupEvent event) - { - // Block renderer selection - for(Block block: getRegisteredBlocks()) { - if(block instanceof IStandardBlock) { - switch(((IStandardBlock)block).getRenderTypeHint()) { - case CUTOUT: - RenderTypeLookup.setRenderLayer(block, RenderType.cutout()); - break; - case CUTOUT_MIPPED: - RenderTypeLookup.setRenderLayer(block, RenderType.cutoutMipped()); - break; - case TRANSLUCENT: - RenderTypeLookup.setRenderLayer(block, RenderType.translucent()); - break; - case TRANSLUCENT_NO_CRUMBLING: - RenderTypeLookup.setRenderLayer(block, RenderType.translucentNoCrumbling()); - break; - case SOLID: - break; - } - } - } - // Entity renderers - RenderingRegistry.registerEntityRenderingHandler(ET_CHAIR, - manager->(new wile.engineersdecor.detail.ModRenderers.InvisibleEntityRenderer(manager)) - ); - } - -} +/* + * @file ModContent.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Definition and initialisation of blocks of this + * module, along with their tile entities if applicable. + * + * Note: Straight forward definition of different blocks/entities + * to make recipes, models and texture definitions easier. + */ +package wile.engineersdecor; + +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; +import net.minecraft.client.renderer.entity.EntityRenderers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.MobCategory; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.MaterialColor; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.shapes.BooleanOp; +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; +import net.minecraftforge.common.ToolType; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import org.apache.commons.lang3.ArrayUtils; +import wile.engineersdecor.blocks.*; +import wile.engineersdecor.detail.ModRenderers; +import wile.engineersdecor.items.EdItem; +import wile.engineersdecor.libmc.blocks.*; +import wile.engineersdecor.libmc.blocks.StandardBlocks.IStandardBlock; +import wile.engineersdecor.libmc.detail.Auxiliaries; + +import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + + +@SuppressWarnings("unused") +public class ModContent +{ + private static final String MODID = ModEngineersDecor.MODID; + + //-------------------------------------------------------------------------------------------------------------------- + + private static Boolean disallowSpawn(BlockState state, BlockGetter reader, BlockPos pos, EntityType entity) { return false; } + + //-------------------------------------------------------------------------------------------------------------------- + // Registry auxiliary functions. + //-------------------------------------------------------------------------------------------------------------------- + + private static class ModRegistry + { + private static BlockEntityType register(String name, BlockEntityType.BlockEntitySupplier ctor, Block... blocks) + { + final BlockEntityType tet = BlockEntityType.Builder.of(ctor, blocks).build(null); + tet.setRegistryName(MODID, name); + return tet; + } + + @SuppressWarnings("unchecked") + private static EntityType register(String name, EntityType.Builder builder) + { + final EntityType et = (EntityType)builder.build(new ResourceLocation(MODID, name).toString()); + et.setRegistryName(MODID, name); + return et; + } + } + + + //-------------------------------------------------------------------------------------------------------------------- + // Blocks + //-------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock CLINKER_BRICK_BLOCK = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_block")); + + public static final VariantSlabBlock CLINKER_BRICK_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_slab")); + + public static final StandardStairsBlock CLINKER_BRICK_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + CLINKER_BRICK_BLOCK.defaultBlockState(), + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stairs")); + + public static final EdWallBlock CLINKER_BRICK_WALL = (EdWallBlock)(new EdWallBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_wall")); + + public static final StandardBlocks.BaseBlock CLINKER_BRICK_STAINED_BLOCK = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_block")); + + public static final VariantSlabBlock CLINKER_BRICK_STAINED_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_slab")); + + public static final StandardStairsBlock CLINKER_BRICK_STAINED_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + CLINKER_BRICK_BLOCK.defaultBlockState(), + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_stained_stairs")); + + public static final EdCornerOrnamentedBlock CLINKER_BRICK_SASTOR_CORNER = (EdCornerOrnamentedBlock)(new EdCornerOrnamentedBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), + new Block[]{CLINKER_BRICK_BLOCK, CLINKER_BRICK_STAINED_BLOCK, CLINKER_BRICK_SLAB, CLINKER_BRICK_STAIRS, CLINKER_BRICK_STAINED_SLAB, CLINKER_BRICK_STAINED_STAIRS} + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_sastor_corner_block")); + + public static final StandardBlocks.HorizontalWaterLoggable CLINKER_BRICK_RECESSED = (StandardBlocks.HorizontalWaterLoggable)(new StandardBlocks.HorizontalWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), + new AABB[] { + Auxiliaries.getPixeledAABB( 3,0, 0, 13,16, 1), + Auxiliaries.getPixeledAABB( 0,0, 1, 16,16,11), + Auxiliaries.getPixeledAABB( 4,0,11, 12,16,13) + } + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_recessed")); + + public static final StandardBlocks.HorizontalWaterLoggable CLINKER_BRICK_SASTOR_VERTICAL_SLOTTED = (StandardBlocks.HorizontalWaterLoggable)(new StandardBlocks.HorizontalWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), + new AABB[] { + Auxiliaries.getPixeledAABB( 3,0, 0, 13,16, 1), + Auxiliaries.getPixeledAABB( 3,0,15, 13,16,16), + Auxiliaries.getPixeledAABB( 0,0, 1, 16,16,15) + } + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_vertically_slit")); + + public static final StandardBlocks.HorizontalWaterLoggable CLINKER_BRICK_VERTICAL_SLAB_STRUCTURED = (StandardBlocks.HorizontalWaterLoggable)(new StandardBlocks.HorizontalWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE), + new AABB[] { + Auxiliaries.getPixeledAABB( 0,0, 0, 16,16, 8), + } + )).setRegistryName(new ResourceLocation(MODID, "clinker_brick_vertical_slab_structured")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock SLAG_BRICK_BLOCK = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "slag_brick_block")); + + public static final VariantSlabBlock SLAG_BRICK_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "slag_brick_slab")); + + public static final StandardStairsBlock SLAG_BRICK_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + SLAG_BRICK_BLOCK.defaultBlockState(), + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "slag_brick_stairs")); + + public static final EdWallBlock SLAG_BRICK_WALL = (EdWallBlock)(new EdWallBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(3f, 10f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "slag_brick_wall")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock REBAR_CONCRETE_BLOCK = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete")); + + public static final VariantSlabBlock REBAR_CONCRETE_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_slab")); + + public static final StandardStairsBlock REBAR_CONCRETE_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + REBAR_CONCRETE_BLOCK.defaultBlockState(), + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_stairs")); + + public static final EdWallBlock REBAR_CONCRETE_WALL = (EdWallBlock)(new EdWallBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_wall")); + + public static final SlabSliceBlock HALFSLAB_REBARCONCRETE = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "halfslab_rebar_concrete")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock REBAR_CONCRETE_TILE = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile")); + + public static final VariantSlabBlock REBAR_CONCRETE_TILE_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile_slab")); + + public static final StandardStairsBlock REBAR_CONCRETE_TILE_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + REBAR_CONCRETE_TILE.defaultBlockState(), + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 2000f).sound(SoundType.STONE).isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "rebar_concrete_tile_stairs")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdGlassBlock PANZERGLASS_BLOCK = (EdGlassBlock)(new EdGlassBlock( + DecorBlock.CFG_TRANSLUCENT, + BlockBehaviour.Properties.of(Material.GLASS, MaterialColor.NONE).strength(0.7f, 2000f).sound(SoundType.METAL).noOcclusion().isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "panzerglass_block")); + + public static final VariantSlabBlock PANZERGLASS_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_TRANSLUCENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(0.7f, 2000f).sound(SoundType.METAL).noOcclusion().isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "panzerglass_slab")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF = (EdRoofBlock)(new EdRoofBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof")); + + public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF_METALIZED = (EdRoofBlock)(new EdRoofBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_metallized")); + + public static final EdRoofBlock DARK_CERAMIC_SHINGLE_ROOF_SKYLIGHT = (EdRoofBlock)(new EdRoofBlock( + DecorBlock.CFG_TRANSLUCENT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_skylight")); + + public static final EdChimneyTrunkBlock DARK_CERAMIC_SHINGLE_ROOF_CHIMNEYTRUNK = (EdChimneyTrunkBlock)(new EdChimneyTrunkBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn), + Shapes.create(Auxiliaries.getPixeledAABB(3, 0, 3, 13, 16, 13)), + Shapes.create(Auxiliaries.getPixeledAABB(5, 0, 5, 11, 16, 11)) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_chimneytrunk")); + + public static final EdChimneyTrunkBlock DARK_CERAMIC_SHINGLE_ROOF_WIRECONDUIT = (EdChimneyTrunkBlock)(new EdChimneyTrunkBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE).noOcclusion().dynamicShape().isValidSpawn(ModContent::disallowSpawn), + Shapes.join( + Shapes.create(Auxiliaries.getPixeledAABB(3, 0, 3, 13, 13, 13)), + Shapes.create(Auxiliaries.getPixeledAABB(5, 13, 5, 11, 16, 11)), + BooleanOp.OR + ), + Shapes.join( + Shapes.create(Auxiliaries.getPixeledAABB(5, 0, 5, 11, 15, 11)), + Shapes.create(Auxiliaries.getPixeledAABB(7, 15, 7, 9, 16, 9)), + BooleanOp.OR + ) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_wireconduit")); + + public static final EdChimneyBlock DARK_CERAMIC_SHINGLE_ROOF_CHIMNEY = (EdChimneyBlock)(new EdChimneyBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(5f, 6f).sound(SoundType.STONE).dynamicShape().isValidSpawn(ModContent::disallowSpawn), + Auxiliaries.getPixeledAABB(3, 0, 3, 13, 6, 13) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_chimney")); + + public static final StandardBlocks.BaseBlock DARK_CERAMIC_SHINGLE_ROOF_BLOCK = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_block")); + + public static final VariantSlabBlock DARK_CERAMIC_SHINGLE_ROOF_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 6f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_slab")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock DENSE_GRIT_SAND = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.DIRT, MaterialColor.DIRT).strength(0.5f, 3f).sound(SoundType.GRAVEL).harvestTool(ToolType.SHOVEL) + )).setRegistryName(new ResourceLocation(MODID, "dense_grit_sand_block")); + + public static final StandardBlocks.BaseBlock DENSE_GRIT_DIRT = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.DIRT, MaterialColor.DIRT).strength(0.5f, 3f).sound(SoundType.GRAVEL).harvestTool(ToolType.SHOVEL) + )).setRegistryName(new ResourceLocation(MODID, "dense_grit_dirt_block")); + + public static final SlabSliceBlock HALFSLAB_DARK_CERAMIC_SHINGLE_ROOF = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.STONE, MaterialColor.STONE).strength(2f, 15f).sound(SoundType.STONE) + )).setRegistryName(new ResourceLocation(MODID, "dark_shingle_roof_slabslice")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdLadderBlock METAL_RUNG_LADDER = (EdLadderBlock)(new EdLadderBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.0f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "metal_rung_ladder")); + + public static final EdLadderBlock METAL_RUNG_STEPS = (EdLadderBlock)(new EdLadderBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.0f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "metal_rung_steps")); + + public static final EdLadderBlock TREATED_WOOD_LADDER = (EdLadderBlock)(new EdLadderBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.0f, 8f).sound(SoundType.WOOD).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_ladder")); + + public static final EdHatchBlock IRON_HATCH = (EdHatchBlock)(new EdHatchBlock( + DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 2000f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0.5,1,0, 15.5,3,14), + Auxiliaries.getPixeledAABB(0.5,1,0, 15.5,14.,2) + )).setRegistryName(new ResourceLocation(MODID, "iron_hatch")); + + public static final StandardDoorBlock METAL_SLIDING_DOOR = (StandardDoorBlock)(new StandardDoorBlock( + DecorBlock.CFG_TRANSLUCENT|DecorBlock.CFG_HORIZIONTAL, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1.5f, 8f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(15, 0.0,6, 16,16.0,10), + Auxiliaries.getPixeledAABB( 0,15.5,6, 16,16.0,10), + }, + new AABB[]{ + Auxiliaries.getPixeledAABB(15, 0.0,6, 16,16.0,10), + Auxiliaries.getPixeledAABB( 0, 0.0,6, 16, 0.3,10), + }, + new AABB[]{ + Auxiliaries.getPixeledAABB( 0,0,7, 16,16,9) + }, + new AABB[]{ + Auxiliaries.getPixeledAABB( 0,0,7, 16,16,9) + }, + SoundEvents.IRON_DOOR_OPEN, SoundEvents.IRON_DOOR_CLOSE + )).setRegistryName(new ResourceLocation(MODID, "metal_sliding_door")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.BaseBlock OLD_INDUSTRIAL_PLANKS = (StandardBlocks.BaseBlock)(new StandardBlocks.BaseBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) + )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_planks")); + + public static final VariantSlabBlock OLD_INDUSTRIAL_SLAB = (VariantSlabBlock)(new VariantSlabBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) + )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_slab")); + + public static final StandardStairsBlock OLD_INDUSTRIAL_STAIRS = (StandardStairsBlock)(new StandardStairsBlock( + DecorBlock.CFG_DEFAULT, + OLD_INDUSTRIAL_PLANKS.defaultBlockState(), + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD) + )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_stairs")); + + public static final SlabSliceBlock OLD_INDUSTRIAL_SLABSLICE = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_slabslice")); + + public static final StandardDoorBlock OLD_INDUSTRIAL_WOOD_DOOR = (StandardDoorBlock)(new StandardDoorBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1.5f, 6f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(15,0, 0, 16,16,16), + Auxiliaries.getPixeledAABB( 0,0,13, 16,16,16), + SoundEvents.WOODEN_DOOR_OPEN, SoundEvents.WOODEN_DOOR_CLOSE + )).setRegistryName(new ResourceLocation(MODID, "old_industrial_wood_door")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.WaterLoggable TREATED_WOOD_TABLE = (StandardBlocks.WaterLoggable)(new StandardBlocks.WaterLoggable( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(1,0,1, 15,15.9,15) + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_table")); + + public static final EdChair.ChairBlock TREATED_WOOD_STOOL = (EdChair.ChairBlock)(new EdChair.ChairBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(4,7,4, 12,8.8,12), + Auxiliaries.getPixeledAABB(7,0,7, 9,7,9), + Auxiliaries.getPixeledAABB(4,0,7, 12,1,9), + Auxiliaries.getPixeledAABB(7,0,4, 9,1,12), + } + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_stool")); + + public static final StandardBlocks.DirectedWaterLoggable TREATED_WOOD_WINDOWSILL = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(0.5,15,10.5, 15.5,16,16) + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_windowsill")); + + public static final StandardBlocks.DirectedWaterLoggable TREATED_WOOD_BROAD_WINDOWSILL = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_FACING_PLACEMENT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(0,14.5,4, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_broad_windowsill")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.DirectedWaterLoggable INSET_LIGHT_IRON = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), + Auxiliaries.getPixeledAABB(5.2,5.2,0, 10.8,10.8,0.3) + )).setRegistryName(new ResourceLocation(MODID, "iron_inset_light")); + + public static final StandardBlocks.DirectedWaterLoggable FLOOR_EDGE_LIGHT_IRON = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), + Auxiliaries.getPixeledAABB(5,0,0, 11,2,0.5) + )).setRegistryName(new ResourceLocation(MODID, "iron_floor_edge_light")); + + public static final StandardBlocks.DirectedWaterLoggable CEILING_EDGE_LIGHT_IRON = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB( 0,15.5,0, 16,16,2.0), + Auxiliaries.getPixeledAABB( 0,14.0,0, 16,16,0.5), + Auxiliaries.getPixeledAABB( 0,14.0,0, 1,16,2.0), + Auxiliaries.getPixeledAABB(15,14.0,0, 16,16,2.0), + } + )).setRegistryName(new ResourceLocation(MODID, "iron_ceiling_edge_light")); + + public static final StandardBlocks.DirectedWaterLoggable BULB_LIGHT_IRON = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).lightLevel((state)->15).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(6.5,6.5,1, 9.5,9.5,4), + Auxiliaries.getPixeledAABB(6.0,6.0,0, 10.0,10.0,1.0) + } + )).setRegistryName(new ResourceLocation(MODID, "iron_bulb_light")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.WaterLoggable STEEL_TABLE = (StandardBlocks.WaterLoggable)(new StandardBlocks.WaterLoggable( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "steel_table")); + + public static final EdFloorGratingBlock STEEL_FLOOR_GRATING = (EdFloorGratingBlock)(new EdFloorGratingBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,14,0, 16,15.5,16) + )).setRegistryName(new ResourceLocation(MODID, "steel_floor_grating")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdWindowBlock TREATED_WOOD_WINDOW = (EdWindowBlock)(new EdWindowBlock( + DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 8f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,7, 16,16,9) + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_window")); + + public static final EdWindowBlock STEEL_FRAMED_WINDOW = (EdWindowBlock)(new EdWindowBlock( + DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,7.5, 16,16,8.5) + )).setRegistryName(new ResourceLocation(MODID, "steel_framed_window")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdStraightPoleBlock TREATED_WOOD_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), + null + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole")); + + public static final EdStraightPoleBlock TREATED_WOOD_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), + TREATED_WOOD_POLE + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole_head")); + + public static final EdStraightPoleBlock TREATED_WOOD_POLE_SUPPORT = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(2f, 5f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(5.8,5.8,0, 10.2,10.2,16), + TREATED_WOOD_POLE + )).setRegistryName(new ResourceLocation(MODID, "treated_wood_pole_support")); + + public static final EdStraightPoleBlock THIN_STEEL_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(6,6,0, 10,10,16), + null + )).setRegistryName(new ResourceLocation(MODID, "thin_steel_pole")); + + public static final EdStraightPoleBlock THIN_STEEL_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(6,6,0, 10,10,16), + THIN_STEEL_POLE + )).setRegistryName(new ResourceLocation(MODID, "thin_steel_pole_head")); + + public static final EdStraightPoleBlock THICK_STEEL_POLE = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(5,5,0, 11,11,16), + null + )).setRegistryName(new ResourceLocation(MODID, "thick_steel_pole")); + + public static final EdStraightPoleBlock THICK_STEEL_POLE_HEAD = (EdStraightPoleBlock)(new EdStraightPoleBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_IF_SAME, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(5,5,0, 11,11,16), + THICK_STEEL_POLE + )).setRegistryName(new ResourceLocation(MODID, "thick_steel_pole_head")); + + public static final EdHorizontalSupportBlock STEEL_DOUBLE_T_SUPPORT = (EdHorizontalSupportBlock)(new EdHorizontalSupportBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 11f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB( 5,11,0, 11,16,16), // main beam + Auxiliaries.getPixeledAABB(10,11,5, 16,16,11), // east beam (also for west 180deg) + Auxiliaries.getPixeledAABB( 6, 0,6, 10,16,10), // down thin + Auxiliaries.getPixeledAABB( 5, 0,5, 11,16,11) // down thick + )).setRegistryName(new ResourceLocation(MODID, "steel_double_t_support")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final StandardBlocks.DirectedWaterLoggable SIGN_MODLOGO = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1000f).sound(SoundType.WOOD).lightLevel((state)->1).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,15.6, 16,16,16.0) + )).setRegistryName(new ResourceLocation(MODID, "sign_decor")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_HOTWIRE = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_hotwire")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_DANGER = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_danger")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_DEFENSE = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_defense")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_FACTORY_AREA = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_factoryarea")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_EXIT = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(3,7,15.6, 13,13,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_exit")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_RADIOACTIVE = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_radioactive")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_LASER = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_laser")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_CAUTION = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_caution")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_MAGIC_HAZARD = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_magichazard")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_FIRE_HAZARD = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_firehazard")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_HOT_SURFACE = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_hotsurface")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_MAGNETIC_FIELD = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_magneticfield")); + + public static final StandardBlocks.DirectedWaterLoggable SIGN_FROST_WARNING = (StandardBlocks.DirectedWaterLoggable)(new StandardBlocks.DirectedWaterLoggable( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_AI_PASSABLE, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 1f).sound(SoundType.WOOD).noOcclusion(), + Auxiliaries.getPixeledAABB(2,2,15.6, 14,14,16) + )).setRegistryName(new ResourceLocation(MODID, "sign_frost")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdCraftingTable.CraftingTableBlock CRAFTING_TABLE = (EdCraftingTable.CraftingTableBlock)(new EdCraftingTable.CraftingTableBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 12f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(0,15,0, 16,16,16), + Auxiliaries.getPixeledAABB(1, 0,1, 15,16,15) + } + )).setRegistryName(new ResourceLocation(MODID, "metal_crafting_table")); + + public static final EdFurnace.FurnaceBlock SMALL_LAB_FURNACE = (EdFurnace.FurnaceBlock)(new EdFurnace.FurnaceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 12f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(1,0,1, 15, 1,15), + Auxiliaries.getPixeledAABB(0,1,1, 16,16,16), + } + )).setRegistryName(new ResourceLocation(MODID, "small_lab_furnace")); + + public static final EdElectricalFurnace.ElectricalFurnaceBlock SMALL_ELECTRICAL_FURNACE = (EdElectricalFurnace.ElectricalFurnaceBlock)(new EdElectricalFurnace.ElectricalFurnaceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(0, 0,0, 16,11,16), + Auxiliaries.getPixeledAABB(1,11,0, 15,12,16), + Auxiliaries.getPixeledAABB(2,12,0, 14,13,16), + Auxiliaries.getPixeledAABB(3,13,0, 13,14,16), + Auxiliaries.getPixeledAABB(4,14,0, 12,16,16), + } + )).setRegistryName(new ResourceLocation(MODID, "small_electrical_furnace")); + + public static final EdDropper.DropperBlock FACTORY_DROPPER = (EdDropper.DropperBlock)(new EdDropper.DropperBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,1, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "factory_dropper")); + + public static final EdPlacer.PlacerBlock FACTORY_PLACER = (EdPlacer.PlacerBlock)(new EdPlacer.PlacerBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(0,0,2, 16,16,16), + Auxiliaries.getPixeledAABB( 0,0,0, 1,16, 2), + Auxiliaries.getPixeledAABB(15,0,0,16,16, 2) + } + )).setRegistryName(new ResourceLocation(MODID, "factory_placer")); + + public static final EdBreaker.BreakerBlock SMALL_BLOCK_BREAKER = (EdBreaker.BreakerBlock)(new EdBreaker.BreakerBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(1,0,0, 15, 4, 7), + Auxiliaries.getPixeledAABB(1,0,7, 15,12,16), + Auxiliaries.getPixeledAABB(0,0,0, 1, 5, 4), + Auxiliaries.getPixeledAABB(0,0,4, 1,12,16), + Auxiliaries.getPixeledAABB(15,0,0, 16, 5, 4), + Auxiliaries.getPixeledAABB(15,0,4, 16,12,16) + } + )).setRegistryName(new ResourceLocation(MODID, "small_block_breaker")); + + public static final EdHopper.HopperBlock FACTORY_HOPPER = (EdHopper.HopperBlock)(new EdHopper.HopperBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(),()->{ + final AABB[] down_aabbs = new AABB[]{ + Auxiliaries.getPixeledAABB( 5, 0, 5, 11, 1,11), + Auxiliaries.getPixeledAABB( 4, 1, 4, 12, 7,12), + Auxiliaries.getPixeledAABB( 2, 7, 2, 14,10,14), + Auxiliaries.getPixeledAABB( 0,10, 0, 16,16,16), + Auxiliaries.getPixeledAABB( 0, 4, 5, 2,10,11), + Auxiliaries.getPixeledAABB(14, 4, 5, 16,10,11), + Auxiliaries.getPixeledAABB( 5, 4, 0, 11,10, 2), + Auxiliaries.getPixeledAABB( 5, 4,14, 11,10,16), + }; + final AABB[] up_aabbs = new AABB[]{ + Auxiliaries.getPixeledAABB( 5,15, 5, 11,16,11), + Auxiliaries.getPixeledAABB( 4,14, 4, 12, 9,12), + Auxiliaries.getPixeledAABB( 2, 9, 2, 14, 6,14), + Auxiliaries.getPixeledAABB( 0, 6, 0, 16, 0,16), + Auxiliaries.getPixeledAABB( 0,12, 5, 2, 6,11), + Auxiliaries.getPixeledAABB(14,12, 5, 16, 6,11), + Auxiliaries.getPixeledAABB( 5,12, 0, 11, 6, 2), + Auxiliaries.getPixeledAABB( 5,12,14, 11, 6,16), + }; + final AABB[] north_aabbs = new AABB[]{ + Auxiliaries.getPixeledAABB( 5, 0, 5, 11, 1,11), + Auxiliaries.getPixeledAABB( 4, 1, 4, 12, 7,12), + Auxiliaries.getPixeledAABB( 2, 7, 2, 14,10,14), + Auxiliaries.getPixeledAABB( 0,10, 0, 16,16,16), + Auxiliaries.getPixeledAABB( 0, 4, 5, 2,10,11), + Auxiliaries.getPixeledAABB(14, 4, 5, 16,10,11), + Auxiliaries.getPixeledAABB( 5, 1, 0, 11, 7, 4), + Auxiliaries.getPixeledAABB( 5, 4,14, 11,10,16), + }; + return new ArrayList<>(Arrays.asList( + Auxiliaries.getUnionShape(down_aabbs), + Auxiliaries.getUnionShape(up_aabbs), + Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.NORTH, false)), + Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.SOUTH, false)), + Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.WEST, false)), + Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(north_aabbs, Direction.EAST, false)), + Shapes.block(), + Shapes.block() + )); + } + )).setRegistryName(new ResourceLocation(MODID, "factory_hopper")); + + public static final EdWasteIncinerator.WasteIncineratorBlock SMALL_WASTE_INCINERATOR = (EdWasteIncinerator.WasteIncineratorBlock)(new EdWasteIncinerator.WasteIncineratorBlock( + DecorBlock.CFG_DEFAULT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL), + Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "small_waste_incinerator")); + + public static final EdMineralSmelter.MineralSmelterBlock SMALL_MINERAL_SMELTER = (EdMineralSmelter.MineralSmelterBlock)(new EdMineralSmelter.MineralSmelterBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9) + )).setRegistryName(new ResourceLocation(MODID, "small_mineral_smelter")); + + public static final EdFreezer.FreezerBlock SMALL_FREEZER = (EdFreezer.FreezerBlock)(new EdFreezer.FreezerBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 12f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(1.1,0,1.1, 14.9,16,14.9) + )).setRegistryName(new ResourceLocation(MODID, "small_freezer")); + + public static final EdSolarPanel.SolarPanelBlock SMALL_SOLAR_PANEL = (EdSolarPanel.SolarPanelBlock)(new EdSolarPanel.SolarPanelBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(0,0,0, 16,2,16), + Auxiliaries.getPixeledAABB(6,1.5,3, 10,10.5,13), + } + )).setRegistryName(new ResourceLocation(MODID, "small_solar_panel")); + + public static final EdMilker.MilkerBlock SMALL_MILKING_MACHINE = (EdMilker.MilkerBlock)(new EdMilker.MilkerBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB( 1, 1,0, 15,14,10), + Auxiliaries.getPixeledAABB( 0,14,0, 16,16,13), + Auxiliaries.getPixeledAABB( 0, 0,0, 16, 1,13), + Auxiliaries.getPixeledAABB( 0, 1,1, 1,14,11), + Auxiliaries.getPixeledAABB(15, 1,1, 16,14,11) + } + )).setRegistryName(new ResourceLocation(MODID, "small_milking_machine")); + + public static final EdTreeCutter.TreeCutterBlock SMALL_TREE_CUTTER = (EdTreeCutter.TreeCutterBlock)(new EdTreeCutter.TreeCutterBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB( 0,0, 0, 16,3,16), + Auxiliaries.getPixeledAABB( 0,3, 0, 3,8,16), + Auxiliaries.getPixeledAABB( 3,7, 0, 5,8,16), + Auxiliaries.getPixeledAABB(15,0, 0, 16,6,16), + Auxiliaries.getPixeledAABB( 0,0,13, 16,8,16), + Auxiliaries.getPixeledAABB( 5,6,12, 16,8,13), + } + )).setRegistryName(new ResourceLocation(MODID, "small_tree_cutter")); + + public static final EdPipeValve.PipeValveBlock STRAIGHT_CHECK_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT|DecorBlock.CFG_FLIP_PLACEMENT_SHIFTCLICK, + EdPipeValve.CFG_CHECK_VALVE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), + Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), + Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), + Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), + } + )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve")); + + public static final EdPipeValve.PipeValveBlock STRAIGHT_REDSTONE_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + EdPipeValve.CFG_REDSTONE_CONTROLLED_VALVE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), + Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), + Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), + Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), + } + )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve_redstone")); + + public static final EdPipeValve.PipeValveBlock STRAIGHT_REDSTONE_ANALOG_VALVE = (EdPipeValve.PipeValveBlock)(new EdPipeValve.PipeValveBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_FACING_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + EdPipeValve.CFG_REDSTONE_CONTROLLED_VALVE|EdPipeValve.CFG_ANALOG_VALVE, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 8f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(2,2, 0, 14,14, 2), + Auxiliaries.getPixeledAABB(2,2,14, 14,14,16), + Auxiliaries.getPixeledAABB(3,3, 5, 13,13,11), + Auxiliaries.getPixeledAABB(4,4, 2, 12,12,14), + } + )).setRegistryName(new ResourceLocation(MODID, "straight_pipe_valve_redstone_analog")); + + public static final EdFluidBarrel.FluidBarrelBlock FLUID_BARREL = (EdFluidBarrel.FluidBarrelBlock)(new EdFluidBarrel.FluidBarrelBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(2, 0,0, 14, 1,16), + Auxiliaries.getPixeledAABB(1, 1,0, 15, 2,16), + Auxiliaries.getPixeledAABB(0, 2,0, 16,14,16), + Auxiliaries.getPixeledAABB(1,14,0, 15,15,16), + Auxiliaries.getPixeledAABB(2,15,0, 14,16,16), + } + )).setRegistryName(new ResourceLocation(MODID, "fluid_barrel")); + + public static final EdFluidFunnel.FluidFunnelBlock SMALL_FLUID_FUNNEL = (EdFluidFunnel.FluidFunnelBlock)(new EdFluidFunnel.FluidFunnelBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[]{ + Auxiliaries.getPixeledAABB(0, 0,0, 16,14,16), + Auxiliaries.getPixeledAABB(1,14,1, 15,15,15), + Auxiliaries.getPixeledAABB(0,15,0, 16,16,16) + } + )).setRegistryName(new ResourceLocation(MODID, "small_fluid_funnel")); + + public static final EdLabeledCrate.LabeledCrateBlock LABELED_CRATE = (EdLabeledCrate.LabeledCrateBlock)(new EdLabeledCrate.LabeledCrateBlock( + DecorBlock.CFG_HORIZIONTAL|DecorBlock.CFG_LOOK_PLACEMENT|DecorBlock.CFG_OPPOSITE_PLACEMENT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(0.5f, 32f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "labeled_crate")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final SlabSliceBlock HALFSLAB_TREATEDWOOD = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.WOOD, MaterialColor.WOOD).strength(1f, 4f).sound(SoundType.WOOD).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_treated_wood")); + + public static final SlabSliceBlock HALFSLAB_SHEETMETALIRON = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_iron")); + + public static final SlabSliceBlock HALFSLAB_SHEETMETALSTEEL = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_steel")); + + public static final SlabSliceBlock HALFSLAB_SHEETMETALCOPPER = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_copper")); + + public static final SlabSliceBlock HALFSLAB_SHEETMETALGOLD = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_gold")); + + public static final SlabSliceBlock HALFSLAB_SHEETMETALALUMINIUM = (SlabSliceBlock)(new SlabSliceBlock( + DecorBlock.CFG_CUTOUT|DecorBlock.CFG_HARD_IE_DEPENDENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 8f).sound(SoundType.METAL).noOcclusion() + )).setRegistryName(new ResourceLocation(MODID, "halfslab_sheetmetal_aluminum")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdFenceBlock STEEL_MESH_FENCE = (EdFenceBlock)(new EdFenceBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + 1.5, 16, 0.25, 0, 16, 16 + )).setRegistryName(new ResourceLocation(MODID, "steel_mesh_fence")); + + public static final EdDoubleGateBlock STEEL_MESH_FENCE_GATE = (EdDoubleGateBlock)(new EdDoubleGateBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,6.5, 16,16,9.5) + )).setRegistryName(new ResourceLocation(MODID, "steel_mesh_fence_gate")); + + public static final EdRailingBlock STEEL_RAILING = (EdRailingBlock)(new EdRailingBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(1f, 10f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,0, 0, 0,0), + Auxiliaries.getPixeledAABB(0,0,0, 16,15.9,1) + )).setRegistryName(new ResourceLocation(MODID, "steel_railing")); + + public static final EdCatwalkBlock STEEL_CATWALK = (EdCatwalkBlock)(new EdCatwalkBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + Auxiliaries.getPixeledAABB(0,0,0, 16, 2,16), + Auxiliaries.getPixeledAABB(0,0,0, 16,15.9, 1), + STEEL_RAILING + )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk")); + + public static final EdCatwalkTopAlignedBlock STEEL_CATWALK_TOP_ALIGNED = (EdCatwalkTopAlignedBlock)(new EdCatwalkTopAlignedBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new VoxelShape[]{ + Shapes.create(Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16)), // only base + Auxiliaries.getUnionShape( // base with thick pole + Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16), + Auxiliaries.getPixeledAABB(5, 0,5, 11,15, 11) + ), + Auxiliaries.getUnionShape( // base with thin pole + Auxiliaries.getPixeledAABB(0,14,0, 16, 16,16), + Auxiliaries.getPixeledAABB(6, 0,6, 10,15, 10) + ), + Auxiliaries.getUnionShape( // structure frame-like + Auxiliaries.getPixeledAABB( 0, 0, 0, 16, 2,16), + Auxiliaries.getPixeledAABB( 0,14, 0, 16, 16,16), + Auxiliaries.getPixeledAABB( 0, 0, 0, 1, 16, 1), + Auxiliaries.getPixeledAABB(15, 0, 0, 16, 16, 1), + Auxiliaries.getPixeledAABB(15, 0,15, 16, 16,16), + Auxiliaries.getPixeledAABB( 0, 0,15, 1, 16,16) + ) + } + )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk_ta")); + + public static final EdCatwalkStairsBlock STEEL_CATWALK_STAIRS = (EdCatwalkStairsBlock)(new EdCatwalkStairsBlock( + DecorBlock.CFG_CUTOUT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(2f, 10f).sound(SoundType.METAL).noOcclusion(), + new AABB[] { // base + Auxiliaries.getPixeledAABB( 1, 2, 8, 15, 4, 16), + Auxiliaries.getPixeledAABB( 1,10, 0, 15, 12, 8), + }, + new AABB[] { // railing left + Auxiliaries.getPixeledAABB(0.4, 0, 15, 0.6, 15, 16), + Auxiliaries.getPixeledAABB(0.4, 1, 14, 0.6, 16, 15), + Auxiliaries.getPixeledAABB(0.4, 2, 13, 0.6, 17, 14), + Auxiliaries.getPixeledAABB(0.4, 3, 12, 0.6, 18, 13), + Auxiliaries.getPixeledAABB(0.4, 4, 11, 0.6, 19, 12), + Auxiliaries.getPixeledAABB(0.4, 5, 10, 0.6, 20, 11), + Auxiliaries.getPixeledAABB(0.4, 6, 9, 0.6, 21, 10), + Auxiliaries.getPixeledAABB(0.4, 7, 8, 0.6, 22, 9), + Auxiliaries.getPixeledAABB(0.4, 8, 7, 0.6, 23, 8), + Auxiliaries.getPixeledAABB(0.4, 9, 6, 0.6, 24, 7), + Auxiliaries.getPixeledAABB(0.4, 10, 5, 0.6, 25, 6), + Auxiliaries.getPixeledAABB(0.4, 11, 4, 0.6, 26, 5), + Auxiliaries.getPixeledAABB(0.4, 12, 3, 0.6, 27, 4), + Auxiliaries.getPixeledAABB(0.4, 13, 2, 0.6, 28, 3), + Auxiliaries.getPixeledAABB(0.4, 14, 1, 0.6, 29, 2), + Auxiliaries.getPixeledAABB(0.4, 15, 0, 0.6, 30, 1) + } + )).setRegistryName(new ResourceLocation(MODID, "steel_catwalk_stairs")); + + // ------------------------------------------------------------------------------------------------------------------- + + public static final EdTestBlock.TestBlock TEST_BLOCK = (EdTestBlock.TestBlock)(new EdTestBlock.TestBlock( + DecorBlock.CFG_LOOK_PLACEMENT, + BlockBehaviour.Properties.of(Material.METAL, MaterialColor.METAL).strength(0f, 32000f).sound(SoundType.METAL), + Auxiliaries.getPixeledAABB(0,0,0, 16,16,16) + )).setRegistryName(new ResourceLocation(MODID, "test_block")); + + // ------------------------------------------------------------------------------------------------------------------- + + private static final Block[] modBlocks = { + CRAFTING_TABLE, + LABELED_CRATE, + SMALL_LAB_FURNACE, + SMALL_ELECTRICAL_FURNACE, + FACTORY_HOPPER, + FACTORY_DROPPER, + FACTORY_PLACER, + SMALL_BLOCK_BREAKER, + SMALL_TREE_CUTTER, + SMALL_SOLAR_PANEL, + SMALL_WASTE_INCINERATOR, +//>>>> untested + SMALL_MINERAL_SMELTER, + SMALL_FREEZER, + SMALL_MILKING_MACHINE, +//<<<< /untested + FLUID_BARREL, + STRAIGHT_CHECK_VALVE, + STRAIGHT_REDSTONE_VALVE, + STRAIGHT_REDSTONE_ANALOG_VALVE, + SMALL_FLUID_FUNNEL, + DENSE_GRIT_SAND, + DENSE_GRIT_DIRT, + CLINKER_BRICK_BLOCK, + CLINKER_BRICK_SLAB, + CLINKER_BRICK_STAIRS, + CLINKER_BRICK_WALL, + CLINKER_BRICK_SASTOR_CORNER, + CLINKER_BRICK_STAINED_BLOCK, + CLINKER_BRICK_STAINED_SLAB, + CLINKER_BRICK_STAINED_STAIRS, + CLINKER_BRICK_SASTOR_VERTICAL_SLOTTED, + CLINKER_BRICK_RECESSED, + CLINKER_BRICK_VERTICAL_SLAB_STRUCTURED, + SLAG_BRICK_BLOCK, + SLAG_BRICK_SLAB, + SLAG_BRICK_STAIRS, + SLAG_BRICK_WALL, + REBAR_CONCRETE_BLOCK, + REBAR_CONCRETE_SLAB, + REBAR_CONCRETE_STAIRS, + REBAR_CONCRETE_WALL, + REBAR_CONCRETE_TILE, + REBAR_CONCRETE_TILE_SLAB, + REBAR_CONCRETE_TILE_STAIRS, + HALFSLAB_REBARCONCRETE, + HALFSLAB_TREATEDWOOD, + HALFSLAB_SHEETMETALIRON, + HALFSLAB_SHEETMETALSTEEL, + HALFSLAB_SHEETMETALCOPPER, + HALFSLAB_SHEETMETALGOLD, + HALFSLAB_SHEETMETALALUMINIUM, + PANZERGLASS_BLOCK, + PANZERGLASS_SLAB, + DARK_CERAMIC_SHINGLE_ROOF, + DARK_CERAMIC_SHINGLE_ROOF_METALIZED, + DARK_CERAMIC_SHINGLE_ROOF_SKYLIGHT, + DARK_CERAMIC_SHINGLE_ROOF_CHIMNEYTRUNK, + DARK_CERAMIC_SHINGLE_ROOF_WIRECONDUIT, + DARK_CERAMIC_SHINGLE_ROOF_BLOCK, + DARK_CERAMIC_SHINGLE_ROOF_SLAB, + HALFSLAB_DARK_CERAMIC_SHINGLE_ROOF, + DARK_CERAMIC_SHINGLE_ROOF_CHIMNEY, + METAL_RUNG_LADDER, + METAL_RUNG_STEPS, + TREATED_WOOD_LADDER, + METAL_SLIDING_DOOR, + IRON_HATCH, + OLD_INDUSTRIAL_PLANKS, + OLD_INDUSTRIAL_SLAB, + OLD_INDUSTRIAL_STAIRS, + OLD_INDUSTRIAL_SLABSLICE, + OLD_INDUSTRIAL_WOOD_DOOR, + TREATED_WOOD_TABLE, + TREATED_WOOD_STOOL, + TREATED_WOOD_WINDOWSILL, + TREATED_WOOD_BROAD_WINDOWSILL, + TREATED_WOOD_WINDOW, + STEEL_FRAMED_WINDOW, + STEEL_TABLE, + INSET_LIGHT_IRON, + FLOOR_EDGE_LIGHT_IRON, + CEILING_EDGE_LIGHT_IRON, + BULB_LIGHT_IRON, + STEEL_FLOOR_GRATING, + STEEL_MESH_FENCE, + STEEL_MESH_FENCE_GATE, + STEEL_CATWALK, + STEEL_RAILING, + STEEL_CATWALK_TOP_ALIGNED, + STEEL_CATWALK_STAIRS, + TREATED_WOOD_POLE, + TREATED_WOOD_POLE_HEAD, + TREATED_WOOD_POLE_SUPPORT, + THIN_STEEL_POLE, + THIN_STEEL_POLE_HEAD, + THICK_STEEL_POLE, + THICK_STEEL_POLE_HEAD, + STEEL_DOUBLE_T_SUPPORT, + SIGN_HOTWIRE, + SIGN_DANGER, + SIGN_DEFENSE, + SIGN_FACTORY_AREA, + SIGN_EXIT, + SIGN_RADIOACTIVE, + SIGN_LASER, + SIGN_CAUTION, + SIGN_MAGIC_HAZARD, + SIGN_FIRE_HAZARD, + SIGN_HOT_SURFACE, + SIGN_MAGNETIC_FIELD, + SIGN_FROST_WARNING, + SIGN_MODLOGO, + }; + + private static final Block[] devBlocks = { + TEST_BLOCK + }; + + //-------------------------------------------------------------------------------------------------------------------- + // Tile entities bound exclusively to the blocks above + //-------------------------------------------------------------------------------------------------------------------- + + public static final BlockEntityType TET_CRAFTING_TABLE = ModRegistry.register("te_treated_wood_crafting_table", EdCraftingTable.CraftingTableTileEntity::new, CRAFTING_TABLE); + public static final BlockEntityType TET_LABELED_CRATE = ModRegistry.register("te_labeled_crate", EdLabeledCrate.LabeledCrateTileEntity::new, LABELED_CRATE); + public static final BlockEntityType TET_SMALL_LAB_FURNACE = ModRegistry.register("te_small_lab_furnace", EdFurnace.FurnaceTileEntity::new, SMALL_LAB_FURNACE); + public static final BlockEntityType TET_SMALL_ELECTRICAL_FURNACE = ModRegistry.register("te_small_electrical_furnace", EdElectricalFurnace.ElectricalFurnaceTileEntity::new, SMALL_ELECTRICAL_FURNACE); + public static final BlockEntityType TET_FACTORY_DROPPER = ModRegistry.register("te_factory_dropper", EdDropper.DropperTileEntity::new, FACTORY_DROPPER); + public static final BlockEntityType TET_FACTORY_PLACER = ModRegistry.register("te_factory_placer", EdPlacer.PlacerTileEntity::new, FACTORY_PLACER); + public static final BlockEntityType TET_SMALL_BLOCK_BREAKER = ModRegistry.register("te_small_block_breaker", EdBreaker.BreakerTileEntity::new, SMALL_BLOCK_BREAKER); + public static final BlockEntityType TET_FACTORY_HOPPER = ModRegistry.register("te_factory_hopper", EdHopper.HopperTileEntity::new, FACTORY_HOPPER); + public static final BlockEntityType TET_WASTE_INCINERATOR = ModRegistry.register("te_small_waste_incinerator", EdWasteIncinerator.WasteIncineratorTileEntity::new, SMALL_WASTE_INCINERATOR); + public static final BlockEntityType TET_STRAIGHT_PIPE_VALVE = ModRegistry.register("te_pipe_valve", EdPipeValve.PipeValveTileEntity::new, STRAIGHT_CHECK_VALVE, STRAIGHT_REDSTONE_VALVE, STRAIGHT_REDSTONE_ANALOG_VALVE); + public static final BlockEntityType TET_FLUID_BARREL = ModRegistry.register("te_fluid_barrel", EdFluidBarrel.FluidBarrelTileEntity::new, FLUID_BARREL); + public static final BlockEntityType TET_SMALL_FLUID_FUNNEL = ModRegistry.register("te_small_fluid_funnel", EdFluidFunnel.FluidFunnelTileEntity::new, SMALL_FLUID_FUNNEL); + public static final BlockEntityType TET_MINERAL_SMELTER = ModRegistry.register("te_small_mineral_smelter", EdMineralSmelter.MineralSmelterTileEntity::new, SMALL_MINERAL_SMELTER); + public static final BlockEntityType TET_FREEZER = ModRegistry.register("te_small_freezer", EdFreezer.FreezerTileEntity::new, SMALL_FREEZER); + public static final BlockEntityType TET_SMALL_SOLAR_PANEL = ModRegistry.register("te_small_solar_panel", EdSolarPanel.SolarPanelTileEntity::new, SMALL_SOLAR_PANEL); + public static final BlockEntityType TET_SMALL_MILKING_MACHINE = ModRegistry.register("te_small_milking_machine", EdMilker.MilkerTileEntity::new, SMALL_MILKING_MACHINE); + public static final BlockEntityType TET_SMALL_TREE_CUTTER = ModRegistry.register("te_small_tree_cutter", EdTreeCutter.TreeCutterTileEntity::new, SMALL_TREE_CUTTER); + public static final BlockEntityType TET_TEST_BLOCK = ModRegistry.register("te_test_block", EdTestBlock.TestTileEntity::new, TEST_BLOCK); + + private static final BlockEntityType[] tile_entity_types = { + TET_CRAFTING_TABLE, + TET_LABELED_CRATE, + TET_SMALL_LAB_FURNACE, + TET_SMALL_ELECTRICAL_FURNACE, + TET_FACTORY_HOPPER, + TET_FACTORY_DROPPER, + TET_FACTORY_PLACER, + TET_SMALL_BLOCK_BREAKER, + TET_SMALL_TREE_CUTTER, + TET_WASTE_INCINERATOR, + TET_MINERAL_SMELTER, + TET_FREEZER, + TET_SMALL_SOLAR_PANEL, + TET_SMALL_MILKING_MACHINE, + TET_STRAIGHT_PIPE_VALVE, + TET_FLUID_BARREL, + TET_SMALL_FLUID_FUNNEL, + TET_TEST_BLOCK + }; + + //-------------------------------------------------------------------------------------------------------------------- + // Items + //-------------------------------------------------------------------------------------------------------------------- + + private static Item.Properties default_item_properties() + { return (new Item.Properties()).tab(ModEngineersDecor.ITEMGROUP); } + + public static final EdItem METAL_BAR_ITEM = (EdItem)((new EdItem(default_item_properties()).setRegistryName(MODID, "metal_bar"))); + + private static final EdItem[] modItems = { + METAL_BAR_ITEM + }; + + //-------------------------------------------------------------------------------------------------------------------- + // Entities bound exclusively to the blocks above + //-------------------------------------------------------------------------------------------------------------------- + + public static final EntityType ET_CHAIR = ModRegistry.register("et_chair", + EntityType.Builder.of(EdChair.EntityChair::new, MobCategory.MISC) + .fireImmune().sized(1e-3f, 1e-3f).noSave() + .setShouldReceiveVelocityUpdates(false).setUpdateInterval(4) + .setCustomClientFactory(EdChair.EntityChair::customClientFactory) + ); + + private static final EntityType[] entity_types = { + ET_CHAIR + }; + + //-------------------------------------------------------------------------------------------------------------------- + // Container registration + //-------------------------------------------------------------------------------------------------------------------- + + public static final MenuType CT_TREATED_WOOD_CRAFTING_TABLE; + public static final MenuType CT_FACTORY_DROPPER; + public static final MenuType CT_FACTORY_PLACER; + public static final MenuType CT_FACTORY_HOPPER; + public static final MenuType CT_SMALL_LAB_FURNACE; + public static final MenuType CT_SMALL_ELECTRICAL_FURNACE; + public static final MenuType CT_WASTE_INCINERATOR; + public static final MenuType CT_LABELED_CRATE; + + static { + CT_TREATED_WOOD_CRAFTING_TABLE = (new MenuType<>(EdCraftingTable.CraftingTableUiContainer::new)); + CT_TREATED_WOOD_CRAFTING_TABLE.setRegistryName(MODID,"ct_treated_wood_crafting_table"); + CT_FACTORY_DROPPER = (new MenuType<>(EdDropper.DropperUiContainer::new)); + CT_FACTORY_DROPPER.setRegistryName(MODID,"ct_factory_dropper"); + CT_FACTORY_PLACER = (new MenuType<>(EdPlacer.PlacerContainer::new)); + CT_FACTORY_PLACER.setRegistryName(MODID,"ct_factory_placer"); + CT_FACTORY_HOPPER = (new MenuType<>(EdHopper.HopperContainer::new)); + CT_FACTORY_HOPPER.setRegistryName(MODID,"ct_factory_hopper"); + CT_SMALL_LAB_FURNACE = (new MenuType<>(EdFurnace.FurnaceContainer::new)); + CT_SMALL_LAB_FURNACE.setRegistryName(MODID,"ct_small_lab_furnace"); + CT_SMALL_ELECTRICAL_FURNACE = (new MenuType<>(EdElectricalFurnace.ElectricalFurnaceContainer::new)); + CT_SMALL_ELECTRICAL_FURNACE.setRegistryName(MODID,"ct_small_electrical_furnace"); + CT_WASTE_INCINERATOR = (new MenuType<>(EdWasteIncinerator.WasteIncineratorContainer::new)); + CT_WASTE_INCINERATOR.setRegistryName(MODID,"ct_small_waste_incinerator"); + CT_LABELED_CRATE = (new MenuType<>(EdLabeledCrate.LabeledCrateContainer::new)); + CT_LABELED_CRATE.setRegistryName(MODID,"ct_labeled_crate"); + } + + private static final MenuType[] container_types = { + CT_TREATED_WOOD_CRAFTING_TABLE, + CT_LABELED_CRATE, + CT_FACTORY_DROPPER, + CT_FACTORY_PLACER, + CT_FACTORY_HOPPER, + CT_SMALL_LAB_FURNACE, + CT_SMALL_ELECTRICAL_FURNACE, + CT_WASTE_INCINERATOR + }; + + //-------------------------------------------------------------------------------------------------------------------- + // Initialisation events + //-------------------------------------------------------------------------------------------------------------------- + + private static final ArrayList registeredBlocks = new ArrayList<>(); + + public static ArrayList allBlocks() + { + ArrayList blocks = new ArrayList<>(); + Collections.addAll(blocks, modBlocks); + Collections.addAll(blocks, devBlocks); + return blocks; + } + + @SuppressWarnings("deprecation") + public static boolean isExperimentalBlock(Block block) + { return ArrayUtils.contains(devBlocks, block) || ((block instanceof StandardBlocks.IStandardBlock) && ((((StandardBlocks.IStandardBlock)block).config() & DecorBlock.CFG_EXPERIMENTAL))!=0); } + + @Nonnull + public static List getRegisteredBlocks() + { return Collections.unmodifiableList(registeredBlocks); } + + @Nonnull + public static List getRegisteredItems() + { return new ArrayList<>(); } + + public static void registerBlocks(final RegistryEvent.Register event) + { + boolean ie_available = Auxiliaries.isModLoaded("immersiveengineering"); + if(ie_available) { + Auxiliaries.logInfo("Immersive Engineering also installed ..."); + registeredBlocks.addAll(allBlocks()); + } else { + registeredBlocks.addAll(allBlocks().stream() + .filter(block-> + ((!(block instanceof StandardBlocks.IStandardBlock)) || ((((StandardBlocks.IStandardBlock)block).config() & DecorBlock.CFG_HARD_IE_DEPENDENT)==0)) + ) + .collect(Collectors.toList()) + ); + } + for(Block e:registeredBlocks) event.getRegistry().register(e); + Auxiliaries.logInfo("Registered " + (registeredBlocks.size()) + " blocks."); + } + + public static void registerBlockItems(final RegistryEvent.Register event) + { + int n = 0; + for(Block e:registeredBlocks) { + ResourceLocation rl = e.getRegistryName(); + if(rl == null) continue; + if(e instanceof StandardBlocks.IBlockItemFactory) { + event.getRegistry().register(((StandardBlocks.IBlockItemFactory)e).getBlockItem(e, (new Item.Properties().tab(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl)); + } else { + event.getRegistry().register(new BlockItem(e, (new Item.Properties().tab(ModEngineersDecor.ITEMGROUP))).setRegistryName(rl)); + } + ++n; + } + } + + public static void registerItems(final RegistryEvent.Register event) + { for(Item e:modItems) event.getRegistry().register(e); } + + public static void registerTileEntities(final RegistryEvent.Register> event) + { + int n_registered = 0; + for(final BlockEntityType e:tile_entity_types) { + event.getRegistry().register(e); + ++n_registered; + } + Auxiliaries.logInfo("Registered " + (n_registered) + " tile entities."); + } + + public static void registerEntities(final RegistryEvent.Register> event) + { + int n_registered = 0; + for(final EntityType e:entity_types) { + if((e==ET_CHAIR) && (!registeredBlocks.contains(TREATED_WOOD_STOOL))) continue; + event.getRegistry().register(e); + ++n_registered; + } + Auxiliaries.logInfo("Registered " + (n_registered) + " entities bound to blocks."); + } + + public static void registerContainers(final RegistryEvent.Register> event) + { + int n_registered = 0; + for(final MenuType e:container_types) { + event.getRegistry().register(e); + ++n_registered; + } + Auxiliaries.logInfo("Registered " + (n_registered) + " containers bound to tile entities."); + } + + @OnlyIn(Dist.CLIENT) + public static void registerContainerGuis(final FMLClientSetupEvent event) + { + MenuScreens.register(CT_TREATED_WOOD_CRAFTING_TABLE, EdCraftingTable.CraftingTableGui::new); + MenuScreens.register(CT_LABELED_CRATE, EdLabeledCrate.LabeledCrateGui::new); + MenuScreens.register(CT_FACTORY_DROPPER, EdDropper.DropperGui::new); + MenuScreens.register(CT_FACTORY_PLACER, EdPlacer.PlacerGui::new); + MenuScreens.register(CT_FACTORY_HOPPER, EdHopper.HopperGui::new); + MenuScreens.register(CT_SMALL_LAB_FURNACE, EdFurnace.FurnaceGui::new); + MenuScreens.register(CT_SMALL_ELECTRICAL_FURNACE, EdElectricalFurnace.ElectricalFurnaceGui::new); + MenuScreens.register(CT_WASTE_INCINERATOR, EdWasteIncinerator.WasteIncineratorGui::new); + } + + @OnlyIn(Dist.CLIENT) + @SuppressWarnings("unchecked") + public static void registerTileEntityRenderers(final FMLClientSetupEvent event) + { + BlockEntityRenderers.register(TET_CRAFTING_TABLE, wile.engineersdecor.detail.ModRenderers.CraftingTableTer::new); + BlockEntityRenderers.register(TET_LABELED_CRATE, wile.engineersdecor.detail.ModRenderers.DecorLabeledCrateTer::new); + } + + @OnlyIn(Dist.CLIENT) + public static void processContentClientSide(final FMLClientSetupEvent event) + { + // Block renderer selection + for(Block block: getRegisteredBlocks()) { + if(block instanceof IStandardBlock) { + switch(((IStandardBlock)block).getRenderTypeHint()) { + case CUTOUT: ItemBlockRenderTypes.setRenderLayer(block, RenderType.cutout()); break; + case CUTOUT_MIPPED: ItemBlockRenderTypes.setRenderLayer(block, RenderType.cutoutMipped()); break; + case TRANSLUCENT: ItemBlockRenderTypes.setRenderLayer(block, RenderType.translucent()); break; + case TRANSLUCENT_NO_CRUMBLING: ItemBlockRenderTypes.setRenderLayer(block, RenderType.translucentNoCrumbling()); break; + case SOLID: break; + } + } + } + // Entity renderers + EntityRenderers.register(ET_CHAIR, ModRenderers.InvisibleEntityRenderer::new); + } + +} diff --git a/src/main/java/wile/engineersdecor/ModEngineersDecor.java b/src/main/java/wile/engineersdecor/ModEngineersDecor.java index b500264..4d91e7b 100644 --- a/src/main/java/wile/engineersdecor/ModEngineersDecor.java +++ b/src/main/java/wile/engineersdecor/ModEngineersDecor.java @@ -1,136 +1,131 @@ -package wile.engineersdecor; - -import wile.engineersdecor.blocks.*; -import wile.engineersdecor.libmc.detail.Auxiliaries; -import wile.engineersdecor.libmc.detail.OptionalRecipeCondition; -import net.minecraft.entity.EntityType; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.inventory.container.ContainerType; -import net.minecraft.item.ItemGroup; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.block.Block; -import net.minecraft.item.Item; -import net.minecraft.item.ItemStack; -import net.minecraftforge.common.crafting.CraftingHelper; -import net.minecraftforge.event.entity.living.LivingEvent; -import net.minecraftforge.common.MinecraftForge; -import net.minecraftforge.event.RegistryEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.*; -import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - - -@Mod("engineersdecor") -public class ModEngineersDecor -{ - public static final String MODID = "engineersdecor"; - public static final String MODNAME = "Engineer's Decor"; - public static final int VERSION_DATAFIXER = 0; - private static final Logger LOGGER = LogManager.getLogger(); - - public ModEngineersDecor() - { - Auxiliaries.init(MODID, LOGGER, ModConfig::getServerConfig); - Auxiliaries.logGitVersion(MODNAME); - OptionalRecipeCondition.init(MODID, LOGGER); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetup); - FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup); - FMLJavaModLoadingContext.get().getModEventBus().addListener(ForgeEvents::onConfigLoad); - FMLJavaModLoadingContext.get().getModEventBus().addListener(ForgeEvents::onConfigReload); - ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.SERVER, ModConfig.SERVER_CONFIG_SPEC); - ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.COMMON, ModConfig.COMMON_CONFIG_SPEC); - ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.CLIENT, ModConfig.CLIENT_CONFIG_SPEC); - MinecraftForge.EVENT_BUS.register(this); - } - - public static final Logger logger() { return LOGGER; } - - // - // Events - // - - private void onSetup(final FMLCommonSetupEvent event) - { - LOGGER.info("Registering recipe condition processor ..."); - CraftingHelper.register(OptionalRecipeCondition.Serializer.INSTANCE); - wile.engineersdecor.libmc.detail.Networking.init(MODID); - } - - private void onClientSetup(final FMLClientSetupEvent event) - { - ModContent.registerContainerGuis(event); - ModContent.registerTileEntityRenderers(event); - ModContent.processContentClientSide(event); - wile.engineersdecor.libmc.detail.Overlay.register(); - } - - @Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) - public static class ForgeEvents - { - @SubscribeEvent - public static void onBlocksRegistry(final RegistryEvent.Register event) - { ModContent.registerBlocks(event); } - - @SubscribeEvent - public static void onItemRegistry(final RegistryEvent.Register event) - { ModContent.registerItems(event); ModContent.registerBlockItems(event); } - - @SubscribeEvent - public static void onTileEntityRegistry(final RegistryEvent.Register> event) - { ModContent.registerTileEntities(event); } - - @SubscribeEvent - public static void onRegisterEntityTypes(final RegistryEvent.Register> event) - { ModContent.registerEntities(event); } - - @SubscribeEvent - public static void onRegisterContainerTypes(final RegistryEvent.Register> event) - { ModContent.registerContainers(event); } - - public static void onConfigLoad(net.minecraftforge.fml.config.ModConfig.Loading configEvent) - { ModConfig.apply(); } - - public static void onConfigReload(net.minecraftforge.fml.config.ModConfig.Reloading configEvent) - { - try { - ModEngineersDecor.logger().info("Config file changed {}", configEvent.getConfig().getFileName()); - ModConfig.apply(); - } catch(Throwable e) { - ModEngineersDecor.logger().error("Failed to load changed config: " + e.getMessage()); - } - } - - @SubscribeEvent - public static void onDataGeneration(GatherDataEvent event) - { - event.getGenerator().addProvider(new wile.engineersdecor.libmc.datagen.LootTableGen(event.getGenerator(), ModContent::allBlocks)); - } - } - - // - // Item group / creative tab - // - public static final ItemGroup ITEMGROUP = (new ItemGroup("tab" + MODID) { - @OnlyIn(Dist.CLIENT) - public ItemStack makeIcon() - { return new ItemStack(ModContent.SIGN_MODLOGO); } - }); - - // - // Player update event - // - @SubscribeEvent - public void onPlayerEvent(final LivingEvent.LivingUpdateEvent event) - { - if((event.getEntity().level == null) || (!(event.getEntity() instanceof PlayerEntity))) return; - final PlayerEntity player = (PlayerEntity)event.getEntity(); - if(player.onClimbable()) EdLadderBlock.onPlayerUpdateEvent(player); - } - -} +package wile.engineersdecor; + +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.crafting.CraftingHelper; +import net.minecraftforge.event.RegistryEvent; +import net.minecraftforge.event.entity.living.LivingEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.ModLoadingContext; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import wile.engineersdecor.blocks.EdLadderBlock; +import wile.engineersdecor.libmc.detail.Auxiliaries; +import wile.engineersdecor.libmc.detail.OptionalRecipeCondition; + + +@Mod("engineersdecor") +public class ModEngineersDecor +{ + public static final String MODID = "engineersdecor"; + public static final String MODNAME = "Engineer's Decor"; + public static final int VERSION_DATAFIXER = 0; + private static final Logger LOGGER = LogManager.getLogger(); + + public ModEngineersDecor() + { + Auxiliaries.init(MODID, LOGGER, ModConfig::getServerConfig); + Auxiliaries.logGitVersion(MODNAME); + OptionalRecipeCondition.init(MODID, LOGGER); + ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.SERVER, ModConfig.SERVER_CONFIG_SPEC); + ModLoadingContext.get().registerConfig(net.minecraftforge.fml.config.ModConfig.Type.COMMON, ModConfig.COMMON_CONFIG_SPEC); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onSetup); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onClientSetup); + // FMLJavaModLoadingContext.get().getModEventBus().addListener(ForgeEvents::onConfigLoad); + // FMLJavaModLoadingContext.get().getModEventBus().addListener(ForgeEvents::onConfigReload); + MinecraftForge.EVENT_BUS.register(this); + } + + public static Logger logger() { return LOGGER; } + + // + // Events + // + + private void onSetup(final FMLCommonSetupEvent event) + { + LOGGER.info("Registering recipe condition processor ..."); + CraftingHelper.register(OptionalRecipeCondition.Serializer.INSTANCE); + wile.engineersdecor.libmc.detail.Networking.init(MODID); + } + + private void onClientSetup(final FMLClientSetupEvent event) + { + ModContent.registerContainerGuis(event); + ModContent.registerTileEntityRenderers(event); + ModContent.processContentClientSide(event); + wile.engineersdecor.libmc.detail.Overlay.register(); + } + + @Mod.EventBusSubscriber(bus=Mod.EventBusSubscriber.Bus.MOD) + public static class ForgeEvents + { + @SubscribeEvent + public static void onBlocksRegistry(final RegistryEvent.Register event) + { ModContent.registerBlocks(event); } + + @SubscribeEvent + public static void onItemRegistry(final RegistryEvent.Register event) + { ModContent.registerItems(event); ModContent.registerBlockItems(event); } + + @SubscribeEvent + public static void onTileEntityRegistry(final RegistryEvent.Register> event) + { ModContent.registerTileEntities(event); } + + @SubscribeEvent + public static void onRegisterEntityTypes(final RegistryEvent.Register> event) + { ModContent.registerEntities(event); } + + @SubscribeEvent + public static void onRegisterContainerTypes(final RegistryEvent.Register> event) + { ModContent.registerContainers(event); } + + /* + public static void onConfigLoad(net.minecraftforge.fml.config.ModConfig.Loading configEvent) + { ModConfig.apply(); } + + public static void onConfigReload(net.minecraftforge.fml.config.ModConfig.Reloading configEvent) + { + try { + ModEngineersDecor.logger().info("Config file changed {}", configEvent.getConfig().getFileName()); + ModConfig.apply(); + } catch(Throwable e) { + ModEngineersDecor.logger().error("Failed to load changed config: " + e.getMessage()); + } + } + */ + } + + // + // Item group / creative tab + // + public static final CreativeModeTab ITEMGROUP = (new CreativeModeTab("tab" + MODID) { + @OnlyIn(Dist.CLIENT) + public ItemStack makeIcon() + { return new ItemStack(ModContent.SIGN_MODLOGO); } + }); + + // + // Player update event + // + @SubscribeEvent + public void onPlayerEvent(final LivingEvent.LivingUpdateEvent event) + { + if((event.getEntity().level == null) || (!(event.getEntity() instanceof final Player player))) return; + if(player.onClimbable()) EdLadderBlock.onPlayerUpdateEvent(player); + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/DecorBlock.java b/src/main/java/wile/engineersdecor/blocks/DecorBlock.java index d0739af..9c46917 100644 --- a/src/main/java/wile/engineersdecor/blocks/DecorBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/DecorBlock.java @@ -1,135 +1,34 @@ -/* - * @file DecorBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Common functionality class for decor blocks. - * Mainly needed for: - * - MC block defaults. - * - Tooltip functionality - * - Model initialisation - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.AbstractBlock; -import wile.engineersdecor.libmc.blocks.StandardBlocks; -import wile.engineersdecor.libmc.blocks.StandardBlocks.IStandardBlock; -import wile.engineersdecor.libmc.detail.Auxiliaries; -import net.minecraft.block.IWaterLoggable; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.shapes.VoxelShape; -import java.util.ArrayList; -import java.util.function.Supplier; - - - -public class DecorBlock -{ - public static final long CFG_DEFAULT = StandardBlocks.CFG_DEFAULT; - public static final long CFG_CUTOUT = StandardBlocks.CFG_CUTOUT; - public static final long CFG_MIPPED = StandardBlocks.CFG_MIPPED; - public static final long CFG_TRANSLUCENT = StandardBlocks.CFG_TRANSLUCENT; - public static final long CFG_WATERLOGGABLE = StandardBlocks.CFG_WATERLOGGABLE; - public static final long CFG_HORIZIONTAL = StandardBlocks.CFG_HORIZIONTAL; - public static final long CFG_LOOK_PLACEMENT = StandardBlocks.CFG_LOOK_PLACEMENT; - public static final long CFG_FACING_PLACEMENT = StandardBlocks.CFG_FACING_PLACEMENT; - public static final long CFG_OPPOSITE_PLACEMENT = StandardBlocks.CFG_OPPOSITE_PLACEMENT; - public static final long CFG_FLIP_PLACEMENT_IF_SAME = StandardBlocks.CFG_FLIP_PLACEMENT_IF_SAME; - public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = StandardBlocks.CFG_FLIP_PLACEMENT_SHIFTCLICK; - public static final long CFG_STRICT_CONNECTIONS = StandardBlocks.CFG_STRICT_CONNECTIONS; - public static final long CFG_AI_PASSABLE = StandardBlocks.CFG_AI_PASSABLE; - public static final long CFG_HARD_IE_DEPENDENT = 0x8000000000000000L; - @Deprecated public static final long CFG_EXPERIMENTAL = 0x4000000000000000L; - - public static class Normal extends StandardBlocks.BaseBlock implements IDecorBlock - { - public Normal(long conf, AbstractBlock.Properties properties) - { super(conf, properties); } - } - - public static class Cutout extends StandardBlocks.Cutout implements IDecorBlock - { - public Cutout(long conf, AbstractBlock.Properties properties) - { super(conf, properties, Auxiliaries.getPixeledAABB(0, 0, 0, 16, 16,16 )); } - - public Cutout(long conf, AbstractBlock.Properties properties, AxisAlignedBB aabb) - { super(conf, properties, aabb);} - - public Cutout(long conf, AbstractBlock.Properties properties, VoxelShape voxel_shape) - { super(conf, properties, voxel_shape); } - - public Cutout(long conf, AbstractBlock.Properties properties, AxisAlignedBB[] aabbs) - { super(conf, properties, aabbs); } - } - - public static class WaterLoggable extends StandardBlocks.WaterLoggable implements IStandardBlock, IWaterLoggable - { - public WaterLoggable(long config, AbstractBlock.Properties properties) - { super(config, properties); } - - public WaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB aabb) - { super(config, properties, aabb); } - - public WaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB[] aabbs) - { super(config, properties, aabbs); } - - public WaterLoggable(long config, AbstractBlock.Properties properties, VoxelShape voxel_shape) - { super(config, properties, voxel_shape); } - } - - public static class Directed extends StandardBlocks.Directed implements IDecorBlock - { - public Directed(long config, AbstractBlock.Properties properties, final AxisAlignedBB unrotatedAABB) - { super(config, properties, unrotatedAABB); } - - public Directed(long config, AbstractBlock.Properties properties, final AxisAlignedBB[] unrotatedAABBs) - { super(config, properties, unrotatedAABBs); } - - public Directed(long config, AbstractBlock.Properties properties, final Supplier> shape_supplier) - { super(config, properties, shape_supplier); } - } - - public static class DirectedWaterLoggable extends StandardBlocks.DirectedWaterLoggable implements IDecorBlock,IWaterLoggable - { - public DirectedWaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB aabb) - { super(config, properties, aabb); } - - public DirectedWaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB[] aabbs) - { super(config, properties, aabbs); } - - public DirectedWaterLoggable(long config, AbstractBlock.Properties properties, final Supplier> shape_supplier) - { super(config, properties, shape_supplier); } - } - - public static class Horizontal extends StandardBlocks.Horizontal implements IDecorBlock - { - public Horizontal(long config, AbstractBlock.Properties properties, final AxisAlignedBB unrotatedAABB) - { super(config, properties, unrotatedAABB); } - - public Horizontal(long config, AbstractBlock.Properties properties, final AxisAlignedBB[] unrotatedAABBs) - { super(config, properties, unrotatedAABBs); } - - public Horizontal(long config, AbstractBlock.Properties properties, final Supplier> shape_supplier) - { super(config, properties, shape_supplier); } - } - - public static class HorizontalWaterLoggable extends StandardBlocks.HorizontalWaterLoggable implements IWaterLoggable - { - public HorizontalWaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB aabb) - { super(config, properties, aabb); } - - public HorizontalWaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB[] aabbs) - { super(config, properties, aabbs); } - - public HorizontalWaterLoggable(long config, AbstractBlock.Properties properties, final Supplier> shape_supplier) - { super(config, properties, shape_supplier); } - } - - public static class HorizontalFourWayWaterLoggable extends StandardBlocks.HorizontalFourWayWaterLoggable implements IWaterLoggable - { - public HorizontalFourWayWaterLoggable(long config, AbstractBlock.Properties properties, AxisAlignedBB base_aabb, AxisAlignedBB side_aabb, int railing_height_extension) - { super(config, properties, base_aabb, side_aabb, railing_height_extension); } - } - -} +/* + * @file DecorBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Common functionality class for decor blocks. + * Mainly needed for: + * - MC block defaults. + * - Tooltip functionality + * - Model initialisation + */ +package wile.engineersdecor.blocks; + +import wile.engineersdecor.libmc.blocks.StandardBlocks; + +public class DecorBlock +{ + public static final long CFG_DEFAULT = StandardBlocks.CFG_DEFAULT; + public static final long CFG_CUTOUT = StandardBlocks.CFG_CUTOUT; + public static final long CFG_MIPPED = StandardBlocks.CFG_MIPPED; + public static final long CFG_TRANSLUCENT = StandardBlocks.CFG_TRANSLUCENT; + public static final long CFG_WATERLOGGABLE = StandardBlocks.CFG_WATERLOGGABLE; + public static final long CFG_HORIZIONTAL = StandardBlocks.CFG_HORIZIONTAL; + public static final long CFG_LOOK_PLACEMENT = StandardBlocks.CFG_LOOK_PLACEMENT; + public static final long CFG_FACING_PLACEMENT = StandardBlocks.CFG_FACING_PLACEMENT; + public static final long CFG_OPPOSITE_PLACEMENT = StandardBlocks.CFG_OPPOSITE_PLACEMENT; + public static final long CFG_FLIP_PLACEMENT_IF_SAME = StandardBlocks.CFG_FLIP_PLACEMENT_IF_SAME; + public static final long CFG_FLIP_PLACEMENT_SHIFTCLICK = StandardBlocks.CFG_FLIP_PLACEMENT_SHIFTCLICK; + public static final long CFG_STRICT_CONNECTIONS = StandardBlocks.CFG_STRICT_CONNECTIONS; + public static final long CFG_AI_PASSABLE = StandardBlocks.CFG_AI_PASSABLE; + public static final long CFG_HARD_IE_DEPENDENT = 0x8000000000000000L; + @Deprecated public static final long CFG_EXPERIMENTAL = 0x4000000000000000L; +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdBreaker.java b/src/main/java/wile/engineersdecor/blocks/EdBreaker.java index fc31b41..8606981 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdBreaker.java +++ b/src/main/java/wile/engineersdecor/blocks/EdBreaker.java @@ -1,356 +1,349 @@ -/* - * @file EdBreaker.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Small Block Breaker - */ -package wile.engineersdecor.blocks; - -import wile.engineersdecor.ModConfig; -import wile.engineersdecor.ModContent; -import wile.engineersdecor.libmc.detail.Auxiliaries; -import wile.engineersdecor.libmc.detail.Inventories; -import wile.engineersdecor.libmc.detail.Overlay; -import net.minecraft.world.World; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.GameRules; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.state.BooleanProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Blocks; -import net.minecraft.block.SoundType; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.tileentity.ITickableTileEntity; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.item.ItemEntity; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.item.ItemStack; -import net.minecraft.particles.ParticleTypes; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.util.*; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import net.minecraftforge.common.util.LazyOptional; -import net.minecraftforge.energy.CapabilityEnergy; -import net.minecraftforge.energy.IEnergyStorage; -import wile.engineersdecor.libmc.detail.RfEnergy; - -import javax.annotation.Nullable; -import java.util.HashSet; -import java.util.List; -import java.util.Random; - - - -public class EdBreaker -{ - public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required) - { BreakerTileEntity.on_config(boost_energy_per_tick, breaking_time_per_hardness, min_breaking_time_ticks, power_required); } - - //-------------------------------------------------------------------------------------------------------------------- - // Block - //-------------------------------------------------------------------------------------------------------------------- - - public static class BreakerBlock extends DecorBlock.HorizontalWaterLoggable implements IDecorBlock - { - public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); - - public BreakerBlock(long config, AbstractBlock.Properties builder, final AxisAlignedBB[] unrotatedAABBs) - { super(config, builder, unrotatedAABBs); } - - @Override - protected void createBlockStateDefinition(StateContainer.Builder builder) - { super.createBlockStateDefinition(builder); builder.add(ACTIVE); } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { return super.getStateForPlacement(context).setValue(ACTIVE, false); } - - @Override - public boolean hasTileEntity(BlockState state) - { return true; } - - @Override - @Nullable - public TileEntity createTileEntity(BlockState state, IBlockReader world) - { return new BreakerTileEntity(); } - - @OnlyIn(Dist.CLIENT) - public void animateTick(BlockState state, World world, BlockPos pos, Random rnd) - { - if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return; - final double rv = rnd.nextDouble(); - if(rv > 0.8) return; - final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ(); - final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2); - switch(state.getValue(HORIZONTAL_FACING)) { - case WEST: world.addParticle(ParticleTypes.SMOKE, x-xc, yr, z+xr, 0.0, 0.0, 0.0); break; - case EAST: world.addParticle(ParticleTypes.SMOKE, x+xc, yr, z+xr, 0.0, 0.0, 0.0); break; - case NORTH: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z-xc, 0.0, 0.0, 0.0); break; - default: world.addParticle(ParticleTypes.SMOKE, x+xr, yr, z+xc, 0.0, 0.0, 0.0); break; - } - } - - @Override - @SuppressWarnings("deprecation") - public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) - { - if(!(world instanceof World) || (((World) world).isClientSide)) return; - TileEntity te = world.getBlockEntity(pos); - if(!(te instanceof BreakerTileEntity)) return; - ((BreakerTileEntity)te).block_updated(); - } - - @Override - @SuppressWarnings("deprecation") - public boolean isSignalSource(BlockState state) - { return true; } - - @Override - @SuppressWarnings("deprecation") - public int getSignal(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) - { return 0; } - - @Override - @SuppressWarnings("deprecation") - public int getDirectSignal(BlockState blockState, IBlockReader blockAccess, BlockPos pos, Direction side) - { return 0; } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) - { - if(world.isClientSide()) return ActionResultType.SUCCESS; - TileEntity te = world.getBlockEntity(pos); - if(te instanceof BreakerTileEntity) ((BreakerTileEntity)te).state_message(player); - return ActionResultType.CONSUME; - } - } - - //-------------------------------------------------------------------------------------------------------------------- - // Tile entity - //-------------------------------------------------------------------------------------------------------------------- - - public static class BreakerTileEntity extends TileEntity implements ITickableTileEntity - { - public static final int IDLE_TICK_INTERVAL = 40; - public static final int TICK_INTERVAL = 5; - public static final int BOOST_FACTOR = 8; - public static final int DEFAULT_BOOST_ENERGY = 64; - public static final int DEFAULT_BREAKING_RELUCTANCE = 17; - public static final int DEFAULT_MIN_BREAKING_TIME = 15; - public static final int MAX_BREAKING_TIME = 800; - private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY; - private static int energy_max = 32000; - private static int breaking_reluctance = DEFAULT_BREAKING_RELUCTANCE; - private static int min_breaking_time = DEFAULT_MIN_BREAKING_TIME; - private static boolean requires_power = false; - private int tick_timer_; - private int active_timer_; - private int proc_time_elapsed_; - private int time_needed_; - private final RfEnergy.Battery battery_; - private final LazyOptional energy_handler_; - - public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required) - { - boost_energy_consumption = TICK_INTERVAL * MathHelper.clamp(boost_energy_per_tick, 4, 4096); - energy_max = Math.max(boost_energy_consumption * 10, 100000); - breaking_reluctance = MathHelper.clamp(breaking_time_per_hardness, 5, 50); - min_breaking_time = MathHelper.clamp(min_breaking_time_ticks, 10, 100); - requires_power = power_required; - ModConfig.log("Config block breaker: Boost energy consumption:" + (boost_energy_consumption/TICK_INTERVAL) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t."); - } - - public BreakerTileEntity() - { this(ModContent.TET_SMALL_BLOCK_BREAKER); } - - public BreakerTileEntity(TileEntityType te_type) - { - super(te_type); - battery_ = new RfEnergy.Battery(energy_max, boost_energy_consumption, 0); - energy_handler_ = battery_.createEnergyHandler(); - } - - public void block_updated() - { if(tick_timer_ > 2) tick_timer_ = 2; } - - public void readnbt(CompoundNBT nbt) - { battery_.load(nbt); } - - private void writenbt(CompoundNBT nbt) - { battery_.save(nbt); } - - public void state_message(PlayerEntity player) - { - String progress = "0"; - if((proc_time_elapsed_ > 0) && (time_needed_ > 0)) { - progress = Integer.toString((int)MathHelper.clamp((((double)proc_time_elapsed_) / ((double)time_needed_) * 100), 0, 100)); - } - Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", new Object[]{battery_.getSOC(), energy_max, progress })); - } - - // TileEntity ------------------------------------------------------------------------------ - - @Override - public void load(BlockState state, CompoundNBT nbt) - { super.load(state, nbt); readnbt(nbt); } - - @Override - public CompoundNBT save(CompoundNBT nbt) - { super.save(nbt); writenbt(nbt); return nbt; } - - @Override - public void setRemoved() - { - super.setRemoved(); - energy_handler_.invalidate(); - } - - // Capability export ---------------------------------------------------------------------------- - - @Override - public LazyOptional getCapability(net.minecraftforge.common.capabilities.Capability capability, @Nullable Direction facing) - { - if(capability == CapabilityEnergy.ENERGY) return energy_handler_.cast(); - return super.getCapability(capability, facing); - } - - // ITickable ------------------------------------------------------------------------------------ - - private static final HashSet blacklist = new HashSet<>(); - static { - blacklist.add(Blocks.AIR); - blacklist.add(Blocks.BEDROCK); - blacklist.add(Blocks.FIRE); - blacklist.add(Blocks.END_PORTAL); - blacklist.add(Blocks.END_GATEWAY); - blacklist.add(Blocks.END_PORTAL_FRAME); - blacklist.add(Blocks.NETHER_PORTAL); - blacklist.add(Blocks.BARRIER); - } - - private static boolean isBreakable(BlockState state, BlockPos pos, World world) - { - final Block block = state.getBlock(); - if(blacklist.contains(block)) return false; - if(state.getMaterial().isLiquid()) return false; - if(block.isAir(state, world, pos)) return false; - float bh = state.getDestroySpeed(world, pos); - if((bh<0) || (bh>55)) return false; - return true; - } - - private static void spawnBlockAsEntity(World world, BlockPos pos, ItemStack stack) { - if(world.isClientSide || stack.isEmpty() || (!world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) || world.restoringBlockSnapshots) return; - ItemEntity e = new ItemEntity(world, - ((world.random.nextFloat()*0.1)+0.5) + pos.getX(), - ((world.random.nextFloat()*0.1)+0.5) + pos.getY(), - ((world.random.nextFloat()*0.1)+0.5) + pos.getZ(), - stack - ); - e.setDefaultPickUpDelay(); - e.setDeltaMovement((world.random.nextFloat()*0.1-0.05), (world.random.nextFloat()*0.1-0.03), (world.random.nextFloat()*0.1-0.05)); - world.addFreshEntity(e); - } - - private static boolean canInsertInto(World world, BlockPos pos) - { - // Maybe make a tag for that. The question is if it is actually worth it, or if that would be only - // tag spamming the game. So for now only FH and VH. - final BlockState state = world.getBlockState(pos); - return (state.getBlock() == ModContent.FACTORY_HOPPER) || (state.getBlock() == Blocks.HOPPER); - } - - private boolean breakBlock(BlockState state, BlockPos pos, World world) - { - if(world.isClientSide || (!(world instanceof ServerWorld)) || world.restoringBlockSnapshots) return false; // retry next cycle - List drops; - final Block block = state.getBlock(); - final boolean insert = canInsertInto(world, getBlockPos().below()); - drops = Block.getDrops(state, (ServerWorld)world, pos, world.getBlockEntity(pos)); - world.removeBlock(pos, false); - for(ItemStack drop:drops) { - if(!insert) { - spawnBlockAsEntity(world, pos, drop); - } else { - final ItemStack remaining = Inventories.insert(world, getBlockPos().below(), Direction.UP, drop, false); - if(!remaining.isEmpty()) spawnBlockAsEntity(world, pos, remaining); - } - } - SoundType stype = state.getBlock().getSoundType(state, world, pos, null); - if(stype != null) world.playSound(null, pos, stype.getPlaceSound(), SoundCategory.BLOCKS, stype.getVolume()*0.6f, stype.getPitch()); - return true; - } - - @Override - @SuppressWarnings("deprecation") - public void tick() - { - if(--tick_timer_ > 0) return; - final BlockState device_state = level.getBlockState(worldPosition); - if(!(device_state.getBlock() instanceof BreakerBlock)) return; - if(level.isClientSide) { - if(!device_state.getValue(BreakerBlock.ACTIVE)) { - tick_timer_ = TICK_INTERVAL; - } else { - tick_timer_ = 1; - // not sure if is so cool to do this each tick ... may be simplified/removed again. - SoundEvent sound = SoundEvents.WOOD_HIT; - BlockState target_state = level.getBlockState(worldPosition.relative(device_state.getValue(BreakerBlock.HORIZONTAL_FACING))); - SoundType stype = target_state.getBlock().getSoundType(target_state); - if((stype == SoundType.WOOL) || (stype == SoundType.GRASS) || (stype == SoundType.SNOW)) { - sound = SoundEvents.WOOL_HIT; - } else if((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) { - sound = SoundEvents.GRAVEL_HIT; - } - level.playLocalSound(worldPosition.getX(), worldPosition.getY(), worldPosition.getZ(), sound, SoundCategory.BLOCKS, 0.1f, 1.2f, false); - } - } else { - tick_timer_ = TICK_INTERVAL; - final BlockPos target_pos = worldPosition.relative(device_state.getValue(BreakerBlock.HORIZONTAL_FACING)); - final BlockState target_state = level.getBlockState(target_pos); - if((level.hasNeighborSignal(worldPosition)) || (!isBreakable(target_state, target_pos, level))) { - if(device_state.getValue(BreakerBlock.ACTIVE)) level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, false), 1|2); - proc_time_elapsed_ = 0; - tick_timer_ = IDLE_TICK_INTERVAL; - return; - } - time_needed_ = MathHelper.clamp((int)(target_state.getDestroySpeed(level, worldPosition) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME); - if(battery_.draw(boost_energy_consumption)) { - proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR); - time_needed_ += min_breaking_time * (3*BOOST_FACTOR/5); - active_timer_ = 2; - } else if(!requires_power) { - proc_time_elapsed_ += TICK_INTERVAL; - active_timer_ = 1024; - } else if(active_timer_ > 0) { - --active_timer_; - } - boolean active = (active_timer_ > 0); - if(requires_power && !active) { - proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL); - } - if(proc_time_elapsed_ >= time_needed_) { - proc_time_elapsed_ = 0; - breakBlock(target_state, target_pos, level); - active = false; - } - if(device_state.getValue(BreakerBlock.ACTIVE) != active) { - level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1|2); - } - } - } - } -} +/* + * @file EdBreaker.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Small Block Breaker + */ +package wile.engineersdecor.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.util.Mth; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.item.ItemEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.GameRules; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.energy.CapabilityEnergy; +import net.minecraftforge.energy.IEnergyStorage; +import wile.engineersdecor.ModConfig; +import wile.engineersdecor.ModContent; +import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.blocks.StandardEntityBlocks; +import wile.engineersdecor.libmc.detail.Auxiliaries; +import wile.engineersdecor.libmc.detail.Inventories; +import wile.engineersdecor.libmc.detail.Overlay; +import wile.engineersdecor.libmc.detail.RfEnergy; + +import javax.annotation.Nullable; +import java.util.HashSet; +import java.util.List; +import java.util.Random; + + +public class EdBreaker +{ + public static final int BOOST_FACTOR = 8; + public static final int DEFAULT_BOOST_ENERGY = 64; + public static final int DEFAULT_BREAKING_RELUCTANCE = 17; + public static final int DEFAULT_MIN_BREAKING_TIME = 15; + public static final int MAX_BREAKING_TIME = 800; + + private static int boost_energy_consumption = DEFAULT_BOOST_ENERGY; + private static int energy_max = 32000; + private static int breaking_reluctance = DEFAULT_BREAKING_RELUCTANCE; + private static int min_breaking_time = DEFAULT_MIN_BREAKING_TIME; + private static boolean requires_power = false; + + public static void on_config(int boost_energy_per_tick, int breaking_time_per_hardness, int min_breaking_time_ticks, boolean power_required) + { + final int interval = BreakerTileEntity.TICK_INTERVAL; + boost_energy_consumption = interval * Mth.clamp(boost_energy_per_tick, 4, 4096); + energy_max = Math.max(boost_energy_consumption * 10, 100000); + breaking_reluctance = Mth.clamp(breaking_time_per_hardness, 5, 50); + min_breaking_time = Mth.clamp(min_breaking_time_ticks, 10, 100); + requires_power = power_required; + ModConfig.log("Config block breaker: Boost energy consumption:" + (boost_energy_consumption/interval) + "rf/t, reluctance=" + breaking_reluctance + "t/hrdn, break time offset=" + min_breaking_time + "t."); + } + + //-------------------------------------------------------------------------------------------------------------------- + // Block + //-------------------------------------------------------------------------------------------------------------------- + + public static class BreakerBlock extends StandardBlocks.HorizontalWaterLoggable implements StandardEntityBlocks.IStandardEntityBlock + { + public static final BooleanProperty ACTIVE = BooleanProperty.create("active"); + + public BreakerBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) + { super(config, builder, unrotatedAABBs); } + + @Nullable + @Override + public BlockEntityType getBlockEntityType() + { return ModContent.TET_SMALL_BLOCK_BREAKER; } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) + { super.createBlockStateDefinition(builder); builder.add(ACTIVE); } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { return super.getStateForPlacement(context).setValue(ACTIVE, false); } + + @OnlyIn(Dist.CLIENT) + @SuppressWarnings("deprecation") + public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) + { + if((state.getBlock()!=this) || (!state.getValue(ACTIVE))) return; + // Sound + if(true || (world.getGameTime() & 0x1) == 0) { + SoundEvent sound = SoundEvents.WOOD_HIT; + BlockState target_state = world.getBlockState(pos.relative(state.getValue(BreakerBlock.HORIZONTAL_FACING))); + SoundType stype = target_state.getBlock().getSoundType(target_state); + if((stype == SoundType.WOOL) || (stype == SoundType.GRASS) || (stype == SoundType.SNOW)) { + sound = SoundEvents.WOOL_HIT; + } else if((stype == SoundType.GRAVEL) || (stype == SoundType.SAND)) { + sound = SoundEvents.GRAVEL_HIT; + } + world.playLocalSound(pos.getX(), pos.getY(), pos.getZ(), sound, SoundSource.BLOCKS, 0.1f, 1.2f, false); + } + // Particles + { + final double rv = rnd.nextDouble(); + if(rv < 0.8) { + final double x=0.5+pos.getX(), y=0.5+pos.getY(), z=0.5+pos.getZ(); + final double xc=0.52, xr=rnd.nextDouble()*0.4-0.2, yr=(y-0.3+rnd.nextDouble()*0.2); + switch (state.getValue(HORIZONTAL_FACING)) { + case WEST -> world.addParticle(ParticleTypes.SMOKE, x - xc, yr, z + xr, 0.0, 0.0, 0.0); + case EAST -> world.addParticle(ParticleTypes.SMOKE, x + xc, yr, z + xr, 0.0, 0.0, 0.0); + case NORTH -> world.addParticle(ParticleTypes.SMOKE, x + xr, yr, z - xc, 0.0, 0.0, 0.0); + default -> world.addParticle(ParticleTypes.SMOKE, x + xr, yr, z + xc, 0.0, 0.0, 0.0); + } + } + } + } + + @Override + @SuppressWarnings("deprecation") + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) + { + if(!(world instanceof Level) || (world.isClientSide)) return; + BlockEntity te = world.getBlockEntity(pos); + if(!(te instanceof BreakerTileEntity)) return; + ((BreakerTileEntity)te).block_updated(); + } + + @Override + @SuppressWarnings("deprecation") + public boolean isSignalSource(BlockState state) + { return true; } + + @Override + @SuppressWarnings("deprecation") + public int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) + { return 0; } + + @Override + @SuppressWarnings("deprecation") + public int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) + { return 0; } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + if(world.isClientSide()) return InteractionResult.SUCCESS; + BlockEntity te = world.getBlockEntity(pos); + if(te instanceof BreakerTileEntity) ((BreakerTileEntity)te).state_message(player); + return InteractionResult.CONSUME; + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // Tile entity + //-------------------------------------------------------------------------------------------------------------------- + + public static class BreakerTileEntity extends StandardEntityBlocks.StandardBlockEntity + { + public static final int IDLE_TICK_INTERVAL = 40; + public static final int TICK_INTERVAL = 5; + private int tick_timer_; + private int active_timer_; + private int proc_time_elapsed_; + private int time_needed_; + private final RfEnergy.Battery battery_ = new RfEnergy.Battery(energy_max, boost_energy_consumption, 0); + private final LazyOptional energy_handler_ = battery_.createEnergyHandler(); + + public BreakerTileEntity(BlockPos pos, BlockState state) + { super(ModContent.TET_SMALL_BLOCK_BREAKER, pos, state); } + + public void block_updated() + { if(tick_timer_ > 2) tick_timer_ = 2; } + + public void readnbt(CompoundTag nbt) + { battery_.load(nbt); } + + private void writenbt(CompoundTag nbt) + { battery_.save(nbt); } + + public void state_message(Player player) + { + String progress = "0"; + if((proc_time_elapsed_ > 0) && (time_needed_ > 0)) { + progress = Integer.toString((int)Mth.clamp((((double)proc_time_elapsed_) / ((double)time_needed_) * 100), 0, 100)); + } + Overlay.show(player, Auxiliaries.localizable("block.engineersdecor.small_block_breaker.status", battery_.getSOC(), energy_max, progress)); + } + + // BlockEntity ------------------------------------------------------------------------------ + + @Override + public void load(CompoundTag nbt) + { super.load(nbt); readnbt(nbt); } + + @Override + public CompoundTag save(CompoundTag nbt) + { super.save(nbt); writenbt(nbt); return nbt; } + + @Override + public void setRemoved() + { + super.setRemoved(); + energy_handler_.invalidate(); + } + + // Capability export ---------------------------------------------------------------------------- + + @Override + public LazyOptional getCapability(net.minecraftforge.common.capabilities.Capability capability, @Nullable Direction facing) + { + if(capability == CapabilityEnergy.ENERGY) return energy_handler_.cast(); + return super.getCapability(capability, facing); + } + + // ITickable ------------------------------------------------------------------------------------ + + private static final HashSet blacklist = new HashSet<>(); + static { + blacklist.add(Blocks.AIR); + blacklist.add(Blocks.BEDROCK); + blacklist.add(Blocks.FIRE); + blacklist.add(Blocks.END_PORTAL); + blacklist.add(Blocks.END_GATEWAY); + blacklist.add(Blocks.END_PORTAL_FRAME); + blacklist.add(Blocks.NETHER_PORTAL); + blacklist.add(Blocks.BARRIER); + } + + private static boolean isBreakable(BlockState state, BlockPos pos, Level world) + { + final Block block = state.getBlock(); + if(blacklist.contains(block)) return false; + if(state.isAir()) return false; + if(state.getMaterial().isLiquid()) return false; + float bh = state.getDestroySpeed(world, pos); + return !((bh<0) || (bh>55)); + } + + private static void spawnBlockAsEntity(Level world, BlockPos pos, ItemStack stack) { + if(world.isClientSide || stack.isEmpty() || (!world.getGameRules().getBoolean(GameRules.RULE_DOBLOCKDROPS)) || world.restoringBlockSnapshots) return; + ItemEntity e = new ItemEntity(world, + ((world.random.nextFloat()*0.1)+0.5) + pos.getX(), + ((world.random.nextFloat()*0.1)+0.5) + pos.getY(), + ((world.random.nextFloat()*0.1)+0.5) + pos.getZ(), + stack + ); + e.setDefaultPickUpDelay(); + e.setDeltaMovement((world.random.nextFloat()*0.1-0.05), (world.random.nextFloat()*0.1-0.03), (world.random.nextFloat()*0.1-0.05)); + world.addFreshEntity(e); + } + + private static boolean canInsertInto(Level world, BlockPos pos) + { + // Maybe make a tag for that. The question is if it is actually worth it, or if that would be only + // tag spamming the game. So for now only FH and VH. + final BlockState state = world.getBlockState(pos); + return (state.getBlock() == ModContent.FACTORY_HOPPER) || (state.getBlock() == Blocks.HOPPER); + } + + private boolean breakBlock(BlockState state, BlockPos pos, Level world) + { + if(world.isClientSide || (!(world instanceof ServerLevel)) || world.restoringBlockSnapshots) return false; // retry next cycle + List drops; + final Block block = state.getBlock(); + final boolean insert = canInsertInto(world, getBlockPos().below()); + drops = Block.getDrops(state, (ServerLevel)world, pos, world.getBlockEntity(pos)); + world.removeBlock(pos, false); + for(ItemStack drop:drops) { + if(!insert) { + spawnBlockAsEntity(world, pos, drop); + } else { + final ItemStack remaining = Inventories.insert(world, getBlockPos().below(), Direction.UP, drop, false); + if(!remaining.isEmpty()) spawnBlockAsEntity(world, pos, remaining); + } + } + SoundType stype = state.getBlock().getSoundType(state, world, pos, null); + if(stype != null) world.playSound(null, pos, stype.getPlaceSound(), SoundSource.BLOCKS, stype.getVolume()*0.6f, stype.getPitch()); + return true; + } + + @Override + @SuppressWarnings("deprecation") + public void tick() + { + if(--tick_timer_ > 0) return; + tick_timer_ = TICK_INTERVAL; + final BlockState device_state = level.getBlockState(worldPosition); + if(!(device_state.getBlock() instanceof BreakerBlock)) return; + final BlockPos target_pos = worldPosition.relative(device_state.getValue(BreakerBlock.HORIZONTAL_FACING)); + final BlockState target_state = level.getBlockState(target_pos); + if((level.hasNeighborSignal(worldPosition)) || (!isBreakable(target_state, target_pos, level))) { + if(device_state.getValue(BreakerBlock.ACTIVE)) level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, false), 1|2); + proc_time_elapsed_ = 0; + tick_timer_ = IDLE_TICK_INTERVAL; + return; + } + time_needed_ = Mth.clamp((int)(target_state.getDestroySpeed(level, worldPosition) * breaking_reluctance) + min_breaking_time, min_breaking_time, MAX_BREAKING_TIME); + if(battery_.draw(boost_energy_consumption)) { + proc_time_elapsed_ += TICK_INTERVAL * (1+BOOST_FACTOR); + time_needed_ += min_breaking_time * (3*BOOST_FACTOR/5); + active_timer_ = 2; + } else if(!requires_power) { + proc_time_elapsed_ += TICK_INTERVAL; + active_timer_ = 1024; + } else if(active_timer_ > 0) { + --active_timer_; + } + boolean active = (active_timer_ > 0); + if(requires_power && !active) { + proc_time_elapsed_ = Math.max(0, proc_time_elapsed_ - 2*TICK_INTERVAL); + } + if(proc_time_elapsed_ >= time_needed_) { + proc_time_elapsed_ = 0; + breakBlock(target_state, target_pos, level); + active = false; + } + if(device_state.getValue(BreakerBlock.ACTIVE) != active) { + level.setBlock(worldPosition, device_state.setValue(BreakerBlock.ACTIVE, active), 1|2); + } + } + + } +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdCatwalkBlock.java b/src/main/java/wile/engineersdecor/blocks/EdCatwalkBlock.java index 4422980..c32b3f3 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdCatwalkBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdCatwalkBlock.java @@ -1,131 +1,138 @@ -/* - * @file EdCatwalkBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Bottom aligned platforms with railings. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.Fluids; -import net.minecraft.item.*; -import net.minecraft.state.BooleanProperty; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.*; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.World; -import wile.engineersdecor.ModContent; -import wile.engineersdecor.libmc.detail.Inventories; - -import javax.annotation.Nullable; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - - -public class EdCatwalkBlock extends DecorBlock.HorizontalFourWayWaterLoggable implements IDecorBlock -{ - final Block railing_block; - final AxisAlignedBB base_aabb; - - public EdCatwalkBlock(long config, AbstractBlock.Properties properties, final AxisAlignedBB base_aabb, final AxisAlignedBB railing_aabb, final Block railing_block) - { super(config, properties, base_aabb, railing_aabb, 0); this.railing_block = railing_block; this.base_aabb=base_aabb; } - - @Override - public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos) - { return true; } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false); } - - public static boolean place_consume(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, int shrink) - { - if(!world.setBlock(pos, state, 1|2)) return false; - world.playSound(player, pos, SoundEvents.METAL_PLACE, SoundCategory.BLOCKS, 1f, 1f); - if((!player.isCreative()) && (!world.isClientSide())) { - ItemStack stack = player.getItemInHand(hand); - if(shrink >= 0) { - stack.shrink(shrink); - } else if(stack.getCount() < stack.getMaxStackSize()) { - stack.grow(Math.abs(shrink)); - } else { - Inventories.give(player, new ItemStack(stack.getItem(), Math.abs(shrink))); - } - Inventories.setItemInPlayerHand(player, hand, stack); - } - return true; - } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) - { - final Item item = player.getItemInHand(hand).getItem(); - if((!(item instanceof BlockItem))) return ActionResultType.PASS; - final Block block = ((BlockItem)item).getBlock(); - if(block == this) { - if(hit.getDirection().getAxis().isHorizontal()) return ActionResultType.PASS; // place new block on the clicked side. - BlockPos adjacent_pos = pos.relative(player.getDirection()); - BlockState adjacent_state = world.getBlockState(adjacent_pos); - if(adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) { - BlockState place_state = defaultBlockState(); - place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); - place_consume(place_state, world, adjacent_pos, player, hand, 1); - } - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } - if(block == railing_block) { - Direction face = hit.getDirection(); - final Vector3d rhv = hit.getLocation().subtract(Vector3d.atCenterOf(hit.getBlockPos())); - if(face.getAxis().isHorizontal()) { - // Side or railing clicked - if(rhv.multiply(Vector3d.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99) face = face.getOpposite(); // click on railing, not the outer side. - } else if(player.distanceToSqr(Vector3d.atCenterOf(pos)) < 3) { - // near accurate placement - face = Direction.getNearest(rhv.x, 0, rhv.z); - } else { - // far automatic placement - face = Direction.getNearest(player.getLookAngle().x, 0, player.getLookAngle().z); - List free_sides = Arrays.stream(Direction.values()).filter(d->d.getAxis().isHorizontal() && (world.getBlockState(pos.relative(d)).getBlock()!=this)).collect(Collectors.toList()); - if(free_sides.isEmpty()) return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - if(!free_sides.contains(face)) face = free_sides.get(0); - } - BooleanProperty railing = getDirectionProperty(face); - boolean add = (!state.getValue(railing)); - place_consume(state.setValue(railing, add), world, pos, player, hand, add ? 1 : -1); - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } - return ActionResultType.PASS; - } - - // -- IDecorBlock - - @Override - public boolean hasDynamicDropList() - { return true; } - - @Override - public List dropList(BlockState state, World world, @Nullable TileEntity te, boolean explosion) - { - if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY); - List drops = new ArrayList<>(); - drops.add(new ItemStack(state.getBlock().asItem())); - int n = (state.getValue(NORTH)?1:0)+(state.getValue(EAST)?1:0)+(state.getValue(SOUTH)?1:0)+(state.getValue(WEST)?1:0); - if(n > 0) drops.add(new ItemStack(ModContent.STEEL_RAILING, n)); - return drops; - } - -} +/* + * @file EdCatwalkBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Bottom aligned platforms with railings. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +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.player.Player; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.DirectionalPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import wile.engineersdecor.ModContent; +import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.detail.Inventories; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + + +public class EdCatwalkBlock extends StandardBlocks.HorizontalFourWayWaterLoggable +{ + final Block railing_block; + final AABB base_aabb; + + public EdCatwalkBlock(long config, BlockBehaviour.Properties properties, final AABB base_aabb, final AABB railing_aabb, final Block railing_block) + { super(config, properties, base_aabb, railing_aabb, 0); this.railing_block = railing_block; this.base_aabb=base_aabb; } + + @Override + public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) + { return true; } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { return super.getStateForPlacement(context).setValue(NORTH, false).setValue(EAST, false).setValue(SOUTH, false).setValue(WEST, false); } + + public static boolean place_consume(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, int shrink) + { + if(!world.setBlock(pos, state, 1|2)) return false; + world.playSound(player, pos, SoundEvents.METAL_PLACE, SoundSource.BLOCKS, 1f, 1f); + if((!player.isCreative()) && (!world.isClientSide())) { + ItemStack stack = player.getItemInHand(hand); + if(shrink >= 0) { + stack.shrink(shrink); + } else if(stack.getCount() < stack.getMaxStackSize()) { + stack.grow(Math.abs(shrink)); + } else { + Inventories.give(player, new ItemStack(stack.getItem(), Math.abs(shrink))); + } + Inventories.setItemInPlayerHand(player, hand, stack); + } + return true; + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + final Item item = player.getItemInHand(hand).getItem(); + if((!(item instanceof BlockItem))) return InteractionResult.PASS; + final Block block = ((BlockItem)item).getBlock(); + if(block == this) { + if(hit.getDirection().getAxis().isHorizontal()) return InteractionResult.PASS; // place new block on the clicked side. + BlockPos adjacent_pos = pos.relative(player.getDirection()); + BlockState adjacent_state = world.getBlockState(adjacent_pos); + if(adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) { + BlockState place_state = defaultBlockState(); + place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); + place_consume(place_state, world, adjacent_pos, player, hand, 1); + } + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + if(block == railing_block) { + Direction face = hit.getDirection(); + final Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos())); + if(face.getAxis().isHorizontal()) { + // Side or railing clicked + if(rhv.multiply(Vec3.atLowerCornerOf(face.getNormal())).scale(2).lengthSqr() < 0.99) face = face.getOpposite(); // click on railing, not the outer side. + } else if(player.distanceToSqr(Vec3.atCenterOf(pos)) < 3) { + // near accurate placement + face = Direction.getNearest(rhv.x, 0, rhv.z); + } else { + // far automatic placement + face = Direction.getNearest(player.getLookAngle().x, 0, player.getLookAngle().z); + List free_sides = Arrays.stream(Direction.values()).filter(d->d.getAxis().isHorizontal() && (world.getBlockState(pos.relative(d)).getBlock()!=this)).collect(Collectors.toList()); + if(free_sides.isEmpty()) return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + if(!free_sides.contains(face)) face = free_sides.get(0); + } + BooleanProperty railing = getDirectionProperty(face); + boolean add = (!state.getValue(railing)); + place_consume(state.setValue(railing, add), world, pos, player, hand, add ? 1 : -1); + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + return InteractionResult.PASS; + } + + @Override + public boolean hasDynamicDropList() + { return true; } + + @Override + public List dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) + { + if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY); + List drops = new ArrayList<>(); + drops.add(new ItemStack(state.getBlock().asItem())); + int n = (state.getValue(NORTH)?1:0)+(state.getValue(EAST)?1:0)+(state.getValue(SOUTH)?1:0)+(state.getValue(WEST)?1:0); + if(n > 0) drops.add(new ItemStack(ModContent.STEEL_RAILING, n)); + return drops; + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdCatwalkStairsBlock.java b/src/main/java/wile/engineersdecor/blocks/EdCatwalkStairsBlock.java index dc440bc..c5069e3 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdCatwalkStairsBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdCatwalkStairsBlock.java @@ -1,183 +1,186 @@ -/* - * @file EdCatwalkStairsBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Stair version of the catwalk block, optional left/right railings. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.Fluids; -import net.minecraft.item.*; -import net.minecraft.state.BooleanProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.*; -import net.minecraft.util.Direction.Axis; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.shapes.IBooleanFunction; -import net.minecraft.util.math.shapes.ISelectionContext; -import net.minecraft.util.math.shapes.VoxelShape; -import net.minecraft.util.math.shapes.VoxelShapes; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.World; -import wile.engineersdecor.ModContent; -import wile.engineersdecor.libmc.detail.Auxiliaries; - -import javax.annotation.Nullable; -import java.util.*; - - - -public class EdCatwalkStairsBlock extends DecorBlock.HorizontalWaterLoggable implements IDecorBlock -{ - public static final BooleanProperty RIGHT_RAILING = BooleanProperty.create("right_railing"); - public static final BooleanProperty LEFT_RAILING = BooleanProperty.create("left_railing"); - protected final Map shapes; - protected final Map collision_shapes; - protected final Map y_rotations; - - public EdCatwalkStairsBlock(long config, AbstractBlock.Properties properties, final AxisAlignedBB[] base_aabb, final AxisAlignedBB[] railing_aabbs) - { - super(config, properties, base_aabb); - Map sh = new HashMap<>(); - Map csh = new HashMap<>(); - getStateDefinition().getPossibleStates().forEach(state->{ - Direction facing = state.getValue(HORIZONTAL_FACING); - VoxelShape base_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(base_aabb, facing, true)); - if(state.getValue(RIGHT_RAILING)) { - VoxelShape right_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(Auxiliaries.getMirroredAABB(railing_aabbs, Axis.X), facing, true)); - base_shape = VoxelShapes.joinUnoptimized(base_shape, right_shape, IBooleanFunction.OR); - } - if(state.getValue(LEFT_RAILING)) { - VoxelShape left_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(railing_aabbs, facing, true)); - base_shape = VoxelShapes.joinUnoptimized(base_shape, left_shape, IBooleanFunction.OR); - } - sh.put(state, base_shape); - csh.put(state, base_shape); - }); - shapes = sh; - collision_shapes = csh; - y_rotations = new HashMap<>(); - y_rotations.put(Direction.NORTH, 0); - y_rotations.put(Direction.EAST, 1); - y_rotations.put(Direction.SOUTH, 2); - y_rotations.put(Direction.WEST, 3); - y_rotations.put(Direction.UP, 0); - y_rotations.put(Direction.DOWN, 0); - registerDefaultState(super.defaultBlockState().setValue(LEFT_RAILING, false).setValue(RIGHT_RAILING, false)); - } - - @Override - public VoxelShape getShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) - { return shapes.getOrDefault(state, VoxelShapes.block()); } - - @Override - public VoxelShape getCollisionShape(BlockState state, IBlockReader worldIn, BlockPos pos, ISelectionContext context) - { return collision_shapes.getOrDefault(state, VoxelShapes.block()); } - - @Override - protected void createBlockStateDefinition(StateContainer.Builder builder) - { super.createBlockStateDefinition(builder); builder.add(RIGHT_RAILING, LEFT_RAILING); } - - @Override - public boolean propagatesSkylightDown(BlockState state, IBlockReader reader, BlockPos pos) - { return true; } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { return super.getStateForPlacement(context); } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) - { - final Item item = player.getItemInHand(hand).getItem(); - if((!(item instanceof BlockItem))) return ActionResultType.PASS; - final Block block = ((BlockItem)item).getBlock(); - final Direction facing = state.getValue(HORIZONTAL_FACING); - if(block == this) { - final Direction hlv = Arrays.stream(Direction.orderedByNearest(player)).filter(d->d.getAxis().isHorizontal()).findFirst().orElse(Direction.NORTH); - BlockPos adjacent_pos; - if(hlv == facing) { - adjacent_pos = pos.above().relative(hlv); - } else if(hlv == facing.getOpposite()) { - adjacent_pos = pos.below().relative(hlv); - } else { - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } - final BlockState adjacent_state = world.getBlockState(adjacent_pos); - if(adjacent_state == null) return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return ActionResultType.CONSUME; - BlockState place_state = defaultBlockState().setValue(HORIZONTAL_FACING, facing); - place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); - EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1); - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } else if((block == ModContent.STEEL_CATWALK) || (block == ModContent.STEEL_CATWALK_TOP_ALIGNED)) { - BlockPos adjacent_pos; - adjacent_pos = pos.relative(facing); - final BlockState adjacent_state = world.getBlockState(adjacent_pos); - if(adjacent_state == null) return ActionResultType.CONSUME; - if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return ActionResultType.CONSUME; - BlockState place_state = ModContent.STEEL_CATWALK_TOP_ALIGNED.defaultBlockState(); - place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); - EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1); - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } else if(block == ModContent.STEEL_RAILING) { - Direction face = hit.getDirection(); - int shrink = 0; - BlockState place_state = state; - if(face == Direction.UP) { - Vector3d rhv = hit.getLocation().subtract(Vector3d.atCenterOf(hit.getBlockPos())).multiply(new Vector3d(1,0,1)).cross(Vector3d.atLowerCornerOf(facing.getNormal())); - face = (rhv.y > 0) ? (facing.getClockWise()) : (facing.getCounterClockWise()); - } - if(face == facing.getClockWise()) { - if(state.getValue(RIGHT_RAILING)) { - place_state = state.setValue(RIGHT_RAILING, false); - shrink = -1; - } else { - place_state = state.setValue(RIGHT_RAILING, true); - shrink = 1; - } - } else if(face == facing.getCounterClockWise()) { - if(state.getValue(LEFT_RAILING)) { - place_state = state.setValue(LEFT_RAILING, false); - shrink = -1; - } else { - place_state = state.setValue(LEFT_RAILING, true); - shrink = 1; - } - } - if(shrink != 0) EdCatwalkBlock.place_consume(place_state, world, pos, player, hand, shrink); - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } - return ActionResultType.PASS; - } - - // -- IDecorBlock - - @Override - public boolean hasDynamicDropList() - { return true; } - - @Override - public List dropList(BlockState state, World world, @Nullable TileEntity te, boolean explosion) - { - if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY); - List drops = new ArrayList<>(); - drops.add(new ItemStack(state.getBlock().asItem())); - int n = (state.getValue(LEFT_RAILING)?1:0)+(state.getValue(RIGHT_RAILING)?1:0); - if(n > 0) drops.add(new ItemStack(ModContent.STEEL_RAILING, n)); - return drops; - } - -} +/* + * @file EdCatwalkStairsBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Stair version of the catwalk block, optional left/right railings. + */ +package wile.engineersdecor.blocks; + +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.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.DirectionalPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.BooleanOp; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import wile.engineersdecor.ModContent; +import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.detail.Auxiliaries; + +import javax.annotation.Nullable; +import java.util.*; + + +public class EdCatwalkStairsBlock extends StandardBlocks.HorizontalWaterLoggable +{ + public static final BooleanProperty RIGHT_RAILING = BooleanProperty.create("right_railing"); + public static final BooleanProperty LEFT_RAILING = BooleanProperty.create("left_railing"); + protected final Map shapes; + protected final Map collision_shapes; + protected final Map y_rotations; + + public EdCatwalkStairsBlock(long config, BlockBehaviour.Properties properties, final AABB[] base_aabb, final AABB[] railing_aabbs) + { + super(config, properties, base_aabb); + Map sh = new HashMap<>(); + Map csh = new HashMap<>(); + getStateDefinition().getPossibleStates().forEach(state->{ + Direction facing = state.getValue(HORIZONTAL_FACING); + VoxelShape base_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(base_aabb, facing, true)); + if(state.getValue(RIGHT_RAILING)) { + VoxelShape right_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(Auxiliaries.getMirroredAABB(railing_aabbs, Direction.Axis.X), facing, true)); + base_shape = Shapes.joinUnoptimized(base_shape, right_shape, BooleanOp.OR); + } + if(state.getValue(LEFT_RAILING)) { + VoxelShape left_shape = Auxiliaries.getUnionShape(Auxiliaries.getRotatedAABB(railing_aabbs, facing, true)); + base_shape = Shapes.joinUnoptimized(base_shape, left_shape, BooleanOp.OR); + } + sh.put(state, base_shape); + csh.put(state, base_shape); + }); + shapes = sh; + collision_shapes = csh; + y_rotations = new HashMap<>(); + y_rotations.put(Direction.NORTH, 0); + y_rotations.put(Direction.EAST, 1); + y_rotations.put(Direction.SOUTH, 2); + y_rotations.put(Direction.WEST, 3); + y_rotations.put(Direction.UP, 0); + y_rotations.put(Direction.DOWN, 0); + registerDefaultState(super.defaultBlockState().setValue(LEFT_RAILING, false).setValue(RIGHT_RAILING, false)); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) + { return shapes.getOrDefault(state, Shapes.block()); } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter worldIn, BlockPos pos, CollisionContext context) + { return collision_shapes.getOrDefault(state, Shapes.block()); } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) + { super.createBlockStateDefinition(builder); builder.add(RIGHT_RAILING, LEFT_RAILING); } + + @Override + public boolean propagatesSkylightDown(BlockState state, BlockGetter reader, BlockPos pos) + { return true; } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { return super.getStateForPlacement(context); } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + final Item item = player.getItemInHand(hand).getItem(); + if((!(item instanceof BlockItem))) return InteractionResult.PASS; + final Block block = ((BlockItem)item).getBlock(); + final Direction facing = state.getValue(HORIZONTAL_FACING); + if(block == this) { + final Direction hlv = Arrays.stream(Direction.orderedByNearest(player)).filter(d->d.getAxis().isHorizontal()).findFirst().orElse(Direction.NORTH); + BlockPos adjacent_pos; + if(hlv == facing) { + adjacent_pos = pos.above().relative(hlv); + } else if(hlv == facing.getOpposite()) { + adjacent_pos = pos.below().relative(hlv); + } else { + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + final BlockState adjacent_state = world.getBlockState(adjacent_pos); + if(adjacent_state == null) return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return InteractionResult.CONSUME; + BlockState place_state = defaultBlockState().setValue(HORIZONTAL_FACING, facing); + place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); + EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1); + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } else if((block == ModContent.STEEL_CATWALK) || (block == ModContent.STEEL_CATWALK_TOP_ALIGNED)) { + BlockPos adjacent_pos; + adjacent_pos = pos.relative(facing); + final BlockState adjacent_state = world.getBlockState(adjacent_pos); + if(adjacent_state == null) return InteractionResult.CONSUME; + if(!adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) return InteractionResult.CONSUME; + BlockState place_state = ModContent.STEEL_CATWALK_TOP_ALIGNED.defaultBlockState(); + place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); + EdCatwalkBlock.place_consume(place_state, world, adjacent_pos, player, hand, 1); + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } else if(block == ModContent.STEEL_RAILING) { + Direction face = hit.getDirection(); + int shrink = 0; + BlockState place_state = state; + if(face == Direction.UP) { + Vec3 rhv = hit.getLocation().subtract(Vec3.atCenterOf(hit.getBlockPos())).multiply(new Vec3(1,0,1)).cross(Vec3.atLowerCornerOf(facing.getNormal())); + face = (rhv.y > 0) ? (facing.getClockWise()) : (facing.getCounterClockWise()); + } + if(face == facing.getClockWise()) { + if(state.getValue(RIGHT_RAILING)) { + place_state = state.setValue(RIGHT_RAILING, false); + shrink = -1; + } else { + place_state = state.setValue(RIGHT_RAILING, true); + shrink = 1; + } + } else if(face == facing.getCounterClockWise()) { + if(state.getValue(LEFT_RAILING)) { + place_state = state.setValue(LEFT_RAILING, false); + shrink = -1; + } else { + place_state = state.setValue(LEFT_RAILING, true); + shrink = 1; + } + } + if(shrink != 0) EdCatwalkBlock.place_consume(place_state, world, pos, player, hand, shrink); + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + return InteractionResult.PASS; + } + + @Override + public boolean hasDynamicDropList() + { return true; } + + @Override + public List dropList(BlockState state, Level world, @Nullable BlockEntity te, boolean explosion) + { + if(world.isClientSide()) return Collections.singletonList(ItemStack.EMPTY); + List drops = new ArrayList<>(); + drops.add(new ItemStack(state.getBlock().asItem())); + int n = (state.getValue(LEFT_RAILING)?1:0)+(state.getValue(RIGHT_RAILING)?1:0); + if(n > 0) drops.add(new ItemStack(ModContent.STEEL_RAILING, n)); + return drops; + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdCatwalkTopAlignedBlock.java b/src/main/java/wile/engineersdecor/blocks/EdCatwalkTopAlignedBlock.java index 838b89b..770222e 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdCatwalkTopAlignedBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdCatwalkTopAlignedBlock.java @@ -1,106 +1,111 @@ -/* - * @file EdCatwalkTopAlignedBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Top aligned platforms, down-connection to poles. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.fluid.Fluids; -import net.minecraft.item.*; -import net.minecraft.state.IntegerProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.util.*; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.math.shapes.ISelectionContext; -import net.minecraft.util.math.shapes.VoxelShape; -import net.minecraft.util.math.shapes.VoxelShapes; -import net.minecraft.world.IBlockReader; -import net.minecraft.world.IWorld; -import net.minecraft.world.World; -import wile.engineersdecor.ModContent; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; - - -public class EdCatwalkTopAlignedBlock extends DecorBlock.WaterLoggable implements IDecorBlock -{ - public static final IntegerProperty VARIANT = IntegerProperty.create("variant", 0, 3); - protected final List variant_shapes; - - public EdCatwalkTopAlignedBlock(long config, AbstractBlock.Properties properties, final VoxelShape[] variant_shapes) - { - super(config, properties, variant_shapes[0]); - registerDefaultState(super.defaultBlockState().setValue(VARIANT, 0)); - this.variant_shapes = VARIANT.getPossibleValues().stream().map(i->(i builder) - { super.createBlockStateDefinition(builder); builder.add(VARIANT); } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { - BlockState state = adapted_state(super.getStateForPlacement(context), context.getLevel(), context.getClickedPos()); - if(context.getClickedFace() != Direction.UP) return state; - BlockState below = context.getLevel().getBlockState(context.getClickedPos().below()); - if((state.getValue(VARIANT)==0) && (below.isFaceSturdy(context.getLevel(), context.getClickedPos().below(), Direction.UP))) return state.setValue(VARIANT, 3); - return state; - } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult hit) - { - final Item item = player.getItemInHand(hand).getItem(); - if(item != this.asItem()) return ActionResultType.PASS; - if(hit.getDirection().getAxis().isHorizontal()) return ActionResultType.PASS; - BlockPos adjacent_pos = pos.relative(player.getDirection()); - BlockState adjacent_state = world.getBlockState(adjacent_pos); - if(adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) { - BlockState place_state = defaultBlockState(); - place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); - EdCatwalkBlock.place_consume(adapted_state(place_state, world, adjacent_pos), world, adjacent_pos, player, hand, 1); - } - return world.isClientSide() ? ActionResultType.SUCCESS : ActionResultType.CONSUME; - } - - @Override - public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, IWorld world, BlockPos pos, BlockPos facingPos) - { return adapted_state(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos); } - - // --- - - private BlockState adapted_state(BlockState state, IWorld world, BlockPos pos) - { - BlockState below = world.getBlockState(pos.below()); - if((below == null) || (state == null)) return state; - if((below.getBlock() == ModContent.THICK_STEEL_POLE) || (below.getBlock() == ModContent.THICK_STEEL_POLE_HEAD)) return state.setValue(VARIANT, 1); - if((below.getBlock() == ModContent.THIN_STEEL_POLE) || (below.getBlock() == ModContent.THIN_STEEL_POLE_HEAD)) return state.setValue(VARIANT, 2); - return state; - } - -} +/* + * @file EdCatwalkTopAlignedBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Top aligned platforms, down-connection to poles. + */ +package wile.engineersdecor.blocks; + +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.Item; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.context.DirectionalPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import wile.engineersdecor.ModContent; +import wile.engineersdecor.libmc.blocks.StandardBlocks; + +import javax.annotation.Nullable; +import java.util.List; +import java.util.stream.Collectors; + + +public class EdCatwalkTopAlignedBlock extends StandardBlocks.WaterLoggable +{ + public static final IntegerProperty VARIANT = IntegerProperty.create("variant", 0, 3); + protected final List variant_shapes; + + public EdCatwalkTopAlignedBlock(long config, BlockBehaviour.Properties properties, final VoxelShape[] variant_shapes) + { + super(config, properties, variant_shapes[0]); + registerDefaultState(super.defaultBlockState().setValue(VARIANT, 0)); + this.variant_shapes = VARIANT.getPossibleValues().stream().map(i->(i builder) + { super.createBlockStateDefinition(builder); builder.add(VARIANT); } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { + BlockState state = adapted_state(super.getStateForPlacement(context), context.getLevel(), context.getClickedPos()); + if(context.getClickedFace() != Direction.UP) return state; + BlockState below = context.getLevel().getBlockState(context.getClickedPos().below()); + if((state.getValue(VARIANT)==0) && (below.isFaceSturdy(context.getLevel(), context.getClickedPos().below(), Direction.UP))) return state.setValue(VARIANT, 3); + return state; + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) + { + final Item item = player.getItemInHand(hand).getItem(); + if(item != this.asItem()) return InteractionResult.PASS; + if(hit.getDirection().getAxis().isHorizontal()) return InteractionResult.PASS; + BlockPos adjacent_pos = pos.relative(player.getDirection()); + BlockState adjacent_state = world.getBlockState(adjacent_pos); + if(adjacent_state.canBeReplaced(new DirectionalPlaceContext(world, adjacent_pos, hit.getDirection().getOpposite(), player.getItemInHand(hand), hit.getDirection()))) { + BlockState place_state = defaultBlockState(); + place_state = place_state.setValue(WATERLOGGED,adjacent_state.getFluidState().getType()==Fluids.WATER); + EdCatwalkBlock.place_consume(adapted_state(place_state, world, adjacent_pos), world, adjacent_pos, player, hand, 1); + } + return world.isClientSide() ? InteractionResult.SUCCESS : InteractionResult.CONSUME; + } + + @Override + public BlockState updateShape(BlockState state, Direction facing, BlockState facingState, LevelAccessor world, BlockPos pos, BlockPos facingPos) + { return adapted_state(super.updateShape(state, facing, facingState, world, pos, facingPos), world, pos); } + + // --- + + private BlockState adapted_state(BlockState state, LevelAccessor world, BlockPos pos) + { + BlockState below = world.getBlockState(pos.below()); + if((below == null) || (state == null)) return state; + if((below.getBlock() == ModContent.THICK_STEEL_POLE) || (below.getBlock() == ModContent.THICK_STEEL_POLE_HEAD)) return state.setValue(VARIANT, 1); + if((below.getBlock() == ModContent.THIN_STEEL_POLE) || (below.getBlock() == ModContent.THIN_STEEL_POLE_HEAD)) return state.setValue(VARIANT, 2); + return state; + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdChair.java b/src/main/java/wile/engineersdecor/blocks/EdChair.java index bc9cba2..cfbd0ef 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdChair.java +++ b/src/main/java/wile/engineersdecor/blocks/EdChair.java @@ -1,195 +1,204 @@ -/* - * @file EdChair.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Full block characteristics class. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.entity.monster.piglin.PiglinEntity; -import net.minecraft.util.math.vector.Vector3d; -import net.minecraft.block.AbstractBlock; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.World; -import net.minecraft.block.BlockState; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.*; -import net.minecraft.entity.monster.*; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.IPacket; -import net.minecraft.util.math.*; -import net.minecraft.util.*; -import net.minecraftforge.fml.network.FMLPlayMessages; -import net.minecraftforge.fml.network.NetworkHooks; -import wile.engineersdecor.ModConfig; -import wile.engineersdecor.ModContent; -import java.util.List; -import java.util.Random; - - - -public class EdChair -{ - private static boolean sitting_enabled = true; - private static double sitting_probability = 0.1; - private static double standup_probability = 0.01; - - public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent) - { - sitting_enabled = (!without_sitting); - sitting_probability = (without_sitting||without_mob_sitting) ? 0.0 : MathHelper.clamp(sitting_probability_percent/100, 0, 0.9); - standup_probability = (without_sitting||without_mob_sitting) ? 1.0 : MathHelper.clamp(standup_probability_percent/100, 1e-6, 1e-2); - ModConfig.log("Config chairs: sit:" + sitting_enabled + ", mob-sit: " + (sitting_probability*100) + "%, standup: " + (standup_probability) + "%."); - } - - //-------------------------------------------------------------------------------------------------------------------- - // Block - //-------------------------------------------------------------------------------------------------------------------- - - public static class ChairBlock extends DecorBlock.HorizontalWaterLoggable implements IDecorBlock - { - public ChairBlock(long config, AbstractBlock.Properties builder, final AxisAlignedBB[] unrotatedAABBs) - { super(config, builder.randomTicks(), unrotatedAABBs); } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult) - { - if(!sitting_enabled) return ActionResultType.PASS; - if(world.isClientSide()) return ActionResultType.SUCCESS; - EntityChair.sit(world, player, pos); - return ActionResultType.CONSUME; - } - - @Override - @SuppressWarnings("deprecation") - public void entityInside(BlockState state, World world, BlockPos pos, Entity entity) - { - if(sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof MobEntity)) EntityChair.sit(world, (LivingEntity)entity, pos); - } - - @Override - @SuppressWarnings("deprecation") - public void tick(BlockState state, ServerWorld world, BlockPos pos, Random rnd) - { - if((!sitting_enabled) || (sitting_probability < 1e-6)) return; - final List entities = world.getEntitiesOfClass(MobEntity.class, new AxisAlignedBB(pos).inflate(2,1,2).expandTowards(0,1,0), e->true); - if(entities.isEmpty()) return; - int index = rnd.nextInt(entities.size()); - if((index < 0) || (index >= entities.size())) return; - EntityChair.sit(world, entities.get(index), pos); - } - } - - //-------------------------------------------------------------------------------------------------------------------- - // Entity - //-------------------------------------------------------------------------------------------------------------------- - - public static class EntityChair extends Entity - { - public static final double x_offset = 0.5d; - public static final double y_offset = 0.4d; - public static final double z_offset = 0.5d; - private int t_sit = 0; - public BlockPos chair_pos = new BlockPos(0,0,0); - - public EntityChair(EntityType entityType, World world) - { - super(entityType, world); - blocksBuilding=true; - setDeltaMovement(Vector3d.ZERO); - canUpdate(true); - noPhysics=true; - } - - public EntityChair(World world) - { this(ModContent.ET_CHAIR, world); } - - public static EntityChair customClientFactory(FMLPlayMessages.SpawnEntity spkt, World world) - { return new EntityChair(world); } - - public IPacket getAddEntityPacket() - { return NetworkHooks.getEntitySpawningPacket(this); } - - public static boolean accepts_mob(LivingEntity entity) - { - if(!(entity instanceof net.minecraft.entity.monster.MonsterEntity)) return false; - if((entity.getType().getDimensions().height > 2.5) || (entity.getType().getDimensions().height > 2.0)) return false; - if(entity instanceof ZombieEntity) return true; - if(entity instanceof ZombieVillagerEntity) return true; - if(entity instanceof ZombifiedPiglinEntity) return true; - if(entity instanceof PiglinEntity) return true; - if(entity instanceof HuskEntity) return true; - if(entity instanceof StrayEntity) return true; - if(entity instanceof SkeletonEntity) return true; - if(entity instanceof WitherSkeletonEntity) return true; - return false; - } - - public static void sit(World world, LivingEntity sitter, BlockPos pos) - { - if(!sitting_enabled) return; - if((world==null) || (world.isClientSide) || (sitter==null) || (pos==null)) return; - if((!(sitter instanceof PlayerEntity)) && (!accepts_mob(sitter))) return; - if(!world.getEntitiesOfClass(EntityChair.class, new AxisAlignedBB(pos)).isEmpty()) return; - if(sitter.isVehicle() || (!sitter.isAlive()) || (sitter.isPassenger()) ) return; - if((!world.isEmptyBlock(pos.above())) || (!world.isEmptyBlock(pos.above(2)))) return; - boolean on_top_of_block_position = true; - boolean use_next_negative_y_position = false; - EntityChair chair = new EntityChair(world); - BlockPos chair_pos = chair.blockPosition(); - chair.chair_pos = pos; - chair.t_sit = 5; - chair.xo = chair_pos.getX(); - chair.yo = chair_pos.getY(); - chair.zo = chair_pos.getZ(); - chair.setPos(pos.getX()+x_offset,pos.getY()+y_offset,pos.getZ()+z_offset); - world.addFreshEntity(chair); - sitter.startRiding(chair, true); - } - - @Override - protected void defineSynchedData() {} - - @Override - protected void readAdditionalSaveData(CompoundNBT compound) {} - - @Override - protected void addAdditionalSaveData(CompoundNBT compound) {} - - @Override - public boolean isPushable() - { return false; } - - @Override - public double getPassengersRidingOffset() - { return 0.0; } - - @Override - public void tick() - { - if(level.isClientSide) return; - super.tick(); - if(--t_sit > 0) return; - Entity sitter = getPassengers().isEmpty() ? null : getPassengers().get(0); - if((sitter==null) || (!sitter.isAlive())) { - this.remove(); - return; - } - boolean abort = (!sitting_enabled); - final BlockState state = level.getBlockState(chair_pos); - if((state==null) || (!(state.getBlock() instanceof ChairBlock))) abort = true; - if(!level.isEmptyBlock(chair_pos.above())) abort = true; - if((!(sitter instanceof PlayerEntity)) && (Math.random() < standup_probability)) abort = true; - if(abort) { - for(Entity e:getPassengers()) { - if(e.isAlive()) e.stopRiding(); - } - this.remove(); - } - } - } - -} +/* + * @file EdChair.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Full block characteristics class. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.protocol.Packet; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.Mth; +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.Mob; +import net.minecraft.world.entity.monster.*; +import net.minecraft.world.entity.monster.piglin.Piglin; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraftforge.fmllegacy.network.FMLPlayMessages; +import net.minecraftforge.fmllegacy.network.NetworkHooks; +import wile.engineersdecor.ModConfig; +import wile.engineersdecor.ModContent; +import wile.engineersdecor.libmc.blocks.StandardBlocks; + +import java.util.List; +import java.util.Random; + + + +public class EdChair +{ + private static boolean sitting_enabled = true; + private static double sitting_probability = 0.1; + private static double standup_probability = 0.01; + + public static void on_config(boolean without_sitting, boolean without_mob_sitting, double sitting_probability_percent, double standup_probability_percent) + { + sitting_enabled = (!without_sitting); + sitting_probability = (without_sitting||without_mob_sitting) ? 0.0 : Mth.clamp(sitting_probability_percent/100, 0, 0.9); + standup_probability = (without_sitting||without_mob_sitting) ? 1.0 : Mth.clamp(standup_probability_percent/100, 1e-6, 1e-2); + ModConfig.log("Config chairs: sit:" + sitting_enabled + ", mob-sit: " + (sitting_probability*100) + "%, standup: " + (standup_probability) + "%."); + } + + //-------------------------------------------------------------------------------------------------------------------- + // Block + //-------------------------------------------------------------------------------------------------------------------- + + public static class ChairBlock extends StandardBlocks.HorizontalWaterLoggable + { + public ChairBlock(long config, BlockBehaviour.Properties builder, final AABB[] unrotatedAABBs) + { super(config, builder.randomTicks(), unrotatedAABBs); } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) + { + if(!sitting_enabled) return InteractionResult.PASS; + if(world.isClientSide()) return InteractionResult.SUCCESS; + EntityChair.sit(world, player, pos); + return InteractionResult.CONSUME; + } + + @Override + @SuppressWarnings("deprecation") + public void entityInside(BlockState state, Level world, BlockPos pos, Entity entity) + { + if(sitting_enabled && (Math.random() < sitting_probability) && (entity instanceof Mob)) EntityChair.sit(world, (LivingEntity)entity, pos); + } + + @Override + @SuppressWarnings("deprecation") + public void tick(BlockState state, ServerLevel world, BlockPos pos, Random rnd) + { + if((!sitting_enabled) || (sitting_probability < 1e-6)) return; + final List entities = world.getEntitiesOfClass(Mob.class, new AABB(pos).inflate(2,1,2).expandTowards(0,1,0), e->true); + if(entities.isEmpty()) return; + int index = rnd.nextInt(entities.size()); + if((index < 0) || (index >= entities.size())) return; + EntityChair.sit(world, entities.get(index), pos); + } + } + + //-------------------------------------------------------------------------------------------------------------------- + // Entity + //-------------------------------------------------------------------------------------------------------------------- + + public static class EntityChair extends Entity + { + public static final double x_offset = 0.5d; + public static final double y_offset = 0.4d; + public static final double z_offset = 0.5d; + private int t_sit = 0; + public BlockPos chair_pos = new BlockPos(0,0,0); + + public EntityChair(EntityType entityType, Level world) + { + super(entityType, world); + blocksBuilding=true; + setDeltaMovement(Vec3.ZERO); + canUpdate(true); + noPhysics=true; + } + + public EntityChair(Level world) + { this(ModContent.ET_CHAIR, world); } + + public static EntityChair customClientFactory(FMLPlayMessages.SpawnEntity spkt, Level world) + { return new EntityChair(world); } + + public Packet getAddEntityPacket() + { return NetworkHooks.getEntitySpawningPacket(this); } + + public static boolean accepts_mob(LivingEntity entity) + { + if(!(entity instanceof Monster)) return false; + if((entity.getType().getDimensions().height > 2.5) || (entity.getType().getDimensions().height > 2.0)) return false; + if(entity instanceof Zombie) return true; + if(entity instanceof ZombieVillager) return true; + if(entity instanceof ZombifiedPiglin) return true; + if(entity instanceof Piglin) return true; + if(entity instanceof Husk) return true; + if(entity instanceof Stray) return true; + if(entity instanceof Skeleton) return true; + if(entity instanceof WitherSkeleton) return true; + return false; + } + + public static void sit(Level world, LivingEntity sitter, BlockPos pos) + { + if(!sitting_enabled) return; + if((world==null) || (world.isClientSide) || (sitter==null) || (pos==null)) return; + if((!(sitter instanceof Player)) && (!accepts_mob(sitter))) return; + if(!world.getEntitiesOfClass(EntityChair.class, new AABB(pos)).isEmpty()) return; + if(sitter.isVehicle() || (!sitter.isAlive()) || (sitter.isPassenger()) ) return; + if((!world.isEmptyBlock(pos.above())) || (!world.isEmptyBlock(pos.above(2)))) return; + boolean on_top_of_block_position = true; + boolean use_next_negative_y_position = false; + EntityChair chair = new EntityChair(world); + BlockPos chair_pos = chair.blockPosition(); + chair.chair_pos = pos; + chair.t_sit = 5; + chair.xo = chair_pos.getX(); + chair.yo = chair_pos.getY(); + chair.zo = chair_pos.getZ(); + chair.setPos(pos.getX()+x_offset,pos.getY()+y_offset,pos.getZ()+z_offset); + world.addFreshEntity(chair); + sitter.startRiding(chair, true); + } + + @Override + protected void defineSynchedData() {} + + @Override + protected void readAdditionalSaveData(CompoundTag compound) {} + + @Override + protected void addAdditionalSaveData(CompoundTag compound) {} + + @Override + public boolean isPushable() + { return false; } + + @Override + public double getPassengersRidingOffset() + { return 0.0; } + + @Override + public void tick() + { + if(level.isClientSide) return; + super.tick(); + if(--t_sit > 0) return; + Entity sitter = getPassengers().isEmpty() ? null : getPassengers().get(0); + if((sitter==null) || (!sitter.isAlive())) { + this.remove(RemovalReason.DISCARDED); + return; + } + boolean abort = (!sitting_enabled); + final BlockState state = level.getBlockState(chair_pos); + if((state==null) || (!(state.getBlock() instanceof ChairBlock))) abort = true; + if(!level.isEmptyBlock(chair_pos.above())) abort = true; + if((!(sitter instanceof Player)) && (Math.random() < standup_probability)) abort = true; + if(abort) { + for(Entity e:getPassengers()) { + if(e.isAlive()) e.stopRiding(); + } + this.remove(RemovalReason.DISCARDED); + } + } + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdChimneyBlock.java b/src/main/java/wile/engineersdecor/blocks/EdChimneyBlock.java index 20b243b..d3d08a4 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdChimneyBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdChimneyBlock.java @@ -1,98 +1,101 @@ -/* - * @file EdChimneyBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Block type for smoking chimneys. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.*; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.particles.ParticleTypes; -import net.minecraft.state.IntegerProperty; -import net.minecraft.state.StateContainer; -import net.minecraft.state.properties.BlockStateProperties; -import net.minecraft.util.ActionResultType; -import net.minecraft.util.Direction; -import net.minecraft.util.Hand; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.world.IWorldReader; -import net.minecraft.world.World; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; - -import javax.annotation.Nullable; -import java.util.Random; - -public class EdChimneyBlock extends DecorBlock.Cutout implements IDecorBlock -{ - public static final IntegerProperty POWER = BlockStateProperties.POWER; - - public EdChimneyBlock(long config, AbstractBlock.Properties properties, AxisAlignedBB aabb) - { super(config, properties, aabb); } - - public EdChimneyBlock(long config, AbstractBlock.Properties builder) - { - this(config, builder, new AxisAlignedBB(0,0,0,1,1,1)); - registerDefaultState(super.defaultBlockState().setValue(POWER, 0)); // no smoke in JEI - } - - @Override - protected void createBlockStateDefinition(StateContainer.Builder builder) - { super.createBlockStateDefinition(builder); builder.add(POWER); } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { - BlockState state = super.getStateForPlacement(context); - if(state==null) return state; - int p = context.getLevel().getBestNeighborSignal(context.getClickedPos()); - return state.setValue(POWER, p==0 ? 5 : p); - } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult) - { world.setBlock(pos, state.setValue(POWER, (state.getValue(POWER)+1) & 0xf), 1|2); return ActionResultType.sidedSuccess(world.isClientSide()); } - - @Override - @SuppressWarnings("deprecation") - public void neighborChanged(BlockState state, World world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) - { - int p = world.getBestNeighborSignal(pos); - if(p != state.getValue(POWER)) world.setBlock(pos, state.setValue(POWER, p), 2); - } - - @Override - public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side) - { return false; } - - @Override - @OnlyIn(Dist.CLIENT) - public void animateTick(BlockState state, World world, BlockPos pos, Random rnd) - { - if(state.getBlock() != this) return; - final int p = state.getValue(POWER); - if(p==0) return; - int end = 1+rnd.nextInt(10) * p / 15; - for(int i=0; i 0.7 ? ParticleTypes.LARGE_SMOKE : (rv>0.4 ? ParticleTypes.SMOKE : ParticleTypes.CAMPFIRE_COSY_SMOKE)), - 0.5+pos.getX()+(rnd.nextDouble()*0.2), - 0.9+pos.getY()+(rnd.nextDouble()*0.1), - 0.5+pos.getZ()+(rnd.nextDouble()*0.2), - -0.02 + rnd.nextDouble()*0.04, - +0.05 + rnd.nextDouble()*0.1, - -0.02 + rnd.nextDouble()*0.04 - ); - } - } - -} +/* + * @file EdChimneyBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Block type for smoking chimneys. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.context.BlockPlaceContext; +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.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.IntegerProperty; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import wile.engineersdecor.libmc.blocks.StandardBlocks; + +import javax.annotation.Nullable; +import java.util.Random; + +public class EdChimneyBlock extends StandardBlocks.Cutout +{ + public static final IntegerProperty POWER = BlockStateProperties.POWER; + + public EdChimneyBlock(long config, BlockBehaviour.Properties properties, AABB aabb) + { super(config, properties, aabb); } + + public EdChimneyBlock(long config, BlockBehaviour.Properties builder) + { + this(config, builder, new AABB(0,0,0,1,1,1)); + registerDefaultState(super.defaultBlockState().setValue(POWER, 0)); // no smoke in JEI + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) + { super.createBlockStateDefinition(builder); builder.add(POWER); } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { + BlockState state = super.getStateForPlacement(context); + if(state==null) return state; + int p = context.getLevel().getBestNeighborSignal(context.getClickedPos()); + return state.setValue(POWER, p==0 ? 5 : p); + } + + @Override + @SuppressWarnings("deprecation") + public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) + { world.setBlock(pos, state.setValue(POWER, (state.getValue(POWER)+1) & 0xf), 1|2); return InteractionResult.sidedSuccess(world.isClientSide()); } + + @Override + @SuppressWarnings("deprecation") + public void neighborChanged(BlockState state, Level world, BlockPos pos, Block block, BlockPos fromPos, boolean unused) + { + int p = world.getBestNeighborSignal(pos); + if(p != state.getValue(POWER)) world.setBlock(pos, state.setValue(POWER, p), 2); + } + + @Override + public boolean shouldCheckWeakPower(BlockState state, LevelReader world, BlockPos pos, Direction side) + { return false; } + + @Override + @OnlyIn(Dist.CLIENT) + public void animateTick(BlockState state, Level world, BlockPos pos, Random rnd) + { + if(state.getBlock() != this) return; + final int p = state.getValue(POWER); + if(p==0) return; + int end = 1+rnd.nextInt(10) * p / 15; + for(int i=0; i 0.7 ? ParticleTypes.LARGE_SMOKE : (rv>0.4 ? ParticleTypes.SMOKE : ParticleTypes.CAMPFIRE_COSY_SMOKE)), + 0.5+pos.getX()+(rnd.nextDouble()*0.2), + 0.9+pos.getY()+(rnd.nextDouble()*0.1), + 0.5+pos.getZ()+(rnd.nextDouble()*0.2), + -0.02 + rnd.nextDouble()*0.04, + +0.05 + rnd.nextDouble()*0.1, + -0.02 + rnd.nextDouble()*0.04 + ); + } + } + +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdChimneyTrunkBlock.java b/src/main/java/wile/engineersdecor/blocks/EdChimneyTrunkBlock.java index 7a0fc2d..8fef447 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdChimneyTrunkBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdChimneyTrunkBlock.java @@ -1,36 +1,37 @@ -/* - * @file EdChimneyTrunkBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Roof block with chimney trunk, only straight. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.*; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.state.properties.Half; -import net.minecraft.state.properties.StairsShape; -import net.minecraft.util.math.shapes.VoxelShape; -import net.minecraft.util.math.shapes.VoxelShapes; - -import javax.annotation.Nullable; - - -public class EdChimneyTrunkBlock extends EdRoofBlock implements IDecorBlock -{ - public EdChimneyTrunkBlock(long config, AbstractBlock.Properties properties) - { super(config, properties.dynamicShape(), VoxelShapes.empty(), VoxelShapes.empty()); } - - public EdChimneyTrunkBlock(long config, AbstractBlock.Properties properties, VoxelShape add, VoxelShape cut) - { super(config, properties, add, cut); } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { - BlockState state = super.getStateForPlacement(context); - return (state==null) ? (state) : (state.setValue(EdRoofBlock.SHAPE, StairsShape.STRAIGHT).setValue(EdRoofBlock.HALF, Half.BOTTOM)); - } -} +/* + * @file EdChimneyTrunkBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Roof block with chimney trunk, only straight. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Half; +import net.minecraft.world.level.block.state.properties.StairsShape; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +import javax.annotation.Nullable; + + +public class EdChimneyTrunkBlock extends EdRoofBlock +{ + public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties) + { super(config, properties.dynamicShape(), Shapes.empty(), Shapes.empty()); } + + public EdChimneyTrunkBlock(long config, BlockBehaviour.Properties properties, VoxelShape add, VoxelShape cut) + { super(config, properties, add, cut); } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { + BlockState state = super.getStateForPlacement(context); + return (state==null) ? (state) : (state.setValue(EdRoofBlock.SHAPE, StairsShape.STRAIGHT).setValue(EdRoofBlock.HALF, Half.BOTTOM)); + } +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdCornerOrnamentedBlock.java b/src/main/java/wile/engineersdecor/blocks/EdCornerOrnamentedBlock.java index 2720229..e2357eb 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdCornerOrnamentedBlock.java +++ b/src/main/java/wile/engineersdecor/blocks/EdCornerOrnamentedBlock.java @@ -1,71 +1,72 @@ -/* - * @file EdCornerOrnamentedBlock.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Block for corner/quoin ornamentation. - */ -package wile.engineersdecor.blocks; - -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.item.BlockItemUseContext; -import net.minecraft.util.Direction; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.vector.Vector2f; -import net.minecraft.world.World; -import wile.engineersdecor.libmc.detail.Auxiliaries; - -import javax.annotation.Nullable; -import java.util.*; - - - -public class EdCornerOrnamentedBlock extends DecorBlock.Directed -{ - protected final HashSet compatible_blocks; - - public EdCornerOrnamentedBlock(long config, AbstractBlock.Properties properties, Block[] assigned_wall_blocks) - { - super(config, properties, Auxiliaries.getPixeledAABB(0,0,0,16,16,16)); - compatible_blocks = new HashSet(Arrays.asList(assigned_wall_blocks)); - } - - @Override - @Nullable - public BlockState getStateForPlacement(BlockItemUseContext context) - { - final World world = context.getLevel(); - final BlockPos pos = context.getClickedPos(); - // 1. Placement as below/above for corners, or placement adjacent horizontally if up/down facing. - for(Direction adj: Direction.values()) { - BlockState state = world.getBlockState(pos.relative(adj)); - if(state.getBlock() != this) continue; - Direction facing = state.getValue(FACING); - if(facing.getAxis().isHorizontal() == (adj.getAxis().isVertical())) { - return super.getStateForPlacement(context).setValue(FACING, state.getValue(FACING)); - } - } - // 2. By Player look angles with minimum horizontal diagonal deviation. - { - Direction facing = Direction.WEST; - final Vector2f look = context.getPlayer().getRotationVector(); - final Direction hit_face = context.getClickedFace(); - if((context.getClickedFace()==Direction.DOWN) && (look.x <= -60)) { - facing = Direction.DOWN; - } else if((context.getClickedFace()==Direction.UP) && (look.x >= 60)) { - facing = Direction.UP; - } else if(MathHelper.degreesDifferenceAbs(look.y, 45) <= 45) { - facing = Direction.NORTH; - } else if(MathHelper.degreesDifferenceAbs(look.y, 45+90) <= 45) { - facing = Direction.EAST; - } else if(MathHelper.degreesDifferenceAbs(look.y, 45+180) <= 45) { - facing = Direction.SOUTH; - } - return super.getStateForPlacement(context).setValue(FACING, facing); - } - } -} +/* + * @file EdCornerOrnamentedBlock.java + * @author Stefan Wilhelm (wile) + * @copyright (C) 2020 Stefan Wilhelm + * @license MIT (see https://opensource.org/licenses/MIT) + * + * Block for corner/quoin ornamentation. + */ +package wile.engineersdecor.blocks; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.Mth; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.phys.Vec2; +import wile.engineersdecor.libmc.blocks.StandardBlocks; +import wile.engineersdecor.libmc.detail.Auxiliaries; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.HashSet; + + +public class EdCornerOrnamentedBlock extends StandardBlocks.Directed +{ + protected final HashSet compatible_blocks; + + public EdCornerOrnamentedBlock(long config, BlockBehaviour.Properties properties, Block[] assigned_wall_blocks) + { + super(config, properties, Auxiliaries.getPixeledAABB(0,0,0,16,16,16)); + compatible_blocks = new HashSet<>(Arrays.asList(assigned_wall_blocks)); + } + + @Override + @Nullable + public BlockState getStateForPlacement(BlockPlaceContext context) + { + final Level world = context.getLevel(); + final BlockPos pos = context.getClickedPos(); + // 1. Placement as below/above for corners, or placement adjacent horizontally if up/down facing. + for(Direction adj: Direction.values()) { + BlockState state = world.getBlockState(pos.relative(adj)); + if(state.getBlock() != this) continue; + Direction facing = state.getValue(FACING); + if(facing.getAxis().isHorizontal() == (adj.getAxis().isVertical())) { + return super.getStateForPlacement(context).setValue(FACING, state.getValue(FACING)); + } + } + // 2. By Player look angles with minimum horizontal diagonal deviation. + { + Direction facing = Direction.WEST; + final Vec2 look = context.getPlayer().getRotationVector(); + final Direction hit_face = context.getClickedFace(); + if((context.getClickedFace()==Direction.DOWN) && (look.x <= -60)) { + facing = Direction.DOWN; + } else if((context.getClickedFace()==Direction.UP) && (look.x >= 60)) { + facing = Direction.UP; + } else if(Mth.degreesDifferenceAbs(look.y, 45) <= 45) { + facing = Direction.NORTH; + } else if(Mth.degreesDifferenceAbs(look.y, 45+90) <= 45) { + facing = Direction.EAST; + } else if(Mth.degreesDifferenceAbs(look.y, 45+180) <= 45) { + facing = Direction.SOUTH; + } + return super.getStateForPlacement(context).setValue(FACING, facing); + } + } +} diff --git a/src/main/java/wile/engineersdecor/blocks/EdCraftingTable.java b/src/main/java/wile/engineersdecor/blocks/EdCraftingTable.java index 428ae45..31d025b 100644 --- a/src/main/java/wile/engineersdecor/blocks/EdCraftingTable.java +++ b/src/main/java/wile/engineersdecor/blocks/EdCraftingTable.java @@ -1,1681 +1,1625 @@ -/* - * @file EdCraftingTable.java - * @author Stefan Wilhelm (wile) - * @copyright (C) 2020 Stefan Wilhelm - * @license MIT (see https://opensource.org/licenses/MIT) - * - * Crafting table - */ -package wile.engineersdecor.blocks; - -import net.minecraft.inventory.container.*; -import net.minecraft.network.NetworkManager; -import net.minecraft.network.play.server.SUpdateTileEntityPacket; -import net.minecraft.world.*; -import net.minecraft.block.AbstractBlock; -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.tileentity.TileEntityType; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.item.Item; -import net.minecraft.item.Items; -import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.*; -import net.minecraft.inventory.*; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.util.*; -import net.minecraft.util.math.AxisAlignedBB; -import net.minecraft.util.math.BlockPos; -import net.minecraft.util.math.MathHelper; -import net.minecraft.util.text.ITextComponent; -import net.minecraft.util.math.BlockRayTraceResult; -import net.minecraft.util.text.StringTextComponent; -import net.minecraft.client.gui.widget.button.ImageButton; -import net.minecraft.client.gui.widget.button.Button; -import net.minecraft.client.renderer.ItemRenderer; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.fml.network.NetworkHooks; -import net.minecraftforge.common.util.FakePlayer; -import net.minecraftforge.registries.ForgeRegistries; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.api.distmarker.OnlyIn; -import com.mojang.blaze3d.systems.RenderSystem; -import com.google.common.collect.ImmutableList; -import com.mojang.blaze3d.matrix.MatrixStack; -import wile.engineersdecor.ModConfig; -import wile.engineersdecor.ModContent; -import wile.engineersdecor.ModEngineersDecor; -import wile.engineersdecor.libmc.client.ContainerGui; -import wile.engineersdecor.libmc.detail.Auxiliaries; -import wile.engineersdecor.libmc.detail.Inventories; -import wile.engineersdecor.libmc.detail.Inventories.InventoryRange; -import wile.engineersdecor.libmc.detail.Inventories.StorageInventory; -import wile.engineersdecor.libmc.detail.Networking; -import wile.engineersdecor.libmc.detail.TooltipDisplay; -import wile.engineersdecor.libmc.detail.TooltipDisplay.TipRange; - -import javax.annotation.Nullable; -import java.util.*; -import java.util.stream.Collectors; -import java.util.Arrays; - - - -public class EdCraftingTable -{ - public static boolean with_assist = true; - public static boolean with_assist_direct_history_refab = false; - public static boolean with_crafting_slot_mouse_scrolling = true; - public static boolean with_outslot_defined_refab = true; - - public static final void on_config(boolean without_crafting_assist, boolean with_assist_immediate_history_refab, - boolean without_crafting_slot_mouse_scrolling) - { - with_assist = !without_crafting_assist; - with_assist_direct_history_refab = with_assist_immediate_history_refab; - with_crafting_slot_mouse_scrolling = !without_crafting_slot_mouse_scrolling; - with_outslot_defined_refab = with_assist; - CraftingHistory.max_history_size(32); - ModConfig.log("Config crafting table: assist:" + with_assist + ", direct-refab:" + with_assist_direct_history_refab + - ", scrolling:"+with_crafting_slot_mouse_scrolling); - } - - //-------------------------------------------------------------------------------------------------------------------- - // Block - //-------------------------------------------------------------------------------------------------------------------- - - public static final class CraftingTableBlock extends DecorBlock.HorizontalWaterLoggable implements IDecorBlock - { - public CraftingTableBlock(long config, AbstractBlock.Properties builder, final AxisAlignedBB[] unrotatedAABBs) - { super(config, builder, unrotatedAABBs); } - - @Override - public boolean shouldCheckWeakPower(BlockState state, IWorldReader world, BlockPos pos, Direction side) - { return false; } - - @Override - public boolean hasTileEntity(BlockState state) - { return true; } - - @Override - @Nullable - public TileEntity createTileEntity(BlockState state, IBlockReader world) - { return new EdCraftingTable.CraftingTableTileEntity(); } - - @Override - @SuppressWarnings("deprecation") - public ActionResultType use(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockRayTraceResult rayTraceResult) - { - if(world.isClientSide()) return ActionResultType.SUCCESS; - final TileEntity te = world.getBlockEntity(pos); - if(!(te instanceof CraftingTableTileEntity)) return ActionResultType.FAIL; - if((!(player instanceof ServerPlayerEntity) && (!(player instanceof FakePlayer)))) return ActionResultType.FAIL; - NetworkHooks.openGui((ServerPlayerEntity)player,(INamedContainerProvider)te); - return ActionResultType.CONSUME; - } - - @Override - public void setPlacedBy(World world, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) - { - if(world.isClientSide) return; - if(!stack.hasTag()) return; - if((!stack.hasTag()) || (!stack.getTag().contains("inventory"))) return; - CompoundNBT inventory_nbt = stack.getTag().getCompound("inventory"); - if(inventory_nbt.isEmpty()) return; - final TileEntity te = world.getBlockEntity(pos); - if(!(te instanceof CraftingTableTileEntity)) return; - ((CraftingTableTileEntity)te).readnbt(inventory_nbt); - ((CraftingTableTileEntity)te).setChanged(); - } - - @Override - public boolean hasDynamicDropList() - { return true; } - - @Override - public List dropList(BlockState state, World world, final TileEntity te, boolean explosion) - { - final List stacks = new ArrayList(); - if(world.isClientSide) return stacks; - if(!(te instanceof CraftingTableTileEntity)) return stacks; - if(!explosion) { - ItemStack stack = new ItemStack(this, 1); - CompoundNBT inventory_nbt = new CompoundNBT(); - ((CraftingTableTileEntity)te).mainInventory().save(inventory_nbt, false); - if(!inventory_nbt.isEmpty()) { - CompoundNBT nbt = new CompoundNBT(); - nbt.put("inventory", inventory_nbt); - stack.setTag(nbt); - } - ((CraftingTableTileEntity) te).mainInventory().clearContent(); - stacks.add(stack); - } else { - for(ItemStack stack: ((CraftingTableTileEntity)te).mainInventory()) { - if(!stack.isEmpty()) stacks.add(stack); - } - ((CraftingTableTileEntity)te).reset(); - } - return stacks; - } - - @Override - @SuppressWarnings("deprecation") - public void tick(BlockState state, ServerWorld world, BlockPos pos, Random rand) - { - TileEntity te = world.getBlockEntity(pos); - if(!(te instanceof CraftingTableTileEntity)) return; - ((CraftingTableTileEntity)te).sync(); - } - } - - //-------------------------------------------------------------------------------------------------------------------- - // Tile entity - //-------------------------------------------------------------------------------------------------------------------- - - public static class CraftingTableTileEntity extends TileEntity implements INameable, INamedContainerProvider, Networking.IPacketTileNotifyReceiver - { - public static final int NUM_OF_STORAGE_SLOTS = 18; - public static final int NUM_OF_STORAGE_ROWS = 2; - public static final int NUM_OF_SLOTS = 9+NUM_OF_STORAGE_SLOTS+1; - public static final int CRAFTING_RESULT_SLOT = NUM_OF_SLOTS-1; - - protected Inventories.StorageInventory inventory_; - protected CompoundNBT history = new CompoundNBT(); - - public CraftingTableTileEntity() - { this(ModContent.TET_CRAFTING_TABLE); } - - public CraftingTableTileEntity(TileEntityType te_type) - { - super(te_type); - inventory_ = new StorageInventory(this, NUM_OF_SLOTS, 1); - inventory_.setCloseAction((player)->{ - if(getLevel() instanceof World) { - scheduleSync(); - BlockState state = getBlockState(); - getLevel().sendBlockUpdated(getBlockPos(), state, state, 1|2|16); - } - }); - inventory_.setSlotChangeAction((slot_index,stack)-> { - if(slot_index < 9) scheduleSync(); - }); - } - - public void reset() - { inventory_.clearContent(); } - - public void readnbt(CompoundNBT nbt) - { reset(); inventory_.load(nbt); history = nbt.getCompound("history"); } - - private void writenbt(CompoundNBT nbt) - { - inventory_.save(nbt); - if(!history.isEmpty()) nbt.put("history", history); - } - - public Inventories.StorageInventory mainInventory() - { return inventory_; } - - // TileEntity ------------------------------------------------------------------------------ - - @Override - public void load(BlockState state, CompoundNBT nbt) - { super.load(state, nbt); readnbt(nbt); } - - @Override - public CompoundNBT save(CompoundNBT nbt) - { super.save(nbt); writenbt(nbt); return nbt; } - - @Override - public CompoundNBT getUpdateTag() - { CompoundNBT nbt = super.getUpdateTag(); writenbt(nbt); return nbt; } - - @Override - @Nullable - public SUpdateTileEntityPacket getUpdatePacket() - { return new SUpdateTileEntityPacket(worldPosition, 1, getUpdateTag()); } - - @Override - public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) // on client - { readnbt(pkt.getTag()); super.onDataPacket(net, pkt); } - - @Override - public void handleUpdateTag(BlockState state, CompoundNBT tag) // on client - { load(state, tag); } - - @OnlyIn(Dist.CLIENT) - public double getViewDistance() - { return 400; } - - // INameable --------------------------------------------------------------------------- - - @Override - public ITextComponent getName() - { final Block block=getBlockState().getBlock(); return new StringTextComponent((block!=null) ? block.getDescriptionId() : "Treated wood crafting table"); } - - @Override - public boolean hasCustomName() - { return false; } - - @Override - public ITextComponent getCustomName() - { return getName(); } - - // INamedContainerProvider ------------------------------------------------------------------------------ - - @Override - public ITextComponent getDisplayName() - { return INameable.super.getDisplayName(); } - - @Override - public Container createMenu( int id, PlayerInventory inventory, PlayerEntity player ) - { return new CraftingTableUiContainer(id, inventory, inventory_, IWorldPosCallable.create(level, worldPosition)); } - - @Override - public void onServerPacketReceived(CompoundNBT nbt) - { readnbt(nbt); } - - public void sync() - { - if(getLevel().isClientSide()) return; - CompoundNBT nbt = new CompoundNBT(); - writenbt(nbt); - Networking.PacketTileNotifyServerToClient.sendToPlayers(this, nbt); - } - - public void scheduleSync() - { - if(level.isClientSide()) return; - final Block crafting_table_block = getBlockState().getBlock(); - if(!(crafting_table_block instanceof CraftingTableBlock)) return; - if(level.getBlockTicks().hasScheduledTick(getBlockPos(), crafting_table_block)) return; - level.getBlockTicks().scheduleTick(getBlockPos(), crafting_table_block, 10, TickPriority.LOW); - } - } - - //-------------------------------------------------------------------------------------------------------------------- - // Crafting container - //-------------------------------------------------------------------------------------------------------------------- - - public static class CraftingTableUiContainer extends Container implements Networking.INetworkSynchronisableContainer - { - protected static final String BUTTON_NEXT = "next"; - protected static final String BUTTON_PREV = "prev"; - protected static final String BUTTON_CLEAR_GRID = "clear"; - protected static final String BUTTON_NEXT_COLLISION_RECIPE = "next-recipe"; - protected static final String ACTION_PLACE_CURRENT_HISTORY_SEL = "place-refab"; - protected static final String ACTION_PLACE_SHIFTCLICKED_STACK = "place-stack"; - protected static final String ACTION_MOVE_ALL_STACKS = "move-stacks"; - protected static final String ACTION_MOVE_STACK = "move-stack"; - protected static final String ACTION_INCREASE_CRAFTING_STACKS = "inc-crafting-stacks"; - protected static final String ACTION_DECREASE_CRAFTING_STACKS = "dec-crafting-stacks"; - - public static final int CRAFTING_SLOTS_BEGIN = 0; - public static final int CRAFTING_SLOTS_SIZE = 9; - public static final int NUM_OF_STORAGE_SLOTS = CraftingTableTileEntity.NUM_OF_STORAGE_SLOTS; - public static final int NUM_OF_STORAGE_ROWS = CraftingTableTileEntity.NUM_OF_STORAGE_ROWS; - - public final ImmutableList> CRAFTING_SLOT_COORDINATES; - private final PlayerEntity player_; - private final IInventory inventory_; - private final IWorldPosCallable wpc_; - private final CraftingHistory history_; - private final CraftingTableGrid matrix_; - private final CraftResultInventory result_; - private final CraftingOutputSlot crafting_output_slot_; - private boolean has_recipe_collision_; - private boolean crafting_matrix_changed_now_; - private final InventoryRange crafting_grid_range_; - private final InventoryRange crafting_result_range_; - private final InventoryRange block_storage_range_; - private final InventoryRange player_storage_range_; - private final InventoryRange player_hotbar_range_; - private final InventoryRange player_inventory_range_; - private final @Nullable CraftingTableTileEntity te_; - - public CraftingTableUiContainer(int cid, PlayerInventory pinv) - { this(cid, pinv, new Inventory(CraftingTableTileEntity.NUM_OF_SLOTS), IWorldPosCallable.NULL); } - - private CraftingTableUiContainer(int cid, PlayerInventory pinv, IInventory block_inventory, IWorldPosCallable wpc) - { - super(ModContent.CT_TREATED_WOOD_CRAFTING_TABLE, cid); - wpc_ = wpc; - player_ = pinv.player; - inventory_ = block_inventory; - inventory_.startOpen(player_); - World world = player_.level; - if((inventory_ instanceof StorageInventory) && ((((StorageInventory)inventory_).getTileEntity()) instanceof CraftingTableTileEntity)) { - te_ = (CraftingTableTileEntity)(((StorageInventory)inventory_).getTileEntity()); - } else { - te_ = null; - } - crafting_grid_range_ = new InventoryRange(inventory_, 0, 9, 3); - block_storage_range_ = new InventoryRange(inventory_, CRAFTING_SLOTS_SIZE, NUM_OF_STORAGE_SLOTS, NUM_OF_STORAGE_ROWS); - crafting_result_range_= new InventoryRange(inventory_, CraftingTableTileEntity.CRAFTING_RESULT_SLOT, 1, 1); - player_storage_range_ = InventoryRange.fromPlayerStorage(player_); - player_hotbar_range_ = InventoryRange.fromPlayerHotbar(player_); - player_inventory_range_= InventoryRange.fromPlayerInventory(player_); - matrix_ = new CraftingTableGrid(this, inventory_); - result_ = new CraftOutputInventory(crafting_result_range_); - history_ = new CraftingHistory(world); - // container slotId 0 === crafting output - addSlot(crafting_output_slot_=(new CraftingOutputSlot(this, pinv.player, matrix_, result_, 0, 118, 27))); - ArrayList> slotpositions = new ArrayList>(); - slotpositions.add(new Tuple<>(118, 27)); - // container slotId 1..9 === TE slots 0..8 - for(int y=0; y<3; ++y) { - for(int x=0; x<3; ++x) { - int xpos = 44+x*18; - int ypos = 9+y*18; - addSlot(new CraftingGridSlot(matrix_, x+y*3, xpos, ypos)); - slotpositions.add(new Tuple<>(xpos, ypos)); - } - } - // container slotId 10..36 === player slots: 9..35 - for(int y=0; y<3; ++y) { - for(int x=0; x<9; ++x) { - addSlot(new Slot(pinv, x+y*9+9, 8+x*18, 110+y*18)); - } - } - // container slotId 37..45 === player slots: 0..8 - for(int x=0; x<9; ++x) { - addSlot(new Slot(pinv, x, 8+x*18, 168)); - } - // container slotId 46..63 === TE slots 9..27 (storage) - for(int y=0; y<2; ++y) { - for(int x=0; x<9; ++x) { - addSlot(new Slot(inventory_, 9+x+y*9, 8+x*18, 65+y*18)); - } - } - if((!player_.level.isClientSide()) && (te_ != null)) { - history_.read(te_.history.copy()); - } - CRAFTING_SLOT_COORDINATES = ImmutableList.copyOf(slotpositions); - onCraftMatrixChanged(); - } - - @Override - public boolean stillValid(PlayerEntity player) - { return inventory_.stillValid(player); } - - public void onCraftMatrixChanged() - { slotsChanged(matrix_); } - - @Override - public void slotsChanged(IInventory inv) - { - wpc_.execute((world,pos)->{ - if(world.isClientSide()) return; - try { - crafting_matrix_changed_now_ = true; - ServerPlayerEntity player = (ServerPlayerEntity) player_; - ItemStack stack = ItemStack.EMPTY; - List recipes = world.getServer().getRecipeManager().getRecipesFor(IRecipeType.CRAFTING, matrix_, world); - has_recipe_collision_ = false; - if(recipes.size() > 0) { - ICraftingRecipe recipe = recipes.get(0); - IRecipe currently_used = result_.getRecipeUsed(); - has_recipe_collision_ = (recipes.size() > 1); - if((recipes.size() > 1) && (currently_used instanceof ICraftingRecipe) && (recipes.contains(currently_used))) { - recipe = (ICraftingRecipe)currently_used; - } - if(result_.setRecipeUsed(world, player, recipe)) { - broadcastChanges(); - stack = recipe.assemble(matrix_); - } - } - result_.setItem(0, stack); - broadcastChanges(); - } catch(Throwable exc) { - ModEngineersDecor.logger().error("Recipe failed:", exc); - } - }); - } - - @Override - public void removed(PlayerEntity player) - { inventory_.stopOpen(player); } - - @Override - public boolean canTakeItemForPickAll(ItemStack stack, Slot slot) - { return (slot.container != result_) && (super.canTakeItemForPickAll(stack, slot)); } - - @Override - public ItemStack quickMoveStack(PlayerEntity player, int index) - { - Slot slot = slots.get(index); - if((slot == null) || (!slot.hasItem())) return ItemStack.EMPTY; - ItemStack slotstack = slot.getItem(); - ItemStack stack = slotstack.copy(); - if(index == 0) { - if(!this.moveItemStackTo(slotstack, 10, 46+NUM_OF_STORAGE_SLOTS, false)) return ItemStack.EMPTY; - wpc_.execute((world, pos)->slotstack.getItem().onCraftedBy(slotstack, world, player)); - slot.onQuickCraft(slotstack, stack); - } else if(index >= 10 && (index < 46)) { - if(!this.moveItemStackTo(slotstack, 46, 46+NUM_OF_STORAGE_SLOTS, false)) return ItemStack.EMPTY; - } else if((index >= 46) && (index < 46+NUM_OF_STORAGE_SLOTS)) { - if(!this.moveItemStackTo(slotstack, 10, 46, false)) return ItemStack.EMPTY; - } else if(!this.moveItemStackTo(slotstack, 10, 46, false)) { - return ItemStack.EMPTY; - } - if(slotstack.isEmpty()) slot.set(ItemStack.EMPTY); - slot.setChanged(); - if((index != 0) && (slotstack.getCount() == stack.getCount())) return ItemStack.EMPTY; - ItemStack itemstack2 = slot.onTake(player, slotstack); - if(index == 0) player.drop(itemstack2, false); - return stack; - } - - @Override - public ItemStack clicked(int slotId, int button, ClickType clickType, PlayerEntity player) - { - crafting_matrix_changed_now_ = false; - final ItemStack stack = super.clicked(slotId, button, clickType, player); - if((with_outslot_defined_refab) && (slotId == 0) && (clickType == ClickType.PICKUP)) { - if((!crafting_matrix_changed_now_) && (!player.level.isClientSide()) && (crafting_grid_empty())) { - final ItemStack dragged = player.inventory.getCarried(); - if((dragged != null) && (!dragged.isEmpty())) { - try_result_stack_refab(dragged, player.level); - } else if(!history().current().isEmpty()) { - try_result_stack_refab(history().current_recipe().getResultItem(), player.level); - } - } - } - return stack; - } - - // Container client/server synchronisation -------------------------------------------------- - - @OnlyIn(Dist.CLIENT) - public void onGuiAction(String message, CompoundNBT nbt) - { - nbt.putString("action", message); - Networking.PacketContainerSyncClientToServer.sendToServer(containerId, nbt); - } - - @Override - public void onServerPacketReceived(int windowId, CompoundNBT nbt) - { - if(nbt.contains("history")) { - history_.read(nbt.getCompound("history")); - } - if(nbt.contains("hascollision")) { - has_recipe_collision_ = nbt.getBoolean("hascollision"); - } - if(nbt.contains("inventory")) { - Inventories.readNbtStacks(nbt, "inventory", inventory_); - this.slotsChanged(matrix_); - } - } - - @Override - public void onClientPacketReceived(int windowId, PlayerEntity player, CompoundNBT nbt) - { - boolean changed = false; - boolean player_inventory_changed = false; - if(with_assist && nbt.contains("action")) { - switch(nbt.getString("action")) { - case BUTTON_NEXT: { - history_.next(); - // implicitly clear the grid, so that the player can see the refab, and that no recipe is active. - if(crafting_grid_range_.move(block_storage_range_)) changed = true; - if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; } - sync(); - } break; - case BUTTON_PREV: { - history_.prev(); - if(crafting_grid_range_.move(block_storage_range_)) changed = true; - if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; } - sync(); - } break; - case BUTTON_CLEAR_GRID: { - history_.reset_selection(); - sync(); - if(crafting_grid_range_.move(block_storage_range_)) changed = true; - if(crafting_grid_range_.move(player_inventory_range_)) { changed = true; player_inventory_changed = true; } - } break; - case ACTION_PLACE_CURRENT_HISTORY_SEL: { - if(place_stacks( - new InventoryRange[]{block_storage_range_, player_storage_range_, player_hotbar_range_}, - refab_crafting_stacks()) != PlacementResult.UNCHANGED) { - changed = true; - } - } break; - case ACTION_PLACE_SHIFTCLICKED_STACK: { - final int container_slot_id = nbt.getInt("containerslot"); - if((container_slot_id < 10) || (container_slot_id > (46+NUM_OF_STORAGE_SLOTS))) { - break; // out of range - } - if(container_slot_id >= 46) { - // from storage - PlacementResult stat = distribute_stack(block_storage_range_, container_slot_id-46); - if(stat != PlacementResult.UNCHANGED) changed = true; - } else { - // from player - int player_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9); - final ItemStack reference_stack = player.inventory.getItem(player_slot).copy(); - if((!reference_stack.isEmpty()) && (distribute_stack(player.inventory, player_slot) != PlacementResult.UNCHANGED)) { - player_inventory_changed = true; - changed = true; - if(nbt.contains("move-all")) { - for(int i=0; i < player.inventory.getContainerSize(); ++i) { - final ItemStack stack = player.inventory.getItem(i); - if(!Inventories.areItemStacksIdentical(reference_stack, stack)) continue; - if(distribute_stack(player.inventory, i) == PlacementResult.UNCHANGED) break; // grid is full - } - } - } - } - } break; - case ACTION_MOVE_STACK: { - final int container_slot_id = nbt.getInt("containerslot"); - if((container_slot_id < 1) || (container_slot_id >= (46+NUM_OF_STORAGE_SLOTS))) { - break; // out of range - } else if(container_slot_id < 10) { - int slot = container_slot_id; - ItemStack remaining = Inventories.insert( - new InventoryRange[] {block_storage_range_, player_storage_range_, player_hotbar_range_}, - inventory_.getItem(slot-1) - ); - changed = player_inventory_changed = (remaining.getCount()!=inventory_.getItem(slot-1).getCount()); - inventory_.setItem(slot-1, remaining); - } - } break; - case ACTION_MOVE_ALL_STACKS: { - final int container_slot_id = nbt.getInt("containerslot"); - if((container_slot_id < 1) || (container_slot_id >= (46+NUM_OF_STORAGE_SLOTS))) { - break; // out of range - } else if(container_slot_id < 10) { - // from crafting grid to player inventory, we clear the grid here as this is most likely - // what is wanted in the end. Saves clicking the other grid stacks. - if(crafting_grid_range_.move(player_inventory_range_, true)) { - crafting_grid_range_.move(player_inventory_range_, false, false, true); - changed = true; player_inventory_changed = true; - } - if(crafting_grid_range_.move(block_storage_range_)) changed = true; - if(crafting_grid_range_.move(player_inventory_range_, true)) { changed = true; player_inventory_changed = true; } - break; - } - IInventory from_inventory; - InventoryRange[] to_ranges; - int from_slot; - if(container_slot_id >= 46) { - // from storage to player inventory - from_inventory = inventory_; - from_slot = container_slot_id - 46 + CRAFTING_SLOTS_SIZE; - to_ranges = new InventoryRange[] {player_storage_range_, player_hotbar_range_}; - } else { - // from player to storage (otherwise ACTION_PLACE_SHIFTCLICKED_STACK would have been used) - from_inventory = player.inventory; - from_slot = (container_slot_id >= 37) ? (container_slot_id-37) : (container_slot_id-10+9); - to_ranges = new InventoryRange[]{block_storage_range_}; - } - final ItemStack reference_stack = from_inventory.getItem(from_slot).copy(); - if(!reference_stack.isEmpty()) { - boolean abort = false; - for(int i=0; (i < from_inventory.getContainerSize()) && (!abort); ++i) { - final ItemStack stack = from_inventory.getItem(i); - if(Inventories.areItemStacksDifferent(reference_stack, stack)) continue; - ItemStack remaining = Inventories.insert(to_ranges, from_inventory.getItem(i)); - changed = player_inventory_changed = (remaining.getCount()!=from_inventory.getItem(i).getCount()); - from_inventory.setItem(i, remaining); - } - } - } break; - case BUTTON_NEXT_COLLISION_RECIPE: { - select_next_collision_recipe(inventory_); - } break; - case ACTION_DECREASE_CRAFTING_STACKS: { - changed = player_inventory_changed = decrease_grid_stacks( - new InventoryRange[]{block_storage_range_, player_storage_range_, player_hotbar_range_}, - MathHelper.clamp(nbt.getInt("limit"), 1, 8)); - } break; - case ACTION_INCREASE_CRAFTING_STACKS: { - changed = player_inventory_changed = increase_grid_stacks( - new InventoryRange[]{block_storage_range_, player_storage_range_, player_hotbar_range_}, - MathHelper.clamp(nbt.getInt("limit"), 1, 8)); - } break; - } - } - if(changed) inventory_.setChanged(); - if(player_inventory_changed) player.inventory.setChanged(); - if(changed || player_inventory_changed) { - this.onCraftMatrixChanged(); - this.broadcastChanges(); - } - } - - public CraftingHistory history() - { return history_; } - - private void sync() - { - this.wpc_.execute((world,pos)->{ - if(world.isClientSide()) return; - inventory_.setChanged(); - final CompoundNBT nbt = new CompoundNBT(); - if(te_ != null) nbt.put("inventory", te_.mainInventory().save(false)); - if(with_assist) { - CompoundNBT hist_nbt = history_.write(); - if(te_ != null) { - te_.history = hist_nbt.copy(); - } - nbt.put("history", hist_nbt); - nbt.putBoolean("hascollision", has_recipe_collision_); - } - Networking.PacketContainerSyncServerToClient.sendToListeners(world, this, nbt); - }); - } - - // private aux methods --------------------------------------------------------------------- - - public boolean has_recipe_collision() - { return has_recipe_collision_; } - - public void select_next_collision_recipe(IInventory inv) - { - wpc_.execute((world,pos)->{ - if(world.isClientSide) return; - try { - ServerPlayerEntity player = (ServerPlayerEntity) player_; - final List matching_recipes = world.getServer().getRecipeManager().getRecipesFor(IRecipeType.CRAFTING, matrix_, world); - if(matching_recipes.size() < 2) return; // nothing to change - IRecipe currently_used = result_.getRecipeUsed(); - List usable_recipes = matching_recipes.stream() - .filter((r)->result_.setRecipeUsed(world,player,r)) - .sorted((a,b)->Integer.compare(a.getId().hashCode(), b.getId().hashCode())) - .collect(Collectors.toList()); - for(int i=0; i= usable_recipes.size()) i=0; - currently_used = usable_recipes.get(i); - ItemStack stack = ((ICraftingRecipe)currently_used).assemble(matrix_); - result_.setItem(0, stack); - result_.setRecipeUsed(currently_used); - break; - } - } - onCraftMatrixChanged(); - } catch(Throwable exc) { - ModEngineersDecor.logger().error("Recipe failed:", exc); - } - }); - } - - @Nullable - private ICraftingRecipe find_first_recipe_for(World world, ItemStack stack) - { - return (ICraftingRecipe)world.getServer().getRecipeManager().getRecipes().stream() - .filter(r->(r.getType()==IRecipeType.CRAFTING) && (r.getResultItem().sameItem(stack))) - .findFirst().orElse(null); - } - - private Optional search_inventory(ItemStack match_stack) { - InventoryRange search_ranges[] = new InventoryRange[]{block_storage_range_, player_storage_range_, player_hotbar_range_}; - for(InventoryRange range: search_ranges) { - for(int i=0; i search_inventory(ItemStack[] match_stacks) { - for(ItemStack match_stack: match_stacks) { - Optional stack = search_inventory(match_stack); - if(stack.isPresent()) return stack; - } - return Optional.empty(); - } - - private ArrayList placement_stacks(ICraftingRecipe recipe) - { - final World world = player_.level; - final ArrayList grid = new ArrayList(); - if(recipe.getIngredients().size() > 9) { - return grid; - } else if(recipe instanceof ShapedRecipe) { - final int endw = ((ShapedRecipe)recipe).getWidth(); - final int endh = ((ShapedRecipe)recipe).getHeight(); - int ingredient_index = 0; - for(int i=3-endh; i>0; --i) for(int w=0; w<3; ++w) { - grid.add(ItemStack.EMPTY); - } - for(int h=3-endh; h<3; ++h) for(int w=0; w<3; ++w) { - if((w >= endw) || (ingredient_index >= recipe.getIngredients().size())) { grid.add(ItemStack.EMPTY); continue; } - ItemStack[] match_stacks = recipe.getIngredients().get(ingredient_index++).getItems(); - if(match_stacks.length == 0) { grid.add(ItemStack.EMPTY); continue; } - ItemStack preferred = search_inventory(match_stacks).orElse(match_stacks[0]); - if(preferred.isEmpty()) { grid.add(ItemStack.EMPTY); continue; } - grid.add(preferred); - } - } else if(recipe instanceof ShapelessRecipe) { - // todo: check if a collision resolver with shaped recipes makes sense here. - for(int ingredient_index=0; ingredient_index grid_stacks) - { - boolean changed = false; - final List ingredients = recipe.getIngredients(); - for(int stack_index=0; stack_index < grid_stacks.size(); ++stack_index) { - ItemStack to_replace = grid_stacks.get(stack_index); - ItemStack replacement = to_replace; - if(to_replace.isEmpty() || (search_inventory(to_replace).isPresent())) continue; // no replacement needed - for(int ingredient_index=0; ingredient_indexInventories.areItemStacksIdentical(s, to_replace))) { - replacement = search_inventory(match_stacks).orElse(to_replace); - changed = true; - break; - } - } - grid_stacks.set(stack_index, replacement); - } - return changed; - } - - private void try_result_stack_refab(ItemStack output_stack, World world) - { - ICraftingRecipe recipe; - int history_index = history().find(output_stack); - if(history_index >= 0) { - history().selection(history_index); - recipe = history().current_recipe(); - List grid_stacks = history().current().subList(1, history().current().size()); - if(adapt_recipe_placement(recipe, grid_stacks)) { - history().stash(grid_stacks, recipe); - recipe = history().current_recipe(); - } - } else if((recipe=find_first_recipe_for(world, output_stack)) != null) { - ArrayList stacks = placement_stacks(recipe); - if(stacks.isEmpty()) { - recipe = null; - } else { - history().stash(stacks, recipe); - recipe = history().current_recipe(); - } - } - if(recipe != null) { - sync(); - onCraftMatrixChanged(); - } - } - - private boolean crafting_grid_empty() - { for(int i=0; i<10; ++i) { if(getSlot(i).hasItem()) return false; } return true; } - - private boolean itemstack_recipe_match(ItemStack grid_stack, ItemStack history_stack) - { - if(history_.current_recipe()!=null) { - final NonNullList ingredients = history_.current_recipe().getIngredients(); - boolean grid_match, dist_match; - for(int i=0; i refab_crafting_stacks() - { - final ArrayList slots = new ArrayList(); - final List tocraft = history_.current(); - final int stack_sizes[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; - if(tocraft.isEmpty()) return slots; - for(int i=0; i<9; ++i) { - if((i+CraftingHistory.INPUT_STACKS_BEGIN) >= tocraft.size()) break; - final ItemStack needed = tocraft.get(i+CraftingHistory.INPUT_STACKS_BEGIN); - final ItemStack palced = inventory_.getItem(i+CRAFTING_SLOTS_BEGIN); - if(needed.isEmpty() && (!palced.isEmpty())) return slots; // history vs grid mismatch. - if((!palced.isEmpty()) && (!itemstack_recipe_match(needed, palced))) return slots; // also mismatch - if(!needed.isEmpty()) stack_sizes[i] = palced.getCount(); - } - int min_placed = 64, max_placed=0; - for(int i=0; i<9; ++i) { - if(stack_sizes[i] < 0) continue; - min_placed = Math.min(min_placed, stack_sizes[i]); - max_placed = Math.max(max_placed, stack_sizes[i]); - } - int fillup_size = (max_placed <= min_placed) ? (min_placed + 1) : max_placed; - for(int i=0; i<9; ++i) { - if(stack_sizes[i] < 0) continue; - if(fillup_size > inventory_.getItem(i+CRAFTING_SLOTS_BEGIN).getMaxStackSize()) return slots; // can't fillup all - } - for(int i=0; i<9; ++i) { - if(stack_sizes[i] < 0) { - slots.add(ItemStack.EMPTY); - } else { - ItemStack st = inventory_.getItem(i+CRAFTING_SLOTS_BEGIN).copy(); - if(st.isEmpty()) { - st = tocraft.get(i+CraftingHistory.INPUT_STACKS_BEGIN).copy(); - st.setCount(Math.min(st.getMaxStackSize(), fillup_size)); - } else { - st.setCount(MathHelper.clamp(fillup_size-st.getCount(), 0, st.getMaxStackSize())); - } - slots.add(st); - } - } - return slots; - } - - private List incr_crafting_grid_stacks(int count) - { - final ArrayList stacks = new ArrayList(); - for(int i=0; i<9; ++i) { - final ItemStack palced = crafting_grid_range_.getItem(i).copy(); - if(!palced.isEmpty()) palced.setCount(count); - stacks.add(palced); - } - return stacks; - } - - private PlacementResult place_stacks(final InventoryRange[] ranges, final List to_fill) - { - if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe()); - boolean slots_changed = false; - if(!to_fill.isEmpty()) { - for(InventoryRange slot_range: ranges) { - for(int it_guard=63; it_guard>=0; --it_guard) { - boolean slots_updated = false; - for(int i = 0; i < 9; ++i) { - if(to_fill.get(i).isEmpty()) continue; - ItemStack grid_stack = crafting_grid_range_.getItem(i).copy(); - if(grid_stack.getCount() >= grid_stack.getMaxStackSize()) continue; - final ItemStack req_stack = to_fill.get(i).copy(); - req_stack.setCount(1); - final ItemStack mv_stack = slot_range.extract(req_stack); - if(mv_stack.isEmpty()) continue; - to_fill.get(i).shrink(1); - if(grid_stack.isEmpty()) { - grid_stack = mv_stack.copy(); - } else { - grid_stack.grow(mv_stack.getCount()); - } - crafting_grid_range_.setItem(i, grid_stack); - slots_changed = true; - slots_updated = true; - } - if(!slots_updated) break; - } - } - } - boolean missing_item = false; - for(ItemStack st:to_fill) { - if(!st.isEmpty()) { - missing_item = true; - break; - } - } - if(!slots_changed) { - return PlacementResult.UNCHANGED; - } else if(missing_item) { - return PlacementResult.INCOMPLETE; - } else { - return PlacementResult.PLACED; - } - } - - private PlacementResult distribute_stack(IInventory inventory, final int slot_index) - { - List to_refab = refab_crafting_stacks(); - if(history_.current_recipe() != null) result_.setRecipeUsed(history_.current_recipe()); - ItemStack to_distribute = inventory.getItem(slot_index).copy(); - if(to_distribute.isEmpty()) return PlacementResult.UNCHANGED; - int matching_grid_stack_sizes[] = {-1,-1,-1,-1,-1,-1,-1,-1,-1}; - int max_matching_stack_size = -1; - int min_matching_stack_size = 65; - int total_num_missing_stacks = 0; - for(int i=0; i<9; ++i) { - final ItemStack grid_stack = crafting_grid_range_.getItem(i); - final ItemStack refab_stack = to_refab.isEmpty() ? ItemStack.EMPTY : to_refab.get(i).copy(); - if((!grid_stack.isEmpty()) && Inventories.areItemStacksIdentical(grid_stack, to_distribute)) { - matching_grid_stack_sizes[i] = grid_stack.getCount(); - total_num_missing_stacks += grid_stack.getMaxStackSize()-grid_stack.getCount(); - if(max_matching_stack_size < matching_grid_stack_sizes[i]) max_matching_stack_size = matching_grid_stack_sizes[i]; - if(min_matching_stack_size > matching_grid_stack_sizes[i]) min_matching_stack_size = matching_grid_stack_sizes[i]; - } else if((!refab_stack.isEmpty()) && (Inventories.areItemStacksIdentical(refab_stack, to_distribute))) { - matching_grid_stack_sizes[i] = 0; - total_num_missing_stacks += grid_stack.getMaxStackSize(); - if(max_matching_stack_size < matching_grid_stack_sizes[i]) max_matching_stack_size = matching_grid_stack_sizes[i]; - if(min_matching_stack_size > matching_grid_stack_sizes[i]) min_matching_stack_size = matching_grid_stack_sizes[i]; - } else if(grid_stack.isEmpty() && (!refab_stack.isEmpty())) { - if(itemstack_recipe_match(to_distribute, refab_stack)) { - matching_grid_stack_sizes[i] = 0; - total_num_missing_stacks += grid_stack.getMaxStackSize(); - if(max_matching_stack_size < matching_grid_stack_sizes[i]) max_matching_stack_size = matching_grid_stack_sizes[i]; - if(min_matching_stack_size > matching_grid_stack_sizes[i]) min_matching_stack_size = matching_grid_stack_sizes[i]; - } - } - } - if(min_matching_stack_size < 0) return PlacementResult.UNCHANGED; - final int stack_limit_size = Math.min(to_distribute.getMaxStackSize(), crafting_grid_range_.getMaxStackSize()); - if(min_matching_stack_size >= stack_limit_size) return PlacementResult.UNCHANGED; - int n_to_distribute = to_distribute.getCount(); - for(int it_guard=63; it_guard>=0; --it_guard) { - if(n_to_distribute <= 0) break; - for(int i=0; i<9; ++i) { - if(n_to_distribute <= 0) break; - if(matching_grid_stack_sizes[i] == min_matching_stack_size) { - ++matching_grid_stack_sizes[i]; - --n_to_distribute; - } - } - if(min_matching_stack_size < max_matching_stack_size) { - ++min_matching_stack_size; // distribute short stacks - } else { - ++min_matching_stack_size; // stacks even, increase all - max_matching_stack_size = min_matching_stack_size; - } - if(min_matching_stack_size >= stack_limit_size) break; // all full - } - if(n_to_distribute == to_distribute.getCount()) return PlacementResult.UNCHANGED; // was already full - if(n_to_distribute <= 0) { - inventory.setItem(slot_index, ItemStack.EMPTY); - } else { - to_distribute.setCount(n_to_distribute); - inventory.setItem(slot_index, to_distribute); - } - for(int i=0; i<9; ++i) { - if(matching_grid_stack_sizes[i] < 0) continue; - ItemStack grid_stack = crafting_grid_range_.getItem(i).copy(); - if(grid_stack.isEmpty()) grid_stack = to_distribute.copy(); - grid_stack.setCount(matching_grid_stack_sizes[i]); - crafting_grid_range_.setItem(i, grid_stack); - } - return PlacementResult.PLACED; - } - - private boolean decrease_grid_stacks(InventoryRange[] ranges, int limit) - { - boolean changed = false; - for(int i=0; i<9; ++i) { - ItemStack stack = crafting_grid_range_.getItem(i).copy(); - if(stack.isEmpty()) continue; - for(InventoryRange range:ranges) { - ItemStack remaining = range.insert(stack, false, limit, false, false); - if(remaining.getCount() < stack.getCount()) changed = true; - boolean stop = (remaining.getCount() <= Math.max(0, (stack.getCount()-limit))); - stack = remaining; - if(stop) break; - } - crafting_grid_range_.setItem(i, stack.isEmpty() ? ItemStack.EMPTY : stack); - } - return changed; - } - - private boolean increase_grid_stacks(InventoryRange[] ranges, int limit) - { return place_stacks(ranges, incr_crafting_grid_stacks(limit)) != PlacementResult.UNCHANGED; } - - } - - //-------------------------------------------------------------------------------------------------------------------- - // GUI - //-------------------------------------------------------------------------------------------------------------------- - - @OnlyIn(Dist.CLIENT) - public static class CraftingTableGui extends ContainerGui - { - protected static final ResourceLocation BACKGROUND = new ResourceLocation(ModEngineersDecor.MODID, "textures/gui/metal_crafting_table_gui.png"); - protected final PlayerEntity player; - protected final ArrayList