diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b626cf8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +# Local Fabric / PackTest server artifacts +/.fabric/ +/crash-reports/ +/eula.txt +/libraries/ +/logs/ +/mods/ +/server.jar +/server.properties +/server-output.log +/usercache.json +/versions/ +/world/ \ No newline at end of file diff --git a/data/timber/function/slow_chop/destroy_loop.mcfunction b/data/timber/function/slow_chop/destroy_loop.mcfunction index 4688cc0..187670f 100644 --- a/data/timber/function/slow_chop/destroy_loop.mcfunction +++ b/data/timber/function/slow_chop/destroy_loop.mcfunction @@ -7,10 +7,12 @@ $execute at @e[type=minecraft:marker,tag=timber_slow_chop] as @e[type=minecraft: # destroy n block $execute at @e[type=minecraft:marker,tag=timber_slow_chop] as @e[type=minecraft:armor_stand,tag=timber_tool,y=-64,distance=...1,sort=arbitrary,limit=1] at @e[type=minecraft:marker,tag=timber_destroy,sort=nearest,limit=$(blocks_per_chop)] run loot spawn ~ ~ ~ mine ~ ~ ~ mainhand -# destroy animation (minecraft:block_drops can be changed, because datapack wouldn't get to this point otherwise) -gamerule minecraft:block_drops false +# destroy animation. minecraft:block_drops stays on: blocks that hang on the tree (cocoa, torches, lanterns, ...) break with it and drop like in vanilla. +# The destroyed blocks drop like broken by hand too, those drops are removed again, their loot is the one from above. +tag @e[type=minecraft:item] add timber_keep $execute at @e[type=minecraft:marker,tag=timber_slow_chop] at @e[type=minecraft:marker,tag=timber_destroy,sort=nearest,limit=$(blocks_per_chop)] run setblock ~ ~ ~ minecraft:air destroy -gamerule minecraft:block_drops true +$execute at @e[type=minecraft:marker,tag=timber_slow_chop] at @e[type=minecraft:marker,tag=timber_destroy,sort=nearest,limit=$(blocks_per_chop)] align xyz run kill @e[type=minecraft:item,tag=!timber_keep,dx=0,dy=0,dz=0] +tag @e[type=minecraft:item] remove timber_keep # stop sound $execute at @e[type=minecraft:marker,tag=timber_slow_chop] if score stopsound timber matches 1.. at @e[type=minecraft:marker,tag=timber_destroy,sort=nearest,limit=$(blocks_per_chop)] as @a[distance=..20,tag=!global.ignore.gui] run function timber:utils/stopsound diff --git a/data/timber/function/validated.mcfunction b/data/timber/function/validated.mcfunction index ae671b5..9082f89 100644 --- a/data/timber/function/validated.mcfunction +++ b/data/timber/function/validated.mcfunction @@ -26,10 +26,14 @@ execute if score drop_loot timber matches 1.. if entity @s[nbt={Inventory:[{Slot execute unless score slow_chop timber matches 1.. unless score drop_loot timber matches 1.. at @e[type=minecraft:marker,tag=timber_destroy] run loot spawn ~ ~ ~ mine ~ ~ ~ mainhand execute unless score slow_chop timber matches 1.. if score drop_loot timber matches 1.. unless score inventory timber matches 36.. at @e[type=minecraft:marker,tag=timber_destroy] run loot give @s mine ~ ~ ~ mainhand execute unless score slow_chop timber matches 1.. if score drop_loot timber matches 1.. if score inventory timber matches 36.. at @e[type=minecraft:marker,tag=timber_destroy] run loot spawn ~ ~ ~ mine ~ ~ ~ mainhand - # destroy animation (minecraft:block_drops can be changed, because datapack wouldn't get to this point otherwise) - gamerule minecraft:block_drops false + # destroy animation. minecraft:block_drops stays on: blocks that hang on the tree (cocoa, torches, lanterns, ...) break with it and drop like in vanilla. + # The destroyed blocks drop like broken by hand too, those drops are removed again, their loot is the one from above. + execute unless score slow_chop timber matches 1.. run tag @e[type=minecraft:item] add timber_keep execute unless score slow_chop timber matches 1.. at @e[type=minecraft:marker,tag=timber_destroy] run setblock ~ ~ ~ minecraft:air destroy - gamerule minecraft:block_drops true + execute unless score slow_chop timber matches 1.. at @e[type=minecraft:marker,tag=timber_destroy] align xyz run kill @e[type=minecraft:item,tag=!timber_keep,dx=0,dy=0,dz=0] + # the new items that are left are the drops of the blocks that hung on the tree, with "Drop Loot into Inventory" they go to the player + execute unless score slow_chop timber matches 1.. if score drop_loot timber matches 1.. unless score inventory timber matches 36.. run tp @e[type=minecraft:item,tag=!timber_keep] @s + execute unless score slow_chop timber matches 1.. run tag @e[type=minecraft:item] remove timber_keep # remove destroy marker execute unless score slow_chop timber matches 1.. run kill @e[type=minecraft:marker,tag=timber_destroy] diff --git a/tests/101/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction b/tests/101/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction new file mode 100644 index 0000000..83ef7e3 --- /dev/null +++ b/tests/101/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction @@ -0,0 +1,2 @@ +#> Poplar and shelf mushroom are new in 26.3 (pack format 121), nothing to test in the older versions +return 0 diff --git a/tests/data/timber_test/test/chop_crimson_fungus_wall_torch_drops.mcfunction b/tests/data/timber_test/test/chop_crimson_fungus_wall_torch_drops.mcfunction new file mode 100644 index 0000000..3096438 --- /dev/null +++ b/tests/data/timber_test/test/chop_crimson_fungus_wall_torch_drops.mcfunction @@ -0,0 +1,30 @@ +#> A torch on a stem of the chopped crimson fungus drops (chop_fungi is on) +# @environment timber_test:chop_fungi_on +# @template timber_test:arena +# @timeout 400 +# @skyaccess true + +function timber_test:platform +# nether fungi only grow on nylium, without it place feature fails without a message +setblock ~20 ~-1 ~20 minecraft:crimson_nylium +function timber_test:tree {feature:"minecraft:crimson_fungus"} +assert block ~20 ~1 ~20 minecraft:crimson_stem +# torch on the stem (facing points away from the block it hangs on) +setblock ~21 ~1 ~20 minecraft:wall_torch[facing=east] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:wall_torch +function timber_test:player {name:"torch_stem_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"torch_stem_t"} + +# wait until the datapack is done with the fungus +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +assert block ~20 ~1 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +scoreboard objectives add timber_test dummy +execute store result score #torch_stem timber_test if entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:torch",count:1}}] +assert score #torch_stem timber_test matches 1 diff --git a/tests/data/timber_test/test/chop_jungle_cocoa_drops.mcfunction b/tests/data/timber_test/test/chop_jungle_cocoa_drops.mcfunction new file mode 100644 index 0000000..8e47671 --- /dev/null +++ b/tests/data/timber_test/test/chop_jungle_cocoa_drops.mcfunction @@ -0,0 +1,39 @@ +#> Cocoa on a log of the chopped tree drops its beans, cocoa on a log next to the tree stays (#42) +# @environment timber_test:group_2 +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +# a jungle tree without cocoa and vines of its own +function timber_test:tree {feature:"minecraft:jungle_tree_no_vine"} +assert block ~20 ~1 ~20 minecraft:jungle_log +# ripe cocoa on the trunk (facing points at the log it hangs on) +setblock ~21 ~1 ~20 minecraft:cocoa[age=2,facing=west] +# cocoa next to the trunk that hangs on another log, 2 blocks away from the trunk that log is no part of the tree +setblock ~20 ~1 ~18 minecraft:jungle_log +setblock ~20 ~1 ~19 minecraft:cocoa[age=2,facing=north] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:cocoa +assert block ~20 ~1 ~19 minecraft:cocoa +function timber_test:player {name:"cocoa_drop_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"cocoa_drop_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +# the cocoa on the trunk dropped its 3 beans, nothing else did +assert block ~20 ~1 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +scoreboard objectives add timber_test dummy +execute store result score #cocoa_drop timber_test if entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:cocoa_beans"}}] +assert score #cocoa_drop timber_test matches 1 +execute store result score #cocoa_drop timber_test run data get entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:cocoa_beans"}},limit=1] Item.count +assert score #cocoa_drop timber_test matches 3 +# the cocoa on the other log is untouched +assert block ~20 ~1 ~18 minecraft:jungle_log +assert block ~20 ~1 ~19 minecraft:cocoa[age=2,facing=north] diff --git a/tests/data/timber_test/test/chop_jungle_cocoa_drops_slowly.mcfunction b/tests/data/timber_test/test/chop_jungle_cocoa_drops_slowly.mcfunction new file mode 100644 index 0000000..c159caf --- /dev/null +++ b/tests/data/timber_test/test/chop_jungle_cocoa_drops_slowly.mcfunction @@ -0,0 +1,35 @@ +#> Slow chop: cocoa on a log of the chopped tree drops its beans, cocoa on a log next to the tree stays (#42) +# @environment timber_test:slow_chop_on +# @template timber_test:arena +# @timeout 600 +# @skyaccess true + +function timber_test:platform +# a jungle tree without cocoa and vines of its own +function timber_test:tree {feature:"minecraft:jungle_tree_no_vine"} +assert block ~20 ~1 ~20 minecraft:jungle_log +# ripe cocoa on the trunk (facing points at the log it hangs on) +setblock ~21 ~1 ~20 minecraft:cocoa[age=2,facing=west] +# cocoa next to the trunk that hangs on another log, 2 blocks away from the trunk that log is no part of the tree +setblock ~20 ~1 ~18 minecraft:jungle_log +setblock ~20 ~1 ~19 minecraft:cocoa[age=2,facing=north] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:cocoa +assert block ~20 ~1 ~19 minecraft:cocoa +function timber_test:player {name:"cocoa_slow_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"cocoa_slow_t"} + +# the cocoa on the trunk drops its 3 beans +# (checked while they fall: the slow chop goes on for a while, beans that roll to the dummy are picked up by then) +await entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:cocoa_beans",count:3}}] + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +assert block ~20 ~1 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +# the cocoa on the other log is untouched +assert block ~20 ~1 ~18 minecraft:jungle_log +assert block ~20 ~1 ~19 minecraft:cocoa[age=2,facing=north] diff --git a/tests/data/timber_test/test/chop_oak_drops_every_log_once.mcfunction b/tests/data/timber_test/test/chop_oak_drops_every_log_once.mcfunction new file mode 100644 index 0000000..4c40147 --- /dev/null +++ b/tests/data/timber_test/test/chop_oak_drops_every_log_once.mcfunction @@ -0,0 +1,26 @@ +#> Every log of the chopped tree drops once: the drops of the destroy animation are removed, only the loot is left +# @environment timber_test:group_5 +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +function timber_test:tree {feature:"minecraft:oak"} +assert block ~20 ~ ~20 #minecraft:logs + +await delay 1s +function timber_test:count_logs {test:"chop_oak_drops_every_log_once"} +function timber_test:player {name:"log_once_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"log_once_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +# as many logs on the ground as the tree had (the one the dummy mined is one of them, items can be stacks) +scoreboard players set #log_once timber_test 0 +execute as @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:oak_log"}}] store result score @s timber_test run data get entity @s Item.count +execute as @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:oak_log"}}] run scoreboard players operation #log_once timber_test += @s timber_test +assert score #log_once timber_test = #logs0_chop_oak_drops_every_log_once timber_test diff --git a/tests/data/timber_test/test/chop_oak_lanterns_drop.mcfunction b/tests/data/timber_test/test/chop_oak_lanterns_drop.mcfunction new file mode 100644 index 0000000..a313648 --- /dev/null +++ b/tests/data/timber_test/test/chop_oak_lanterns_drop.mcfunction @@ -0,0 +1,35 @@ +#> Lanterns on top of and under a log of the chopped tree drop +# @environment timber_test:group_5 +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +function timber_test:tree {feature:"minecraft:oak"} +assert block ~20 ~2 ~20 #minecraft:logs +# a log at the trunk as a branch, one lantern stands on it, one hangs under it +setblock ~21 ~2 ~20 minecraft:oak_log +setblock ~21 ~3 ~20 minecraft:lantern[hanging=false] +setblock ~21 ~1 ~20 minecraft:lantern[hanging=true] + +await delay 1s +assert block ~21 ~3 ~20 minecraft:lantern +assert block ~21 ~1 ~20 minecraft:lantern +function timber_test:player {name:"lantern_drop_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"lantern_drop_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +# the branch is gone, both lanterns dropped (two items, or one stack of two) +assert block ~21 ~2 ~20 minecraft:air +assert block ~21 ~3 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +scoreboard objectives add timber_test dummy +scoreboard players set #lantern_drop timber_test 0 +execute as @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:lantern"}}] store result score @s timber_test run data get entity @s Item.count +execute as @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:lantern"}}] run scoreboard players operation #lantern_drop timber_test += @s timber_test +assert score #lantern_drop timber_test matches 2 diff --git a/tests/data/timber_test/test/chop_oak_wall_torch_drops.mcfunction b/tests/data/timber_test/test/chop_oak_wall_torch_drops.mcfunction new file mode 100644 index 0000000..057381c --- /dev/null +++ b/tests/data/timber_test/test/chop_oak_wall_torch_drops.mcfunction @@ -0,0 +1,35 @@ +#> A torch on a log of the chopped tree drops, a torch on a block next to the tree stays +# @environment timber_test:group_3 +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +function timber_test:tree {feature:"minecraft:oak"} +assert block ~20 ~1 ~20 #minecraft:logs +# torch on the trunk (facing points away from the block it hangs on) +setblock ~21 ~1 ~20 minecraft:wall_torch[facing=east] +# torch next to the trunk that hangs on another block +setblock ~20 ~1 ~18 minecraft:stone +setblock ~20 ~1 ~19 minecraft:wall_torch[facing=south] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:wall_torch +assert block ~20 ~1 ~19 minecraft:wall_torch +function timber_test:player {name:"torch_drop_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"torch_drop_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +# the torch on the trunk dropped, nothing else did +assert block ~20 ~1 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +scoreboard objectives add timber_test dummy +execute store result score #torch_drop timber_test if entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:torch",count:1}}] +assert score #torch_drop timber_test matches 1 +# the torch on the stone is untouched +assert block ~20 ~1 ~19 minecraft:wall_torch[facing=south] diff --git a/tests/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction b/tests/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction new file mode 100644 index 0000000..78c6717 --- /dev/null +++ b/tests/data/timber_test/test/chop_poplar_shelf_mushroom_drops.mcfunction @@ -0,0 +1,33 @@ +#> A shelf mushroom on a log of the chopped Poplar drops, a shelf mushroom on a block next to the tree stays (#42) +#> Poplar and shelf mushroom are new in 26.3, the overlay 101 replaces this test with an empty one +# @environment timber_test:group_2 +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +function timber_test:tree {feature:"minecraft:yellow_poplar"} +assert block ~20 ~1 ~20 minecraft:poplar_log +# shelf mushroom on the trunk (facing points away from the block it hangs on) +setblock ~21 ~1 ~20 minecraft:shelf_mushroom[facing=east] +# shelf mushroom next to the trunk that hangs on another block +setblock ~20 ~1 ~18 minecraft:stone +setblock ~20 ~1 ~19 minecraft:shelf_mushroom[facing=south] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:shelf_mushroom +assert block ~20 ~1 ~19 minecraft:shelf_mushroom +function timber_test:player {name:"shelf_drop_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"shelf_drop_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +assert block ~20 ~1 ~20 minecraft:air +assert block ~21 ~1 ~20 minecraft:air +assert entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:shelf_mushroom"}}] +# the shelf mushroom on the stone is untouched +assert block ~20 ~1 ~19 minecraft:shelf_mushroom[facing=south] diff --git a/tests/data/timber_test/test/settings_drop_loot_on_gives_cocoa_to_the_player.mcfunction b/tests/data/timber_test/test/settings_drop_loot_on_gives_cocoa_to_the_player.mcfunction new file mode 100644 index 0000000..30b9da4 --- /dev/null +++ b/tests/data/timber_test/test/settings_drop_loot_on_gives_cocoa_to_the_player.mcfunction @@ -0,0 +1,29 @@ +#> With drop_loot on the beans of cocoa on the chopped tree go into the inventory of the player, not on the ground +# @environment timber_test:drop_loot_on +# @template timber_test:arena +# @timeout 200 +# @skyaccess true + +function timber_test:platform +# a jungle tree without cocoa and vines of its own +function timber_test:tree {feature:"minecraft:jungle_tree_no_vine"} +assert block ~20 ~1 ~20 minecraft:jungle_log +setblock ~21 ~1 ~20 minecraft:cocoa[age=2,facing=west] + +await delay 1s +assert block ~21 ~1 ~20 minecraft:cocoa +function timber_test:player {name:"loot_cocoa_t",axe:"minecraft:iron_axe"} +function timber_test:mine {name:"loot_cocoa_t"} + +# wait until the datapack is done with the tree +# (await doesn't work inside a called function, so this block is repeated in every test) +await not block ~20 ~ ~20 #minecraft:logs +await delay 5t +await not entity @e[type=minecraft:marker,dx=39,dy=39,dz=39] + +# the cocoa is gone, its beans were moved to the dummy, which picks them up half a second later +assert block ~21 ~1 ~20 minecraft:air +await not entity @e[type=minecraft:item,dx=39,dy=39,dz=39,nbt={Item:{id:"minecraft:cocoa_beans"}}] +scoreboard objectives add timber_test dummy +execute store result score #loot_cocoa timber_test run clear @e[type=minecraft:player,name=loot_cocoa_t,limit=1] minecraft:cocoa_beans 0 +assert score #loot_cocoa timber_test matches 3 diff --git a/tests/pack.mcmeta b/tests/pack.mcmeta index 26312cd..6e51c3b 100644 --- a/tests/pack.mcmeta +++ b/tests/pack.mcmeta @@ -4,5 +4,10 @@ "pack_format": 121.0, "min_format": 101.0, "max_format": 121.0 + }, + "overlays": { + "entries": [ + {"directory": "101", "min_format": 101, "max_format": 120} + ] } }