diff --git a/src/generated/resources/assets/poopsky/blockstates/poop_leaves.json b/src/generated/resources/assets/poopsky/blockstates/poop_leaves.json new file mode 100644 index 0000000..d1c3bf9 --- /dev/null +++ b/src/generated/resources/assets/poopsky/blockstates/poop_leaves.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "poopsky:block/poop_leaves" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/blockstates/poop_leaves_gold.json b/src/generated/resources/assets/poopsky/blockstates/poop_leaves_gold.json new file mode 100644 index 0000000..20d59c5 --- /dev/null +++ b/src/generated/resources/assets/poopsky/blockstates/poop_leaves_gold.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "poopsky:block/poop_leaves_gold" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/blockstates/poop_leaves_iron.json b/src/generated/resources/assets/poopsky/blockstates/poop_leaves_iron.json new file mode 100644 index 0000000..50242e3 --- /dev/null +++ b/src/generated/resources/assets/poopsky/blockstates/poop_leaves_iron.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "poopsky:block/poop_leaves_iron" + } + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/block/poop_leaves.json b/src/generated/resources/assets/poopsky/models/block/poop_leaves.json new file mode 100644 index 0000000..a5a03d2 --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/block/poop_leaves.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "poopsky:block/poop_leaves" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/block/poop_leaves_gold.json b/src/generated/resources/assets/poopsky/models/block/poop_leaves_gold.json new file mode 100644 index 0000000..490487d --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/block/poop_leaves_gold.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "poopsky:block/poop_leaves_gold" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/block/poop_leaves_iron.json b/src/generated/resources/assets/poopsky/models/block/poop_leaves_iron.json new file mode 100644 index 0000000..9266f86 --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/block/poop_leaves_iron.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "poopsky:block/poop_leaves_iron" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/item/poop_leaves.json b/src/generated/resources/assets/poopsky/models/item/poop_leaves.json new file mode 100644 index 0000000..9513fbd --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/item/poop_leaves.json @@ -0,0 +1,3 @@ +{ + "parent": "poopsky:block/poop_leaves" +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/item/poop_leaves_gold.json b/src/generated/resources/assets/poopsky/models/item/poop_leaves_gold.json new file mode 100644 index 0000000..d599bca --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/item/poop_leaves_gold.json @@ -0,0 +1,3 @@ +{ + "parent": "poopsky:block/poop_leaves_gold" +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/item/poop_leaves_iron.json b/src/generated/resources/assets/poopsky/models/item/poop_leaves_iron.json new file mode 100644 index 0000000..95591f9 --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/item/poop_leaves_iron.json @@ -0,0 +1,3 @@ +{ + "parent": "poopsky:block/poop_leaves_iron" +} \ No newline at end of file diff --git a/src/generated/resources/assets/poopsky/models/item/urine_bottle.json b/src/generated/resources/assets/poopsky/models/item/urine_bottle.json new file mode 100644 index 0000000..80b95cc --- /dev/null +++ b/src/generated/resources/assets/poopsky/models/item/urine_bottle.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "poopsky:item/urine_bottle" + } +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/logs.json b/src/generated/resources/data/minecraft/tags/block/logs.json new file mode 100644 index 0000000..3204962 --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/block/logs.json @@ -0,0 +1,8 @@ +{ + "values": [ + "poopsky:poop_log", + "poopsky:poop_empty_log", + "poopsky:stripped_poop_log", + "poopsky:stripped_poop_empty_log" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json new file mode 100644 index 0000000..2958761 --- /dev/null +++ b/src/generated/resources/data/minecraft/tags/block/mineable/pickaxe.json @@ -0,0 +1,5 @@ +{ + "values": [ + "poopsky:compooper" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/acacia_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/acacia_toilet.json new file mode 100644 index 0000000..c11595e --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/acacia_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:acacia_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/acacia_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/bamboo_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/bamboo_toilet.json new file mode 100644 index 0000000..4b7555f --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/bamboo_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:bamboo_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/bamboo_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/birch_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/birch_toilet.json new file mode 100644 index 0000000..61f2af9 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/birch_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:birch_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/birch_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/black_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/black_concrete_toilet.json new file mode 100644 index 0000000..2f7f359 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/black_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:black_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/black_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/blue_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/blue_concrete_toilet.json new file mode 100644 index 0000000..c82290d --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/blue_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:blue_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/blue_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/brown_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/brown_concrete_toilet.json new file mode 100644 index 0000000..8d7d870 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/brown_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:brown_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/brown_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/cherry_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/cherry_toilet.json new file mode 100644 index 0000000..3b862a3 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/cherry_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:cherry_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/cherry_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/cobblestone_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/cobblestone_toilet.json new file mode 100644 index 0000000..429007e --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/cobblestone_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:cobblestone_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/cobblestone_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/compooper.json b/src/generated/resources/data/poopsky/loot_table/blocks/compooper.json new file mode 100644 index 0000000..7e57d8a --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/compooper.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:compooper" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/compooper" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/crimson_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/crimson_toilet.json new file mode 100644 index 0000000..920c3f0 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/crimson_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:crimson_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/crimson_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/cyan_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/cyan_concrete_toilet.json new file mode 100644 index 0000000..06c1271 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/cyan_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:cyan_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/cyan_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/dark_oak_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/dark_oak_toilet.json new file mode 100644 index 0000000..647225e --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/dark_oak_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:dark_oak_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/dark_oak_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/gray_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/gray_concrete_toilet.json new file mode 100644 index 0000000..01c7260 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/gray_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:gray_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/gray_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/green_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/green_concrete_toilet.json new file mode 100644 index 0000000..8a99f3e --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/green_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:green_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/green_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/jungle_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/jungle_toilet.json new file mode 100644 index 0000000..98627d6 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/jungle_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:jungle_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/jungle_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/light_blue_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/light_blue_concrete_toilet.json new file mode 100644 index 0000000..99fc3a2 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/light_blue_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:light_blue_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/light_blue_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/light_gray_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/light_gray_concrete_toilet.json new file mode 100644 index 0000000..bc16c8f --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/light_gray_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:light_gray_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/light_gray_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/lime_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/lime_concrete_toilet.json new file mode 100644 index 0000000..0bb0a5e --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/lime_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:lime_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/lime_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/magenta_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/magenta_concrete_toilet.json new file mode 100644 index 0000000..df539fd --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/magenta_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:magenta_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/magenta_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/mangrove_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/mangrove_toilet.json new file mode 100644 index 0000000..2b1caf2 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/mangrove_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:mangrove_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/mangrove_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/mossy_cobblestone_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/mossy_cobblestone_toilet.json new file mode 100644 index 0000000..120d5a8 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/mossy_cobblestone_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:mossy_cobblestone_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/mossy_cobblestone_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/mossy_stone_brick_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/mossy_stone_brick_toilet.json new file mode 100644 index 0000000..19c3986 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/mossy_stone_brick_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:mossy_stone_brick_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/mossy_stone_brick_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/oak_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/oak_toilet.json new file mode 100644 index 0000000..f34f145 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/oak_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:oak_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/oak_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/orange_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/orange_concrete_toilet.json new file mode 100644 index 0000000..a186f0b --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/orange_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:orange_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/orange_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/pink_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/pink_concrete_toilet.json new file mode 100644 index 0000000..3c4c1c5 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/pink_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:pink_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/pink_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_empty_log.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_empty_log.json new file mode 100644 index 0000000..658a761 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_empty_log.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:poop_empty_log" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_empty_log" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves.json new file mode 100644 index 0000000..e9ead4f --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves.json @@ -0,0 +1,64 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "name": "poopsky:poop_leaves" + }, + { + "type": "minecraft:item", + "functions": [ + { + "add": false, + "count": { + "type": "minecraft:uniform", + "max": 1.0, + "min": 0.0 + }, + "function": "minecraft:set_count" + }, + { + "enchantment": "minecraft:fortune", + "formula": "minecraft:uniform_bonus_count", + "function": "minecraft:apply_bonus", + "parameters": { + "bonusMultiplier": 1 + } + }, + { + "function": "minecraft:explosion_decay" + } + ], + "name": "poopsky:poop" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_leaves" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_gold.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_gold.json new file mode 100644 index 0000000..b5fb6ef --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_gold.json @@ -0,0 +1,64 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "name": "poopsky:poop_leaves_gold" + }, + { + "type": "minecraft:item", + "functions": [ + { + "add": false, + "count": { + "type": "minecraft:uniform", + "max": 2.0, + "min": 0.0 + }, + "function": "minecraft:set_count" + }, + { + "enchantment": "minecraft:fortune", + "formula": "minecraft:uniform_bonus_count", + "function": "minecraft:apply_bonus", + "parameters": { + "bonusMultiplier": 1 + } + }, + { + "function": "minecraft:explosion_decay" + } + ], + "name": "minecraft:gold_nugget" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_leaves_gold" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_iron.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_iron.json new file mode 100644 index 0000000..79bab47 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_leaves_iron.json @@ -0,0 +1,64 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "name": "poopsky:poop_leaves_iron" + }, + { + "type": "minecraft:item", + "functions": [ + { + "add": false, + "count": { + "type": "minecraft:uniform", + "max": 3.0, + "min": 0.0 + }, + "function": "minecraft:set_count" + }, + { + "enchantment": "minecraft:fortune", + "formula": "minecraft:uniform_bonus_count", + "function": "minecraft:apply_bonus", + "parameters": { + "bonusMultiplier": 1 + } + }, + { + "function": "minecraft:explosion_decay" + } + ], + "name": "minecraft:iron_nugget" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_leaves_iron" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_log.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_log.json new file mode 100644 index 0000000..e2c501d --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_log.json @@ -0,0 +1,64 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "name": "poopsky:poop_log" + }, + { + "type": "minecraft:item", + "functions": [ + { + "add": false, + "count": { + "type": "minecraft:uniform", + "max": 5.0, + "min": 4.0 + }, + "function": "minecraft:set_count" + }, + { + "enchantment": "minecraft:fortune", + "formula": "minecraft:uniform_bonus_count", + "function": "minecraft:apply_bonus", + "parameters": { + "bonusMultiplier": 1 + } + }, + { + "function": "minecraft:explosion_decay" + } + ], + "name": "poopsky:spall" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_log" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/poop_sapling.json b/src/generated/resources/data/poopsky/loot_table/blocks/poop_sapling.json new file mode 100644 index 0000000..030193d --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/poop_sapling.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:poop_sapling" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/poop_sapling" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/purple_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/purple_concrete_toilet.json new file mode 100644 index 0000000..20f3f14 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/purple_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:purple_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/purple_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/rainbow_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/rainbow_toilet.json new file mode 100644 index 0000000..44d62c3 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/rainbow_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:rainbow_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/rainbow_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/red_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/red_concrete_toilet.json new file mode 100644 index 0000000..5dd3c93 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/red_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:red_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/red_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/smooth_stone_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/smooth_stone_toilet.json new file mode 100644 index 0000000..50fab52 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/smooth_stone_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:smooth_stone_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/smooth_stone_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/spruce_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/spruce_toilet.json new file mode 100644 index 0000000..16a5c2f --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/spruce_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:spruce_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/spruce_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/stone_brick_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/stone_brick_toilet.json new file mode 100644 index 0000000..5022056 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/stone_brick_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:stone_brick_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/stone_brick_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/stone_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/stone_toilet.json new file mode 100644 index 0000000..09fef44 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/stone_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:stone_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/stone_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_empty_log.json b/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_empty_log.json new file mode 100644 index 0000000..bd437d9 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_empty_log.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:stripped_poop_empty_log" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/stripped_poop_empty_log" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_log.json b/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_log.json new file mode 100644 index 0000000..260f702 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/stripped_poop_log.json @@ -0,0 +1,64 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "entries": [ + { + "type": "minecraft:alternatives", + "children": [ + { + "type": "minecraft:item", + "conditions": [ + { + "condition": "minecraft:match_tool", + "predicate": { + "predicates": { + "minecraft:enchantments": [ + { + "enchantments": "minecraft:silk_touch", + "levels": { + "min": 1 + } + } + ] + } + } + } + ], + "name": "poopsky:stripped_poop_log" + }, + { + "type": "minecraft:item", + "functions": [ + { + "add": false, + "count": { + "type": "minecraft:uniform", + "max": 5.0, + "min": 4.0 + }, + "function": "minecraft:set_count" + }, + { + "enchantment": "minecraft:fortune", + "formula": "minecraft:uniform_bonus_count", + "function": "minecraft:apply_bonus", + "parameters": { + "bonusMultiplier": 1 + } + }, + { + "function": "minecraft:explosion_decay" + } + ], + "name": "poopsky:spall" + } + ] + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/stripped_poop_log" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/warped_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/warped_toilet.json new file mode 100644 index 0000000..e68a41b --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/warped_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:warped_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/warped_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/white_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/white_concrete_toilet.json new file mode 100644 index 0000000..9e53358 --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/white_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:white_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/white_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/loot_table/blocks/yellow_concrete_toilet.json b/src/generated/resources/data/poopsky/loot_table/blocks/yellow_concrete_toilet.json new file mode 100644 index 0000000..ce5b24f --- /dev/null +++ b/src/generated/resources/data/poopsky/loot_table/blocks/yellow_concrete_toilet.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "name": "poopsky:yellow_concrete_toilet" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "poopsky:blocks/yellow_concrete_toilet" +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/tags/block/toilet_blocks.json b/src/generated/resources/data/poopsky/tags/block/toilet_blocks.json new file mode 100644 index 0000000..b058a70 --- /dev/null +++ b/src/generated/resources/data/poopsky/tags/block/toilet_blocks.json @@ -0,0 +1,38 @@ +{ + "values": [ + "poopsky:oak_toilet", + "poopsky:spruce_toilet", + "poopsky:birch_toilet", + "poopsky:jungle_toilet", + "poopsky:acacia_toilet", + "poopsky:cherry_toilet", + "poopsky:dark_oak_toilet", + "poopsky:mangrove_toilet", + "poopsky:bamboo_toilet", + "poopsky:crimson_toilet", + "poopsky:warped_toilet", + "poopsky:stone_toilet", + "poopsky:cobblestone_toilet", + "poopsky:mossy_cobblestone_toilet", + "poopsky:smooth_stone_toilet", + "poopsky:stone_brick_toilet", + "poopsky:mossy_stone_brick_toilet", + "poopsky:white_concrete_toilet", + "poopsky:light_gray_concrete_toilet", + "poopsky:gray_concrete_toilet", + "poopsky:black_concrete_toilet", + "poopsky:brown_concrete_toilet", + "poopsky:red_concrete_toilet", + "poopsky:orange_concrete_toilet", + "poopsky:yellow_concrete_toilet", + "poopsky:lime_concrete_toilet", + "poopsky:green_concrete_toilet", + "poopsky:cyan_concrete_toilet", + "poopsky:light_blue_concrete_toilet", + "poopsky:blue_concrete_toilet", + "poopsky:purple_concrete_toilet", + "poopsky:magenta_concrete_toilet", + "poopsky:pink_concrete_toilet", + "poopsky:rainbow_toilet" + ] +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/worldgen/configured_feature/mega_poop_tree.json b/src/generated/resources/data/poopsky/worldgen/configured_feature/mega_poop_tree.json new file mode 100644 index 0000000..675a320 --- /dev/null +++ b/src/generated/resources/data/poopsky/worldgen/configured_feature/mega_poop_tree.json @@ -0,0 +1,83 @@ +{ + "type": "minecraft:tree", + "config": { + "decorators": [], + "dirt_provider": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "minecraft:mud" + } + }, + "foliage_placer": { + "type": "poopsky:poop_mega_foliage_placer", + "crown_height": { + "type": "minecraft:uniform", + "max_inclusive": 17, + "min_inclusive": 13 + }, + "offset": 3, + "radius": 0 + }, + "foliage_provider": { + "type": "minecraft:weighted_state_provider", + "entries": [ + { + "data": { + "Name": "poopsky:poop_leaves", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 11 + }, + { + "data": { + "Name": "poopsky:poop_leaves_iron", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 3 + }, + { + "data": { + "Name": "poopsky:poop_leaves_gold", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 1 + } + ] + }, + "force_dirt": true, + "ignore_vines": false, + "minimum_size": { + "type": "minecraft:two_layers_feature_size", + "limit": 1, + "lower_size": 1, + "upper_size": 2 + }, + "trunk_placer": { + "type": "minecraft:giant_trunk_placer", + "base_height": 12, + "height_rand_a": 2, + "height_rand_b": 14 + }, + "trunk_provider": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "poopsky:poop_log", + "Properties": { + "axis": "y" + } + } + } + } +} \ No newline at end of file diff --git a/src/generated/resources/data/poopsky/worldgen/configured_feature/poop_tree.json b/src/generated/resources/data/poopsky/worldgen/configured_feature/poop_tree.json new file mode 100644 index 0000000..d151bb4 --- /dev/null +++ b/src/generated/resources/data/poopsky/worldgen/configured_feature/poop_tree.json @@ -0,0 +1,80 @@ +{ + "type": "minecraft:tree", + "config": { + "decorators": [], + "dirt_provider": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "minecraft:mud" + } + }, + "foliage_placer": { + "type": "minecraft:random_spread_foliage_placer", + "foliage_height": 2, + "leaf_placement_attempts": 114, + "offset": 0, + "radius": 3 + }, + "foliage_provider": { + "type": "minecraft:weighted_state_provider", + "entries": [ + { + "data": { + "Name": "poopsky:poop_leaves", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 11 + }, + { + "data": { + "Name": "poopsky:poop_leaves_iron", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 3 + }, + { + "data": { + "Name": "poopsky:poop_leaves_gold", + "Properties": { + "distance": "7", + "persistent": "false", + "waterlogged": "false" + } + }, + "weight": 1 + } + ] + }, + "force_dirt": true, + "ignore_vines": false, + "minimum_size": { + "type": "minecraft:two_layers_feature_size", + "limit": 2, + "lower_size": 0, + "upper_size": 2 + }, + "trunk_placer": { + "type": "minecraft:straight_trunk_placer", + "base_height": 3, + "height_rand_a": 1, + "height_rand_b": 1 + }, + "trunk_provider": { + "type": "minecraft:simple_state_provider", + "state": { + "Name": "poopsky:poop_log", + "Properties": { + "axis": "y" + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/altnoir/poopsky/PoopSky.java b/src/main/java/com/altnoir/poopsky/PoopSky.java index 9d9000e..54574f5 100644 --- a/src/main/java/com/altnoir/poopsky/PoopSky.java +++ b/src/main/java/com/altnoir/poopsky/PoopSky.java @@ -3,6 +3,7 @@ import com.altnoir.poopsky.block.PSBlockEntities; import com.altnoir.poopsky.block.PSBlocks; import com.altnoir.poopsky.block.ToiletBlocks; +import com.altnoir.poopsky.block.p.CompooperBlock; import com.altnoir.poopsky.component.PSComponents; import com.altnoir.poopsky.effect.PSEffects; import com.altnoir.poopsky.entity.PSEntities; @@ -12,7 +13,11 @@ import com.altnoir.poopsky.particle.PSParticles; import com.altnoir.poopsky.particle.PoopParticle; import com.altnoir.poopsky.sound.PSSoundEvents; +import com.altnoir.poopsky.worldgen.foliage.PSFoliagePlacerTypes; import com.mojang.logging.LogUtils; +import net.minecraft.client.renderer.BiomeColors; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.entity.EntityRenderers; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.IEventBus; @@ -23,6 +28,7 @@ import net.neoforged.fml.config.ModConfig; import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; +import net.neoforged.neoforge.client.event.RegisterColorHandlersEvent; import net.neoforged.neoforge.client.event.RegisterParticleProvidersEvent; import net.neoforged.neoforge.common.NeoForge; import net.neoforged.neoforge.event.BuildCreativeModeTabContentsEvent; @@ -44,6 +50,7 @@ public PoopSky(IEventBus modEventBus, ModContainer modContainer) { PSBlockEntities.register(modEventBus); PSItems.register(modEventBus); PSEntities.register(modEventBus); + PSFoliagePlacerTypes.register(modEventBus); PSEffects.register(modEventBus); PSParticles.register(modEventBus); @@ -75,12 +82,30 @@ public void onServerStarting(ServerStartingEvent event) { public static class ClientModEvents { @SubscribeEvent public static void onClientSetup(FMLClientSetupEvent event) { + ItemBlockRenderTypes.setRenderLayer(PSBlocks.POOP_SAPLING.get(), RenderType.cutout()); + ItemBlockRenderTypes.setRenderLayer(PSBlocks.POOP_EMPTY_LOG.get(), RenderType.cutout()); EntityRenderers.register(PSEntities.TOILET_PLUG.get(), ToiletPlugRenderer::new); + CompooperBlock.bootStrap(); } @SubscribeEvent public static void registerParticleProviders(RegisterParticleProvidersEvent event) { event.registerSpriteSet(PSParticles.POOP_PARTICLE.get(), PoopParticle.Provider::new); } + + @SubscribeEvent + public static void onRegisterBlockColors(RegisterColorHandlersEvent.Block event) { + event.register((state, world, pos, tintIndex) -> { + if (tintIndex == 1) { + if (state.getValue(CompooperBlock.LEVEL) == CompooperBlock.READY && state.getValue(CompooperBlock.LIQUID)) { + return world != null && pos != null + ? BiomeColors.getAverageWaterColor(world, pos) + : 0x3F76E4; + } + return 0x47311A; + } + return -1; + }, PSBlocks.COMPOOPER.get()); + } } } diff --git a/src/main/java/com/altnoir/poopsky/block/AbstractToiletBlock.java b/src/main/java/com/altnoir/poopsky/block/AbstractToiletBlock.java index 635d913..993fe80 100644 --- a/src/main/java/com/altnoir/poopsky/block/AbstractToiletBlock.java +++ b/src/main/java/com/altnoir/poopsky/block/AbstractToiletBlock.java @@ -10,9 +10,8 @@ import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.TickTask; import net.minecraft.server.level.ServerLevel; -import net.minecraft.server.level.ServerPlayer; -import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.util.RandomSource; @@ -25,7 +24,6 @@ import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; -import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; @@ -37,6 +35,9 @@ import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Set; + public abstract class AbstractToiletBlock extends Block implements EntityBlock { public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING; private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 16, 16); @@ -72,10 +73,10 @@ public void fallOn(Level level, BlockState blockState, BlockPos pos, Entity enti poopAnvil(level, entity); } - if (fallDistance >= 1.0f && entity instanceof ServerPlayer player && isPlayerCentered(pos, player)) { + if (fallDistance >= 1.0f && isEntityCentered(pos, entity)) { var be = (ToiletBlockEntity)level.getBlockEntity(pos); if (be == null) return; - teleportPlayer(player, be, fallDistance); + teleportEntity(level, entity, be, fallDistance); } } } @@ -93,7 +94,7 @@ private void poopAnvil(Level level, Entity entity) { @Override public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { if (!level.isClientSide && entity instanceof Player player) { - if (player.isShiftKeyDown() && isPlayerCentered(pos, player)) { + if (player.isShiftKeyDown() && isEntityCentered(pos, player)) { if (player.hasEffect(PSEffects.FECAL_INCONTINENCE)) { onPoop(level, player); player.causeFoodExhaustion(0.05F); @@ -105,9 +106,9 @@ public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { } } - protected boolean isPlayerCentered(BlockPos blockPos, Player player) { + protected boolean isEntityCentered(BlockPos blockPos, Entity entity) { var blockAABB = new AABB(blockPos).inflate(0.2); - return blockAABB.contains(player.position()); + return blockAABB.contains(entity.position()); } protected void onPoop(Level level, Player player) { @@ -133,19 +134,30 @@ protected void onPoop(Level level, Player player) { level.addFreshEntity(poop); } - public void teleportPlayer(ServerPlayer player, ToiletBlockEntity blockEntity, float fallDistance) { - var server = player.server; + public void teleportEntity(Level level, Entity entity, ToiletBlockEntity blockEntity, float fallDistance) { + var server = level.getServer(); if (blockEntity.getLinkedDim() == null) return; var targetWorld = server.getLevel(ResourceKey.create(Registries.DIMENSION, ResourceLocation.parse(blockEntity.getLinkedDim()))); if (targetWorld == null) return; - var targetPos = blockEntity.getLinkedPos(); - player.teleportTo(targetWorld, targetPos.getX() + 0.5, targetPos.getY() + 1, targetPos.getZ() + 0.5, player.getYRot(), player.getXRot()); + targetWorld.getChunk(targetPos); + + if (entity.isVehicle() && !entity.getPassengers().isEmpty()) { + entity.getControllingPassenger().teleportTo(targetWorld, targetPos.getX() + 0.5, targetPos.getY() + 1, targetPos.getZ() + 0.5, Set.of() , entity.getYRot(), entity.getXRot()); + entity.teleportTo(targetWorld, targetPos.getX() + 0.5, targetPos.getY() + 1, targetPos.getZ() + 0.5, Set.of() , entity.getYRot(), entity.getXRot()); + } + else { + entity.teleportTo(targetWorld, targetPos.getX() + 0.5, targetPos.getY() + 1, targetPos.getZ() + 0.5, Set.of() , entity.getYRot(), entity.getXRot()); + } + var pitch = targetWorld.random.nextFloat() + 0.1F; - targetWorld.playSound(null, player.getX(), player.getY() + 0.1, player.getZ(), SoundEvents.MUD_BREAK, SoundSource.PLAYERS, 1.0F, pitch); + targetWorld.playSound(null, entity.getX(), entity.getY() + 0.1, entity.getZ(), SoundEvents.MUD_BREAK, SoundSource.PLAYERS, 1.0F, pitch); var bounce = Math.sqrt(2 * 0.08 * fallDistance) * 0.85; - player.setDeltaMovement(player.getDeltaMovement().x, bounce, player.getDeltaMovement().z); - player.hurtMarked = true; + server.tell(new TickTask(server.getTickCount() + 1, () -> { + entity.setDeltaMovement(entity.getDeltaMovement().x, bounce, entity.getDeltaMovement().z); + entity.hurtMarked = true; + entity.hasImpulse = true; + })); } @Override diff --git a/src/main/java/com/altnoir/poopsky/block/PSBlockProperties.java b/src/main/java/com/altnoir/poopsky/block/PSBlockProperties.java new file mode 100644 index 0000000..54f63bb --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/block/PSBlockProperties.java @@ -0,0 +1,20 @@ +package com.altnoir.poopsky.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.state.BlockState; + +public class PSBlockProperties { + public static boolean neverSuffocate(BlockState state, BlockGetter world, BlockPos pos) { + return false; + } + + public static boolean never(BlockState state, BlockGetter world, BlockPos pos) { + return false; + } + + public static boolean neverBlockVision(BlockState state, BlockGetter world, BlockPos pos) { + return false; + } +} diff --git a/src/main/java/com/altnoir/poopsky/block/PSBlocks.java b/src/main/java/com/altnoir/poopsky/block/PSBlocks.java index 76a2642..ed5aec3 100644 --- a/src/main/java/com/altnoir/poopsky/block/PSBlocks.java +++ b/src/main/java/com/altnoir/poopsky/block/PSBlocks.java @@ -1,14 +1,12 @@ package com.altnoir.poopsky.block; import com.altnoir.poopsky.PoopSky; -import com.altnoir.poopsky.block.p.PoopBlock; -import com.altnoir.poopsky.block.p.PoopPiece; +import com.altnoir.poopsky.block.p.*; import com.altnoir.poopsky.item.PSItems; +import net.minecraft.tags.BlockTags; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; -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.*; import net.minecraft.world.level.block.state.BlockBehaviour; import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; import net.minecraft.world.level.material.MapColor; @@ -47,6 +45,115 @@ public class PSBlocks { ) ); + public static final DeferredBlock COMPOOPER = registerBlock("compooper", + () -> new CompooperBlock(BlockBehaviour.Properties.of() + .randomTicks() + .noOcclusion() + .mapColor(MapColor.COLOR_BROWN) + .instrument(NoteBlockInstrument.BASS) + .requiresCorrectToolForDrops() + .strength(0.6F) + .sound(SoundType.METAL) + ) + ); + + public static final DeferredBlock POOP_LOG = registerBlock("poop_log", + () -> new RotatedPillarBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .noOcclusion() + .instrument(NoteBlockInstrument.BASS) + .strength(LOG) + .sound(SoundType.STONE) + ) + ); + + public static final DeferredBlock POOP_EMPTY_LOG = registerBlock("poop_empty_log", + () -> new EmptyRotatedPillarBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .noOcclusion() + .instrument(NoteBlockInstrument.BASS) + .strength(LOG) + .sound(SoundType.BAMBOO_WOOD) + ) + ); + + public static final DeferredBlock STRIPPED_POOP_LOG = registerBlock("stripped_poop_log", + () -> new RotatedPillarBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .noOcclusion() + .instrument(NoteBlockInstrument.BASS) + .strength(LOG) + .sound(SoundType.STONE) + ) + ); + + public static final DeferredBlock STRIPPED_POOP_EMPTY_LOG = registerBlock("stripped_poop_empty_log", + () -> new EmptyRotatedPillarBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .noOcclusion() + .instrument(NoteBlockInstrument.BASS) + .strength(LOG) + .sound(SoundType.BAMBOO_WOOD) + ) + ); + + public static final DeferredBlock POOP_LEAVES = registerBlock("poop_leaves", + () -> new LeavesBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .strength(0.2F) + .randomTicks() + .noOcclusion() + .sound(SoundType.SCULK_SENSOR) + .isValidSpawn(Blocks::ocelotOrParrot) + .isSuffocating(PSBlockProperties::neverSuffocate) + .isViewBlocking(PSBlockProperties::neverBlockVision) + .ignitedByLava() + .pushReaction(PushReaction.DESTROY) + .isRedstoneConductor(PSBlockProperties::never) + ) + ); + public static final DeferredBlock POOP_LEAVES_IRON = registerBlock("poop_leaves_iron", + () -> new LeavesBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.TERRACOTTA_WHITE) + .strength(0.2F) + .randomTicks() + .noOcclusion() + .sound(SoundType.SCULK_SENSOR) + .isValidSpawn(Blocks::ocelotOrParrot) + .isSuffocating(PSBlockProperties::neverSuffocate) + .isViewBlocking(PSBlockProperties::neverBlockVision) + .ignitedByLava() + .pushReaction(PushReaction.DESTROY) + .isRedstoneConductor(PSBlockProperties::never) + ) + ); + public static final DeferredBlock POOP_LEAVES_GOLD = registerBlock("poop_leaves_gold", + () -> new LeavesBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_YELLOW) + .strength(0.2F) + .randomTicks() + .noOcclusion() + .sound(SoundType.SCULK_SENSOR) + .isValidSpawn(Blocks::ocelotOrParrot) + .isSuffocating(PSBlockProperties::neverSuffocate) + .isViewBlocking(PSBlockProperties::neverBlockVision) + .ignitedByLava() + .pushReaction(PushReaction.DESTROY) + .isRedstoneConductor(PSBlockProperties::never) + ) + ); + + public static final DeferredBlock POOP_SAPLING = registerBlock("poop_sapling", + () -> new PoopTreeBlock(BlockBehaviour.Properties.of() + .mapColor(MapColor.COLOR_BROWN) + .noCollission() + .noOcclusion() + .instabreak() + .sound(SoundType.MUD) + .offsetType(BlockBehaviour.OffsetType.XZ) + .pushReaction(PushReaction.DESTROY) + ) + ); public static DeferredBlock registerBlock(String name, Supplier block) { DeferredBlock toReturn = BLOCKS.register(name, block); diff --git a/src/main/java/com/altnoir/poopsky/block/p/CompooperBlock.java b/src/main/java/com/altnoir/poopsky/block/p/CompooperBlock.java new file mode 100644 index 0000000..87e9383 --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/block/p/CompooperBlock.java @@ -0,0 +1,591 @@ +package com.altnoir.poopsky.block.p; + +import com.altnoir.poopsky.block.PSBlocks; +import com.altnoir.poopsky.item.PSItems; +import com.mojang.serialization.MapCodec; +import it.unimi.dsi.fastutil.objects.Object2FloatMap; +import it.unimi.dsi.fastutil.objects.Object2FloatOpenHashMap; +import net.minecraft.Util; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.DustColorTransitionOptions; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.stats.Stats; +import net.minecraft.util.RandomSource; +import net.minecraft.world.*; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.item.ItemEntity; +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.Items; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.ItemLike; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.CampfireBlock; +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.block.state.properties.IntegerProperty; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.pathfinder.PathComputationType; +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 org.joml.Vector3f; + +import javax.annotation.Nullable; + +public class CompooperBlock extends Block implements WorldlyContainerHolder { + public static final MapCodec CODEC = simpleCodec(CompooperBlock::new); + public static final int READY = 4; + public static final int MIN_LEVEL = 0; + public static final int MAX_LEVEL = 3; + public static final IntegerProperty LEVEL = IntegerProperty.create("level", MIN_LEVEL, READY); + public static final BooleanProperty LIQUID = BooleanProperty.create("liquid"); + public static final BooleanProperty POWERED = BooleanProperty.create("powered"); + public static final Object2FloatMap COMPOSTABLES = new Object2FloatOpenHashMap<>(); + private static final VoxelShape OUTER_SHAPE = Shapes.block(); + private static final VoxelShape[] SHAPES = Util.make(new VoxelShape[9], shapes -> { + for (int i = 0; i < READY; i++) { + shapes[i] = Shapes.join(OUTER_SHAPE, Block.box(2.0, Math.max(2, 1 + i * 2), 2.0, 14.0, 16.0, 14.0), BooleanOp.ONLY_FIRST); + } + + shapes[READY] = shapes[MAX_LEVEL]; + }); + + + @Override + public MapCodec codec() { + return CODEC; + } + + public static final Item[] SAPLINGS = new Item[] { + Items.OAK_SAPLING, + Items.SPRUCE_SAPLING, + Items.BIRCH_SAPLING, + Items.JUNGLE_SAPLING, + Items.ACACIA_SAPLING, + Items.DARK_OAK_SAPLING, + Items.MANGROVE_PROPAGULE, + Items.CHERRY_SAPLING + }; + + public static void bootStrap() { + COMPOSTABLES.defaultReturnValue(-1.0F); + float f = 0.3F; + float f1 = 0.5F; + float f2 = 0.65F; + float f3 = 0.85F; + float f4 = 1.0F; + add(0.1F, PSItems.POOP); + add(0.1F, PSItems.POOP_BALL); + //add(0.2F, PSBlocks.POOP_SAPLING); + //add(0.2F, PSBlocks.POOP_LEAVES); + add(0.1F, PSBlocks.POOP_PIECE); + add(0.3F, PSBlocks.POOP_BLOCK); + //add(0.3F, PSBlocks.POOP_STAIRS); + //add(0.15F, PSBlocks.POOP_SLAB); + //add(0.15F, PSBlocks.POOP_VERTICAL_SLAB); + //add(0.05F, PSBlocks.POOP_BUTTON); + //add(0.1F, PSBlocks.POOP_PRESSURE_PLATE); + //add(0.1F, PSBlocks.POOP_FENCE); + //add(0.1F, PSBlocks.POOP_FENCE_GATE); + //add(0.1F, PSBlocks.POOP_WALL); + //add(0.25F, PSBlocks.POOP_DOOR); + //add(0.15F, PSBlocks.POOP_TRAPDOOR); + //add(0.1F, PSBlocks.STOOL); + //add(0.2F, PSItems.BAKED_MAGGOTS); + //add(0.5F, PSItems.POOP_BREAD); + //add(0.1F, PSItems.MAGGOTS_SEEDS); + //add(1.0F, PSBlocks.POOP_CAKE); + } + + private static void add(float chance, ItemLike item) { + COMPOSTABLES.put(item.asItem(), chance); + } + + public CompooperBlock(Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition.any() + .setValue(LEVEL, 0) + .setValue(LIQUID, false) + .setValue(POWERED, false)); + } + + @Override + protected VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPES[state.getValue(LEVEL)]; + } + + @Override + protected VoxelShape getInteractionShape(BlockState state, BlockGetter level, BlockPos pos) { + return OUTER_SHAPE; + } + + @Override + protected VoxelShape getCollisionShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + return SHAPES[0]; + } + + @Override + protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean isMoving) { + if (state.getValue(LEVEL) == READY) { + level.scheduleTick(pos, state.getBlock(), 20); + } + } + + @Override + protected ItemInteractionResult useItemOn( + ItemStack stack, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hitResult + ) { + int i = state.getValue(LEVEL); + var hasLiquid = state.getValue(LIQUID); + if (i < READY) { + if (i < MAX_LEVEL && !level.isClientSide) { + if (stack.getItem() == Items.WATER_BUCKET) { + return waterBucketUse(level, pos, player, hand); + } + if (stack.getItem() == PSItems.URINE_BOTTLE.get() && ( hasLiquid || i == MIN_LEVEL)) { + return liquidItemUse(i, state, level, pos, player, hand); + } + if (!hasLiquid && getValue(stack) > 0) { + return itemUse(player, state, level, pos, stack); + } + } + return ItemInteractionResult.sidedSuccess(level.isClientSide); + } else { + return super.useItemOn(stack, state, level, pos, player, hand, hitResult); + } + } + + protected ItemInteractionResult waterBucketUse(Level level, BlockPos pos, Player player, InteractionHand hand) { + var stack = player.getItemInHand(hand); + level.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + + if (!level.isClientSide) { + var newState = defaultBlockState() + .setValue(LEVEL, READY) + .setValue(LIQUID, true); + level.setBlock(pos, newState, Block.UPDATE_ALL); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(player, newState)); + if (!player.getAbilities().instabuild) { + stack.shrink(1); + if (!player.getInventory().contains(new ItemStack(Items.BUCKET))) { + player.addItem(new ItemStack(Items.BUCKET)); + } + } + } + + return ItemInteractionResult.sidedSuccess(level.isClientSide); + } + + protected ItemInteractionResult liquidItemUse(int levelValue, BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand) { + var stack = player.getItemInHand(hand); + + if (levelValue < MAX_LEVEL && !level.isClientSide) { + addLiquidToComposter(state, level, pos, stack); + level.playSound(null, pos, SoundEvents.BUCKET_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + player.awardStat(Stats.ITEM_USED.get(stack.getItem())); + if (!player.getAbilities().instabuild) { + stack.shrink(1); + if (!player.getInventory().contains(new ItemStack(Items.GLASS_BOTTLE))) { + player.addItem(new ItemStack(Items.GLASS_BOTTLE)); + } + } + } + + return ItemInteractionResult.sidedSuccess(level.isClientSide); + } + + protected static void addLiquidToComposter(BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack) { + int i = state.getValue(LEVEL); + var f = 1.0F; + + if (i != 0 && !(level.getRandom().nextDouble() < f)) return; + + int j = i + 1; + + var blockState = state.setValue(LEVEL, j).setValue(LIQUID, true); + level.setBlock(pos, blockState, 3); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(blockState)); + if (j == MAX_LEVEL) { + level.scheduleTick(pos, state.getBlock(), 20); + } + } + + protected ItemInteractionResult itemUse(Player player, BlockState state, Level level, BlockPos pos, ItemStack stack) { + var newState = addItem(player, state, level, pos, stack); + level.levelEvent(1500, pos, !state.equals(newState) ? 1 : 0); + player.awardStat(Stats.ITEM_USED.get(stack.getItem())); + stack.consume(1, player); + return ItemInteractionResult.sidedSuccess(level.isClientSide); + } + + @Override + protected InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { + int i = state.getValue(LEVEL); + if (i == READY) { + if (!state.getValue(LIQUID)) { + extractProduce(player, state, level, pos); + } + else { + var stack = player.getItemInHand(InteractionHand.MAIN_HAND); + if (stack.getItem() == Items.BUCKET) { + if (!player.isCreative()) stack.shrink(1); + player.getInventory().add(new ItemStack(Items.WATER_BUCKET)); + empty(player, state, level, pos); + level.playSound(player, pos, SoundEvents.BUCKET_FILL, SoundSource.BLOCKS, 1.0F, 1.0F); + } + } + return InteractionResult.sidedSuccess(level.isClientSide); + } else { + return InteractionResult.PASS; + } + } + + public static BlockState insertItem(Entity entity, BlockState state, ServerLevel level, ItemStack stack, BlockPos pos) { + int i = state.getValue(LEVEL); + if (i < MAX_LEVEL && getValue(stack) > 0) { + var blockstate = addItem(entity, state, level, pos, stack); + stack.shrink(1); + return blockstate; + } else { + return state; + } + } + + public static BlockState extractProduce(Entity entity, BlockState state, Level level, BlockPos pos) { + if (!level.isClientSide) { + var vec3 = Vec3.atLowerCornerWithOffset(pos, 0.5, 1.01, 0.5).offsetRandom(level.random, 0.7F); + var itementity = new ItemEntity(level, vec3.x(), vec3.y(), vec3.z(), new ItemStack(randomProduce())); + itementity.setDefaultPickUpDelay(); + level.addFreshEntity(itementity); + } + + var blockstate = empty(entity, state, level, pos); + level.playSound(null, pos, SoundEvents.COMPOSTER_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F); + return blockstate; + } + + protected static BlockState empty(@Nullable Entity entity, BlockState state, LevelAccessor level, BlockPos pos) { + var blockstate = state.setValue(LEVEL, Integer.valueOf(MIN_LEVEL)).setValue(LIQUID, false); + level.setBlock(pos, blockstate, 3); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, blockstate)); + return blockstate; + } + + private static Item randomProduce() { + var random = RandomSource.create(); + return SAPLINGS[random.nextInt(SAPLINGS.length)]; + } + + protected static BlockState addItem(@Nullable Entity entity, BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack) { + int i = state.getValue(LEVEL); + var f = getValue(stack); + if ((i != MIN_LEVEL || !(f > 0.0F)) && !(level.getRandom().nextDouble() < (double)f)) { + return state; + } else { + var j = i + 1; + var blockstate = state.setValue(LEVEL, j).setValue(LIQUID, false); + level.setBlock(pos, blockstate, 3); + level.gameEvent(GameEvent.BLOCK_CHANGE, pos, GameEvent.Context.of(entity, blockstate)); + if (j == MAX_LEVEL) { + level.scheduleTick(pos, state.getBlock(), 20); + } + + return blockstate; + } + } + + public void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + if (state.getValue(LEVEL) == MAX_LEVEL && (!state.getValue(LIQUID) || hasFire(level, pos))) { + if (state.getValue(LIQUID)) { + level.playSound(null, pos, SoundEvents.BREWING_STAND_BREW, SoundSource.BLOCKS, 1.0F, 1.0F); + + var waterColor = level.getBiome(pos).value().getWaterColor(); + var red = (waterColor >> 16 & 0xFF) / 255.0F; + var green = (waterColor >> 8 & 0xFF) / 255.0F; + var blue = (waterColor & 0xFF) / 255.0F; + + var color = new Vector3f(red, green, blue); + + level.sendParticles( + new DustColorTransitionOptions(color, color, 1.0F), + pos.getX() + 0.5, + pos.getY() + 1.2, + pos.getZ() + 0.5, + 15, + 0.3, 0.1, 0.3, + 0.02 + ); + } else { + level.playSound(null, pos, SoundEvents.COMPOSTER_READY, SoundSource.BLOCKS, 1.0F, 1.0F); + } + level.setBlock(pos, state.cycle(LEVEL), Block.UPDATE_ALL); + } + level.scheduleTick(pos, this, 20); + } + + @Override + public void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + if (!state.getValue(LIQUID) && state.getValue(LEVEL) == MIN_LEVEL) { + var biome = level.getBiome(pos).value(); + var precipitation = biome.getPrecipitationAt(pos); + var isRaining = level.isRaining() && level.canSeeSky(pos); + + if (!isRaining) return; + + boolean canFill = false; + if (precipitation == Biome.Precipitation.RAIN) { + canFill = random.nextFloat() < 0.05F; + } else if (precipitation == Biome.Precipitation.SNOW) { + canFill = random.nextFloat() < 0.1F; + } + + if (canFill) { + var newState = state.setValue(LIQUID, true).setValue(LEVEL, READY); + level.setBlock(pos, newState, Block.UPDATE_ALL); + level.gameEvent(null, GameEvent.BLOCK_CHANGE, pos); + } + } + } + + @Override + public void neighborChanged(BlockState state, Level level, BlockPos pos, Block blockIn, BlockPos fromPos, boolean isMoving) { + boolean hasPower = level.hasNeighborSignal(pos); + if (hasPower != state.getValue(POWERED)) { + level.setBlock(pos, state.setValue(POWERED, hasPower), Block.UPDATE_ALL); + + if (hasPower && !level.isClientSide) { + var be = level.getBlockEntity(pos.below()); + + if (!(be instanceof Container container)) return; + + for (int slot = 0; slot < container.getContainerSize(); slot++) { + var stack = container.getItem(slot); + if (stack.isEmpty()) continue; + + var block = Block.byItem(stack.getItem()); + if (block == null || block.defaultBlockState().isAir()) { + if (stack.getItem() instanceof BlockItem bi) { + block = bi.getBlock(); + } + } + + if (block == null || block.defaultBlockState().isAir()) continue; + + var targetPos = pos.above(); + var targetState = level.getBlockState(targetPos); + + if (!level.isOutsideBuildHeight(targetPos) && isReplaceable(targetState)) { + if (level.setBlock(targetPos, block.defaultBlockState(), Block.UPDATE_ALL)) { + try { + var placeSound = block.defaultBlockState().getSoundType().getPlaceSound(); + level.playSound(null, targetPos, placeSound, SoundSource.BLOCKS, 1.0F, 1.0F); + } catch (Exception e) { + level.playSound(null, targetPos, SoundEvents.GRASS_PLACE, SoundSource.BLOCKS, 1.0F, 1.0F); + } + container.removeItem(slot, 1); + break; + } + } else { + System.out.println(targetState.getBlock().getName().getString() + " False"); + break; + } + } + } + } + + if (fromPos.equals(pos.below()) && state.getValue(LEVEL) == MAX_LEVEL && hasFire((ServerLevel)level, pos)) { + level.scheduleTick(pos, this, 20); + } + + super.neighborChanged(state, level, pos, blockIn, fromPos, isMoving); + } + + private boolean isReplaceable(BlockState state) { + return state.isAir() || + state.is(Blocks.WATER) || + state.is(Blocks.LAVA); + } + + @Override + protected boolean hasAnalogOutputSignal(BlockState state) { + return true; + } + + @Override + protected int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos) { + return blockState.getValue(LEVEL); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(LEVEL); + builder.add(LIQUID); + builder.add(POWERED); + } + + @Override + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } + + private boolean hasFire(ServerLevel level, BlockPos pos) { + BlockState state = level.getBlockState(pos.below()); + return state.is(Blocks.FIRE) + || state.is(Blocks.MAGMA_BLOCK) + || (state.is(Blocks.CAMPFIRE) && state.getValue(CampfireBlock.LIT)) + || (state.is(Blocks.SOUL_CAMPFIRE) && state.getValue(CampfireBlock.LIT)); + } + + @Override + public WorldlyContainer getContainer(BlockState state, LevelAccessor level, BlockPos pos) { + int i = state.getValue(LEVEL); + if (i == READY) { + return new CompooperBlock.OutputContainer(state, level, pos, new ItemStack(randomProduce())); + } else { + return i < 7 ? new InputContainer(state, level, pos) : new EmptyContainer(); + } + } + + static class EmptyContainer extends SimpleContainer implements WorldlyContainer { + public EmptyContainer() { + super(0); + } + + @Override + public int[] getSlotsForFace(Direction side) { + return new int[0]; + } + + /** + * Returns {@code true} if automation can insert the given item in the given slot from the given side. + */ + @Override + public boolean canPlaceItemThroughFace(int index, ItemStack itemStack, @Nullable Direction direction) { + return false; + } + + /** + * Returns {@code true} if automation can extract the given item in the given slot from the given side. + */ + @Override + public boolean canTakeItemThroughFace(int index, ItemStack stack, Direction direction) { + return false; + } + } + + static class InputContainer extends SimpleContainer implements WorldlyContainer { + private final BlockState state; + private final LevelAccessor level; + private final BlockPos pos; + private boolean changed; + + public InputContainer(BlockState state, LevelAccessor level, BlockPos pos) { + super(1); + this.state = state; + this.level = level; + this.pos = pos; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Override + public int[] getSlotsForFace(Direction side) { + return side == Direction.UP ? new int[]{0} : new int[0]; + } + + /** + * Returns {@code true} if automation can insert the given item in the given slot from the given side. + */ + @Override + public boolean canPlaceItemThroughFace(int index, ItemStack itemStack, @Nullable Direction direction) { + return !this.changed && direction == Direction.UP && getValue(itemStack) > 0f; + } + + /** + * Returns {@code true} if automation can extract the given item in the given slot from the given side. + */ + @Override + public boolean canTakeItemThroughFace(int index, ItemStack stack, Direction direction) { + return false; + } + + @Override + public void setChanged() { + ItemStack itemstack = this.getItem(0); + if (!itemstack.isEmpty()) { + this.changed = true; + BlockState blockstate = CompooperBlock.addItem(null, this.state, this.level, this.pos, itemstack); + this.level.levelEvent(1500, this.pos, blockstate != this.state ? 1 : 0); + this.removeItemNoUpdate(0); + } + } + } + + static class OutputContainer extends SimpleContainer implements WorldlyContainer { + private final BlockState state; + private final LevelAccessor level; + private final BlockPos pos; + private boolean changed; + + public OutputContainer(BlockState state, LevelAccessor level, BlockPos pos, ItemStack stack) { + super(stack); + this.state = state; + this.level = level; + this.pos = pos; + } + + @Override + public int getMaxStackSize() { + return 1; + } + + @Override + public int[] getSlotsForFace(Direction side) { + return side == Direction.DOWN ? new int[]{0} : new int[0]; + } + + /** + * Returns {@code true} if automation can insert the given item in the given slot from the given side. + */ + @Override + public boolean canPlaceItemThroughFace(int index, ItemStack itemStack, @Nullable Direction direction) { + return false; + } + + /** + * Returns {@code true} if automation can extract the given item in the given slot from the given side. + */ + @Override + public boolean canTakeItemThroughFace(int index, ItemStack stack, Direction direction) { + return !this.changed && direction == Direction.DOWN && stack.is(Items.BONE_MEAL); + } + + @Override + public void setChanged() { + CompooperBlock.empty(null, this.state, this.level, this.pos); + this.changed = true; + } + } + + public static float getValue(ItemStack stack) { + float value = COMPOSTABLES.getFloat(stack.getItem()); + return value == 0f ? -1f : value; + } +} diff --git a/src/main/java/com/altnoir/poopsky/block/p/EmptyRotatedPillarBlock.java b/src/main/java/com/altnoir/poopsky/block/p/EmptyRotatedPillarBlock.java new file mode 100644 index 0000000..1148007 --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/block/p/EmptyRotatedPillarBlock.java @@ -0,0 +1,88 @@ +package com.altnoir.poopsky.block.p; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.EnumProperty; +import net.minecraft.world.level.pathfinder.PathComputationType; +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; + +public class EmptyRotatedPillarBlock extends Block { + public static final EnumProperty AXIS = EnumProperty.create("axis", Direction.Axis.class); + + private static final VoxelShape RAYCAST_SHAPE_1 = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 16.0D, 14.0D); + private static final VoxelShape RAYCAST_SHAPE_2 = Block.box(2.0D, 2.0D, 0.0D, 14.0D, 14.0D, 16.0D); + private static final VoxelShape RAYCAST_SHAPE_3 = Block.box(0.0D, 2.0D, 2.0D, 16.0D, 14.0D, 14.0D); + private static final VoxelShape RAYCAST_SHAPE = Shapes.block(); + + private static final VoxelShape OUTLINE_SHAPE_1 = Shapes.joinUnoptimized( + RAYCAST_SHAPE, + RAYCAST_SHAPE_1, + BooleanOp.ONLY_FIRST + ); + private static final VoxelShape OUTLINE_SHAPE_2 = Shapes.joinUnoptimized( + RAYCAST_SHAPE, + RAYCAST_SHAPE_2, + BooleanOp.ONLY_FIRST + ); + private static final VoxelShape OUTLINE_SHAPE_3 = Shapes.joinUnoptimized( + RAYCAST_SHAPE, + RAYCAST_SHAPE_3, + BooleanOp.ONLY_FIRST + ); + + public EmptyRotatedPillarBlock(Properties properties) { + super(properties); + this.registerDefaultState(this.stateDefinition.any().setValue(AXIS, Direction.Axis.Y)); + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(AXIS); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + Direction facing = context.getClickedFace(); + return this.defaultBlockState().setValue(AXIS, facing.getAxis()); + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + return switch (state.getValue(AXIS)) { + case X -> OUTLINE_SHAPE_3; + case Z -> OUTLINE_SHAPE_2; + default -> OUTLINE_SHAPE_1; + }; + } + + @Override + public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { + return RAYCAST_SHAPE; + } + + @Override + public BlockState rotate(BlockState state, Rotation rotation) { + Direction.Axis axis = state.getValue(AXIS); + switch (rotation) { + case CLOCKWISE_90, COUNTERCLOCKWISE_90 -> { + if (axis == Direction.Axis.X) return state.setValue(AXIS, Direction.Axis.Z); + else if (axis == Direction.Axis.Z) return state.setValue(AXIS, Direction.Axis.X); + } + } + return state; + } + + @Override + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } +} diff --git a/src/main/java/com/altnoir/poopsky/block/p/PoopTreeBlock.java b/src/main/java/com/altnoir/poopsky/block/p/PoopTreeBlock.java new file mode 100644 index 0000000..04f3387 --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/block/p/PoopTreeBlock.java @@ -0,0 +1,70 @@ +package com.altnoir.poopsky.block.p; + +import com.altnoir.poopsky.PoopSky; +import com.altnoir.poopsky.tag.PSBlockTags; +import com.altnoir.poopsky.worldgen.PSConfigureFeatures; +import com.mojang.serialization.MapCodec; +import net.minecraft.core.BlockPos; +import net.minecraft.core.registries.Registries; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.util.RandomSource; +import net.minecraft.world.level.BlockGetter; +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.BonemealableBlock; +import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.grower.TreeGrower; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.Optional; + +public class PoopTreeBlock extends SaplingBlock implements BonemealableBlock { + public static final MapCodec CODEC = simpleCodec(PoopTreeBlock::new); + public static final TreeGrower treeGrower = new TreeGrower(PoopSky.MOD_ID + ":poop_tree", + Optional.of(PSConfigureFeatures.MEGA_POOP_TREE), + Optional.of(PSConfigureFeatures.POOP_TREE), + Optional.empty()); + private static final VoxelShape SHAPE = Shapes.or( + Block.box(3.0, 8.0, 3.0, 13.0, 15.0, 13.0), + Block.box(6.0, 0.0, 6.0, 10.0, 8.0, 10.0) + ); + + public PoopTreeBlock(Properties properties) { + super(treeGrower, properties); + } + + @Override + public MapCodec codec() { + return CODEC; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter level, BlockPos pos, CollisionContext context) { + var offset = state.getOffset(level, pos); + return SHAPE.move(offset.x, offset.y, offset.z); + } + + @Override + protected boolean mayPlaceOn(BlockState state, BlockGetter level, BlockPos pos) { + return state.is(PSBlockTags.TOILET_BLOCKS) || super.mayPlaceOn(state, level, pos); + } + + @Override + public boolean isValidBonemealTarget(LevelReader levelReader, BlockPos blockPos, BlockState blockState) { + return levelReader.getFluidState(blockPos.above()).isEmpty(); + } + + @Override + public boolean isBonemealSuccess(Level level, RandomSource random, BlockPos pos, BlockState state) { + return random.nextFloat() < 0.45F; + } + + protected boolean isPathfindable(BlockState state, PathComputationType pathComputationType) { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/altnoir/poopsky/block/p/ToiletLavaBlock.java b/src/main/java/com/altnoir/poopsky/block/p/ToiletLavaBlock.java index ee4a413..a407a03 100644 --- a/src/main/java/com/altnoir/poopsky/block/p/ToiletLavaBlock.java +++ b/src/main/java/com/altnoir/poopsky/block/p/ToiletLavaBlock.java @@ -7,9 +7,7 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.ItemInteractionResult; -import net.minecraft.world.effect.MobEffects; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; @@ -47,7 +45,7 @@ public BlockState getStateForPlacement(BlockPlaceContext context) { @Override public void stepOn(Level level, BlockPos pos, BlockState state, Entity entity) { - if (!level.isClientSide && entity instanceof Player player && player.isShiftKeyDown() && isPlayerCentered(pos, player) && !state.getValue(LAVA)) { + if (!level.isClientSide && entity instanceof Player player && player.isShiftKeyDown() && isEntityCentered(pos, player) && !state.getValue(LAVA)) { if (player.hasEffect(PSEffects.FECAL_INCONTINENCE)) { onPoop(level, player); player.causeFoodExhaustion(0.05F); diff --git a/src/main/java/com/altnoir/poopsky/component/PFoods.java b/src/main/java/com/altnoir/poopsky/component/PFoods.java index ef8cf75..f8fb14b 100644 --- a/src/main/java/com/altnoir/poopsky/component/PFoods.java +++ b/src/main/java/com/altnoir/poopsky/component/PFoods.java @@ -22,4 +22,6 @@ public class PFoods { .effect(new MobEffectInstance(MobEffects.BLINDNESS, 20, 0), 1.0F) .effect(new MobEffectInstance(MobEffects.DARKNESS, 60, 0), 1.0F) .build(); + + public static final FoodProperties URINE_BOTTLE = new FoodProperties.Builder().build(); } diff --git a/src/main/java/com/altnoir/poopsky/datagen/PSBlockLootTableProvider.java b/src/main/java/com/altnoir/poopsky/datagen/PSBlockLootTableProvider.java index b6c3448..647eb8c 100644 --- a/src/main/java/com/altnoir/poopsky/datagen/PSBlockLootTableProvider.java +++ b/src/main/java/com/altnoir/poopsky/datagen/PSBlockLootTableProvider.java @@ -1,8 +1,11 @@ package com.altnoir.poopsky.datagen; import com.altnoir.poopsky.block.PSBlocks; +import com.altnoir.poopsky.block.ToiletBlocks; import com.altnoir.poopsky.block.p.PoopPiece; import com.altnoir.poopsky.item.PSItems; +import net.minecraft.advancements.critereon.EnchantmentPredicate; +import net.minecraft.advancements.critereon.ItemPredicate; import net.minecraft.advancements.critereon.StatePropertiesPredicate; import net.minecraft.core.Holder; import net.minecraft.core.HolderLookup; @@ -10,6 +13,7 @@ import net.minecraft.data.loot.BlockLootSubProvider; import net.minecraft.world.flag.FeatureFlags; import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; import net.minecraft.world.item.enchantment.Enchantment; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.level.block.Block; @@ -22,10 +26,14 @@ import net.minecraft.world.level.storage.loot.functions.SetItemCountFunction; import net.minecraft.world.level.storage.loot.predicates.*; import net.minecraft.world.level.storage.loot.providers.number.ConstantValue; +import net.minecraft.world.level.storage.loot.providers.number.UniformGenerator; +import net.neoforged.neoforge.registries.DeferredHolder; import org.jetbrains.annotations.NotNull; import java.util.Set; +import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; public class PSBlockLootTableProvider extends BlockLootSubProvider { protected PSBlockLootTableProvider(HolderLookup.Provider registries) { @@ -34,7 +42,20 @@ protected PSBlockLootTableProvider(HolderLookup.Provider registries) { @Override protected void generate() { + ToiletBlocks.BLOCKS.getEntries().stream() + .map(DeferredHolder::get) + .forEach(this::dropSelf); + + this.add(PSBlocks.POOP_LOG.get(), this::createSpallOreDrops); + this.add(PSBlocks.STRIPPED_POOP_LOG.get(), this::createSpallOreDrops); + this.add(PSBlocks.POOP_LEAVES_IRON.get(), this::createIronLeavesDrops); + this.add(PSBlocks.POOP_LEAVES_GOLD.get(), this::createGoldLeavesDrops); + this.add(PSBlocks.POOP_LEAVES.get(), this::createLeavesDrops); + dropSelf(PSBlocks.POOP_SAPLING.get()); + dropSelf(PSBlocks.POOP_EMPTY_LOG.get()); + dropSelf(PSBlocks.STRIPPED_POOP_EMPTY_LOG.get()); dropSelf(PSBlocks.POOP_BLOCK.get()); + dropSelf(PSBlocks.COMPOOPER.get()); add(PSBlocks.POOP_PIECE.get(), createPoopPieceDrop(PSBlocks.POOP_PIECE.get(), PSItems.POOP_BALL.get())); } @@ -70,8 +91,57 @@ protected void generate() { ); } + protected LootTable.Builder createSpallOreDrops(Block block) { + var registrylookup = this.registries.lookupOrThrow(Registries.ENCHANTMENT); + return this.createSilkTouchDispatchTable(block, + this.applyExplosionDecay(block, + LootItem.lootTableItem(PSItems.SPALL) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(4.0F, 5.0F))) + .apply(ApplyBonusCount.addUniformBonusCount(registrylookup.getOrThrow(Enchantments.FORTUNE))) + ) + ); + } + + protected LootTable.Builder createIronLeavesDrops(Block block) { + var registrylookup = this.registries.lookupOrThrow(Registries.ENCHANTMENT); + return this.createSilkTouchDispatchTable(block, + this.applyExplosionDecay(block, + LootItem.lootTableItem(Items.IRON_NUGGET) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(0.0F, 3.0F))) + .apply(ApplyBonusCount.addUniformBonusCount(registrylookup.getOrThrow(Enchantments.FORTUNE))) + ) + ); + } + + protected LootTable.Builder createGoldLeavesDrops(Block block) { + var registrylookup = this.registries.lookupOrThrow(Registries.ENCHANTMENT); + return this.createSilkTouchDispatchTable(block, + this.applyExplosionDecay(block, + LootItem.lootTableItem(Items.GOLD_NUGGET) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(0.0F, 2.0F))) + .apply(ApplyBonusCount.addUniformBonusCount(registrylookup.getOrThrow(Enchantments.FORTUNE))) + ) + ); + } + + protected LootTable.Builder createLeavesDrops(Block block) { + var registrylookup = this.registries.lookupOrThrow(Registries.ENCHANTMENT); + return this.createSilkTouchDispatchTable(block, + this.applyExplosionDecay(block, + LootItem.lootTableItem(PSItems.POOP) + .apply(SetItemCountFunction.setCount(UniformGenerator.between(0.0F, 1.0F))) + .apply(ApplyBonusCount.addUniformBonusCount(registrylookup.getOrThrow(Enchantments.FORTUNE))) + ) + ); + } + @Override protected Iterable getKnownBlocks() { - return PSBlocks.BLOCKS.getEntries().stream().map(Holder::value)::iterator; + return Stream.concat( + PSBlocks.BLOCKS.getEntries().stream(), + ToiletBlocks.BLOCKS.getEntries().stream() + ) + .map(Holder::value) + .collect(Collectors.toList()); } } \ No newline at end of file diff --git a/src/main/java/com/altnoir/poopsky/datagen/PSBlockStateProvider.java b/src/main/java/com/altnoir/poopsky/datagen/PSBlockStateProvider.java index b405e30..bf5ae5a 100644 --- a/src/main/java/com/altnoir/poopsky/datagen/PSBlockStateProvider.java +++ b/src/main/java/com/altnoir/poopsky/datagen/PSBlockStateProvider.java @@ -88,6 +88,10 @@ protected void registerStatesAndModels() { simpleBlockItem(PSBlocks.POOP_BLOCK.get(), models().getExistingFile(modLoc("block/poop_block1"))); simpleBlockItem(PSBlocks.POOP_PIECE.get(), models().getExistingFile(modLoc("block/poop_height2"))); + blockWithItem(PSBlocks.POOP_LEAVES.get()); + blockWithItem(PSBlocks.POOP_LEAVES_GOLD.get()); + blockWithItem(PSBlocks.POOP_LEAVES_IRON.get()); + registerToilet(ToiletBlocks.OAK_TOILET.get(), Blocks.OAK_PLANKS); registerToilet(ToiletBlocks.SPRUCE_TOILET.get(), Blocks.SPRUCE_PLANKS); registerToilet(ToiletBlocks.BIRCH_TOILET.get(), Blocks.BIRCH_PLANKS); @@ -206,4 +210,8 @@ private void registerToiletLava(Block toilet, Object texture) { itemModels().getBuilder(BuiltInRegistries.BLOCK.getKey(toilet).getPath()) .parent(baseModel); } + + private void blockWithItem(Block block) { + simpleBlockWithItem(block, cubeAll(block)); + } } diff --git a/src/main/java/com/altnoir/poopsky/datagen/PSBlockTagProvider.java b/src/main/java/com/altnoir/poopsky/datagen/PSBlockTagProvider.java index e14a3eb..98fe30b 100644 --- a/src/main/java/com/altnoir/poopsky/datagen/PSBlockTagProvider.java +++ b/src/main/java/com/altnoir/poopsky/datagen/PSBlockTagProvider.java @@ -2,11 +2,14 @@ import com.altnoir.poopsky.PoopSky; import com.altnoir.poopsky.block.PSBlocks; +import com.altnoir.poopsky.block.ToiletBlocks; +import com.altnoir.poopsky.tag.PSBlockTags; import net.minecraft.core.HolderLookup; import net.minecraft.data.PackOutput; import net.minecraft.tags.BlockTags; import net.neoforged.neoforge.common.data.BlockTagsProvider; import net.neoforged.neoforge.common.data.ExistingFileHelper; +import net.neoforged.neoforge.registries.DeferredHolder; import org.jetbrains.annotations.Nullable; import java.util.concurrent.CompletableFuture; @@ -23,5 +26,21 @@ protected void addTags(HolderLookup.Provider provider) { tag(BlockTags.MINEABLE_WITH_SHOVEL) .add(PSBlocks.POOP_PIECE.get()); + + tag(BlockTags.MINEABLE_WITH_PICKAXE) + .add(PSBlocks.COMPOOPER.get()); + + ToiletBlocks.BLOCKS.getEntries().stream() + .map(DeferredHolder::get) + .forEach(toilet -> { + tag(PSBlockTags.TOILET_BLOCKS) + .add(toilet); + }); + + tag(BlockTags.LOGS) + .add(PSBlocks.POOP_LOG.get()) + .add(PSBlocks.POOP_EMPTY_LOG.get()) + .add(PSBlocks.STRIPPED_POOP_LOG.get()) + .add(PSBlocks.STRIPPED_POOP_EMPTY_LOG.get()); } } diff --git a/src/main/java/com/altnoir/poopsky/datagen/PSItemModelProvider.java b/src/main/java/com/altnoir/poopsky/datagen/PSItemModelProvider.java index e91c465..aa3deea 100644 --- a/src/main/java/com/altnoir/poopsky/datagen/PSItemModelProvider.java +++ b/src/main/java/com/altnoir/poopsky/datagen/PSItemModelProvider.java @@ -20,5 +20,6 @@ protected void registerModels() { basicItem(PSItems.SPALL.get()); basicItem(PSItems.LAWRENCE_MUSIC_DISC.get()); basicItem(PSItems.TOILET_LINKER.get()); + basicItem(PSItems.URINE_BOTTLE.get()); } } diff --git a/src/main/java/com/altnoir/poopsky/entity/p/ToiletPlugEntity.java b/src/main/java/com/altnoir/poopsky/entity/p/ToiletPlugEntity.java index 0863434..621c4c5 100644 --- a/src/main/java/com/altnoir/poopsky/entity/p/ToiletPlugEntity.java +++ b/src/main/java/com/altnoir/poopsky/entity/p/ToiletPlugEntity.java @@ -290,6 +290,11 @@ public boolean isPushable() { return true; } + @Override + public boolean isVehicle(){ + return true; + } + @Override public void remove(Entity.RemovalReason reason) { if (!this.level().isClientSide && reason.shouldDestroy() && this.isLeashed()) { diff --git a/src/main/java/com/altnoir/poopsky/event/GlassBottleEvent.java b/src/main/java/com/altnoir/poopsky/event/GlassBottleEvent.java new file mode 100644 index 0000000..de84793 --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/event/GlassBottleEvent.java @@ -0,0 +1,43 @@ +package com.altnoir.poopsky.event; + +import com.altnoir.poopsky.PoopSky; +import com.altnoir.poopsky.item.PSItems; +import com.altnoir.poopsky.tag.PSBlockTags; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.item.BottleItem; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemUtils; +import net.minecraft.world.level.gameevent.GameEvent; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.EventBusSubscriber; +import net.neoforged.neoforge.event.entity.player.PlayerInteractEvent; + +@EventBusSubscriber(modid = PoopSky.MOD_ID) +public class GlassBottleEvent { + @SubscribeEvent + public static void onRightClickBlock(PlayerInteractEvent.RightClickBlock event) { + var level = event.getLevel(); + var player = event.getEntity(); + var pos = event.getPos(); + var hand = event.getHand(); + var heldItem = player.getItemInHand(hand); + + if (!(heldItem.getItem() instanceof BottleItem)) return; + if (!level.getBlockState(pos).is(PSBlockTags.TOILET_BLOCKS)) return; + + if (!level.isClientSide) { + level.playSound(null, pos, SoundEvents.BOTTLE_FILL, SoundSource.PLAYERS, 1.0F, 1.0F); + level.gameEvent(player, GameEvent.FLUID_PICKUP, pos); + + var urineBottle = new ItemStack(PSItems.URINE_BOTTLE.get()); + var result = ItemUtils.createFilledResult(heldItem, player, urineBottle); + + player.setItemInHand(hand, result); + } + + event.setCancellationResult(InteractionResult.SUCCESS); + event.setCanceled(true); + } +} diff --git a/src/main/java/com/altnoir/poopsky/item/PSItems.java b/src/main/java/com/altnoir/poopsky/item/PSItems.java index 94dcafa..d6f8002 100644 --- a/src/main/java/com/altnoir/poopsky/item/PSItems.java +++ b/src/main/java/com/altnoir/poopsky/item/PSItems.java @@ -6,6 +6,7 @@ import com.altnoir.poopsky.component.ToiletComponent; import com.altnoir.poopsky.sound.PSSoundEvents; import net.minecraft.world.item.Item; +import net.minecraft.world.item.Items; import net.minecraft.world.item.Rarity; import net.neoforged.bus.api.IEventBus; import net.neoforged.neoforge.registries.DeferredItem; @@ -29,6 +30,13 @@ public class PSItems { new ToiletLinkerItem(new Item.Properties() .component(PSComponents.TOILET_COMPONENT, ToiletComponent.EMPTY) .stacksTo(1))); + public static final DeferredItem URINE_BOTTLE = ITEMS.register("urine_bottle", + () -> new UrineBottleItem(new Item.Properties() + .craftRemainder(Items.GLASS_BOTTLE) + .food(PFoods.URINE_BOTTLE) + .stacksTo(16) + ) + ); public static final DeferredItem LAWRENCE_MUSIC_DISC = ITEMS.register("music_disc_lawrence", () -> new Item(new Item.Properties().jukeboxPlayable(PSSoundEvents.LAWRENCE_KEY).rarity(Rarity.RARE).stacksTo(1))); diff --git a/src/main/java/com/altnoir/poopsky/item/UrineBottleItem.java b/src/main/java/com/altnoir/poopsky/item/UrineBottleItem.java new file mode 100644 index 0000000..568608e --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/item/UrineBottleItem.java @@ -0,0 +1,89 @@ +package com.altnoir.poopsky.item; + +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.stats.Stats; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.animal.Chicken; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemUtils; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.UseAnim; +import net.minecraft.world.item.alchemy.PotionContents; +import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.level.Level; + +public class UrineBottleItem extends PSBaseItem { + public UrineBottleItem(Properties properties) { + super(properties); + } + + @Override + public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entity) { + var result = super.finishUsingItem(stack, level, entity); + + if (entity instanceof ServerPlayer player) { + player.awardStat(Stats.ITEM_USED.get(this)); + CriteriaTriggers.CONSUME_ITEM.trigger(player, stack); + } + + if (!level.isClientSide) { + entity.addEffect(new MobEffectInstance(MobEffects.POISON, 600, 0)); + } + + if (stack.isEmpty()) { + return new ItemStack(Items.GLASS_BOTTLE); + } else { + if (entity instanceof Player player && !player.getAbilities().instabuild) { + ItemStack glassBottle = new ItemStack(Items.GLASS_BOTTLE); + if (!player.getInventory().add(glassBottle)) { + player.drop(glassBottle, false); + } + } + return stack; + } + } + + @Override + public InteractionResult interactLivingEntity(ItemStack stack, Player player, LivingEntity entity, InteractionHand hand) { + if (!player.level().isClientSide) { + if (entity.isAlive() && entity instanceof Chicken chicken) { + var waterPotion = PotionContents.createItemStack(Items.POTION, Potions.WATER); + + chicken.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SPEED, 1200, 1)); + chicken.hurt(player.damageSources().playerAttack(player), 1.0F); + stack.shrink(1); + entity.spawnAtLocation(waterPotion); + } + } + return super.interactLivingEntity(stack, player, entity, hand); + } + + @Override + public UseAnim getUseAnimation(ItemStack stack) { + return UseAnim.DRINK; + } + + @Override + public SoundEvent getDrinkingSound() { + return SoundEvents.GENERIC_DRINK; + } + + @Override + public SoundEvent getEatingSound() { + return SoundEvents.GENERIC_DRINK; + } + + @Override + public InteractionResultHolder use(Level world, Player player, InteractionHand hand) { + return ItemUtils.startUsingInstantly(world, player, hand); + } +} diff --git a/src/main/java/com/altnoir/poopsky/tag/PSBlockTags.java b/src/main/java/com/altnoir/poopsky/tag/PSBlockTags.java new file mode 100644 index 0000000..2296c7f --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/tag/PSBlockTags.java @@ -0,0 +1,17 @@ +package com.altnoir.poopsky.tag; + +import com.altnoir.poopsky.PoopSky; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.block.Block; + +public class PSBlockTags { + public static final TagKey TOILET_BLOCKS = create("toilet_blocks"); + public static final TagKey POOP_BLOCKS = create("poop_blocks"); + public static final TagKey CONVERTABLE_TO_MOSS = create("convertable_to_moss"); + + private static TagKey create(String name) { + return TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(PoopSky.MOD_ID, name)); + } +} diff --git a/src/main/java/com/altnoir/poopsky/worldgen/PSConfigureFeatures.java b/src/main/java/com/altnoir/poopsky/worldgen/PSConfigureFeatures.java index e2eea8b..4d6b06d 100644 --- a/src/main/java/com/altnoir/poopsky/worldgen/PSConfigureFeatures.java +++ b/src/main/java/com/altnoir/poopsky/worldgen/PSConfigureFeatures.java @@ -1,17 +1,68 @@ package com.altnoir.poopsky.worldgen; import com.altnoir.poopsky.PoopSky; +import com.altnoir.poopsky.block.PSBlocks; +import com.altnoir.poopsky.worldgen.foliage.PoopMegaFoliagePlacer; import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.BootstrapContext; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.random.SimpleWeightedRandomList; +import net.minecraft.util.valueproviders.ConstantInt; +import net.minecraft.util.valueproviders.UniformInt; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.feature.Feature; +import net.minecraft.world.level.levelgen.feature.TreeFeature; import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; +import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration; +import net.minecraft.world.level.levelgen.feature.featuresize.TwoLayersFeatureSize; +import net.minecraft.world.level.levelgen.feature.foliageplacers.RandomSpreadFoliagePlacer; +import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; +import net.minecraft.world.level.levelgen.feature.stateproviders.WeightedStateProvider; +import net.minecraft.world.level.levelgen.feature.trunkplacers.GiantTrunkPlacer; +import net.minecraft.world.level.levelgen.feature.trunkplacers.StraightTrunkPlacer; public class PSConfigureFeatures { + public static final ResourceKey> POOP_TREE = resourceKey("poop_tree"); + public static final ResourceKey> MEGA_POOP_TREE = resourceKey("mega_poop_tree"); + public static void bootstrap(BootstrapContext> context) { + register(context, POOP_TREE, Feature.TREE, new TreeConfiguration.TreeConfigurationBuilder( + BlockStateProvider.simple(PSBlocks.POOP_LOG.get()), + new StraightTrunkPlacer(3, 1, 1), + new WeightedStateProvider(SimpleWeightedRandomList.builder() + .add(PSBlocks.POOP_LEAVES.get().defaultBlockState(), 11) + .add(PSBlocks.POOP_LEAVES_IRON.get().defaultBlockState(), 3) + .add(PSBlocks.POOP_LEAVES_GOLD.get().defaultBlockState(), 1) + .build()), + new RandomSpreadFoliagePlacer(ConstantInt.of(3), ConstantInt.of(0), ConstantInt.of(2), 114), + new TwoLayersFeatureSize(2, 0, 2) + ) + .dirt(BlockStateProvider.simple(Blocks.MUD)) + .forceDirt() + .build() + ); + + register(context, MEGA_POOP_TREE, Feature.TREE, new TreeConfiguration.TreeConfigurationBuilder( + BlockStateProvider.simple(PSBlocks.POOP_LOG.get()), + new GiantTrunkPlacer(12, 2, 14), + + new WeightedStateProvider(SimpleWeightedRandomList.builder() + .add(PSBlocks.POOP_LEAVES.get().defaultBlockState(), 11) + .add(PSBlocks.POOP_LEAVES_IRON.get().defaultBlockState(), 3) + .add(PSBlocks.POOP_LEAVES_GOLD.get().defaultBlockState(), 1) + .build()), + new PoopMegaFoliagePlacer(ConstantInt.of(0), ConstantInt.of(3), UniformInt.of(13, 17)), + new TwoLayersFeatureSize(1, 1, 2) + ) + .dirt(BlockStateProvider.simple(Blocks.MUD)) + .forceDirt() + .build() + ); } public static ResourceKey> resourceKey(String name) { diff --git a/src/main/java/com/altnoir/poopsky/worldgen/foliage/PSFoliagePlacerTypes.java b/src/main/java/com/altnoir/poopsky/worldgen/foliage/PSFoliagePlacerTypes.java new file mode 100644 index 0000000..5077b39 --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/worldgen/foliage/PSFoliagePlacerTypes.java @@ -0,0 +1,23 @@ +package com.altnoir.poopsky.worldgen.foliage; + +import com.altnoir.poopsky.PoopSky; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType; +import net.neoforged.bus.api.IEventBus; +import net.neoforged.neoforge.registries.DeferredHolder; +import net.neoforged.neoforge.registries.DeferredRegister; + +import static com.altnoir.poopsky.worldgen.foliage.PoopMegaFoliagePlacer.CODEC; + +public class PSFoliagePlacerTypes { + public static final DeferredRegister> FOLIAGE_PLACERS = + DeferredRegister.create(Registries.FOLIAGE_PLACER_TYPE, PoopSky.MOD_ID); + + public static final DeferredHolder, FoliagePlacerType> POOP_MEGA_FOLIAGE_PLACER = + FOLIAGE_PLACERS.register("poop_mega_foliage_placer", () -> + new FoliagePlacerType<>(CODEC)); + + public static void register(IEventBus eventBus) { + FOLIAGE_PLACERS.register(eventBus); + } +} diff --git a/src/main/java/com/altnoir/poopsky/worldgen/foliage/PoopMegaFoliagePlacer.java b/src/main/java/com/altnoir/poopsky/worldgen/foliage/PoopMegaFoliagePlacer.java new file mode 100644 index 0000000..c74cbdc --- /dev/null +++ b/src/main/java/com/altnoir/poopsky/worldgen/foliage/PoopMegaFoliagePlacer.java @@ -0,0 +1,67 @@ +package com.altnoir.poopsky.worldgen.foliage; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.util.RandomSource; +import net.minecraft.util.valueproviders.IntProvider; +import net.minecraft.util.valueproviders.UniformInt; +import net.minecraft.world.level.LevelSimulatedReader; +import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration; +import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer; +import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacerType; + +public class PoopMegaFoliagePlacer extends FoliagePlacer { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( + instance -> foliagePlacerParts(instance) + .and(UniformInt.codec(0, 24).fieldOf("crown_height").forGetter(p -> p.crownHeight)) + .apply(instance, PoopMegaFoliagePlacer::new) + ); + + private final IntProvider crownHeight; + + public PoopMegaFoliagePlacer(IntProvider radius, IntProvider offset, IntProvider crownHeight) { + super(radius, offset); + this.crownHeight = crownHeight; + } + + @Override + protected FoliagePlacerType type() { + return PSFoliagePlacerTypes.POOP_MEGA_FOLIAGE_PLACER.get(); + } + + @Override + protected void createFoliage(LevelSimulatedReader reader, FoliageSetter placer, RandomSource random, + TreeConfiguration config, int trunkHeight, FoliageAttachment attachment, + int foliageHeight, int radius, int offset) { + var center = attachment.pos(); + var halfHeight = foliageHeight / 2; + var prevRadius = 0; + + for (var y = center.getY() - foliageHeight + offset; y <= center.getY() + offset; ++y) { + var dy = center.getY() - y; + var spreadFactor = dy >= halfHeight ? foliageHeight - dy : dy; + var currRadius = radius + attachment.radiusOffset() + Mth.floor((float)spreadFactor / foliageHeight * 5.0F); + + if (dy > 0 && currRadius == prevRadius && (y & 1) == 0) { + currRadius++; + } + + placeLeavesRow(reader, placer, random, config, new BlockPos(center.getX(), y, center.getZ()), + currRadius, 0, attachment.doubleTrunk()); + prevRadius = currRadius; + } + } + + @Override + public int foliageHeight(RandomSource random, int trunkHeight, TreeConfiguration config) { + return crownHeight.sample(random); + } + + @Override + protected boolean shouldSkipLocation(RandomSource random, int dx, int y, int dz, int radius, boolean giantTrunk) { + return dx + dz >= 7 || dx * dx + dz * dz > radius * radius; + } +}