diff --git a/src/main/java/carpet/script/CarpetExpression.java b/src/main/java/carpet/script/CarpetExpression.java index 218233cf..a579512b 100644 --- a/src/main/java/carpet/script/CarpetExpression.java +++ b/src/main/java/carpet/script/CarpetExpression.java @@ -44,6 +44,7 @@ import net.minecraft.block.JigsawBlock; import net.minecraft.block.StructureBlock; import net.minecraft.block.entity.BlockEntity; import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.FallingBlockEntity; import net.minecraft.item.BlockItem; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -154,6 +155,7 @@ public class CarpetExpression private final Expression expr; Expression getExpr() {return expr;} private static long tickStart = 0L; + private static FallingBlockEntity DUMMY_ENTITY = new FallingBlockEntity(EntityType.FALLING_BLOCK, null); private static boolean stopAll = false; @@ -521,9 +523,45 @@ public class CarpetExpression *

Causes a block to tick at position.

*

random_tick(pos)

*

Causes a random tick at position.

- *

destroy(pos), destroy(pos, -1), destroy(pos, <N>)

+ *

destroy(pos), destroy(pos, -1), destroy(pos, <N>), destroy(pos, tool, nbt?)

*

Destroys the block like it was mined by a player. Add -1 for silk touch, and positive number for fortune level. - * This function, unlike harvest, will affect all kinds of blocks

+ * If tool is specified, and optionally its nbt, it will use that tool and will attempt to mine the block with this tool. + * If called without item context, this function, unlike harvest, will affect all kinds of blocks. If called with item in context, + * it will fail to break blocks that cannot be broken by a survival player.

+ *

Without item context it returns false if failed to destroy the block and true if block breaking was + * successful. In item context, true means that breaking item has no nbt to use, null indicating that + * the tool should be considered broken in process, and nbt type value, for a resulting NBT tag on a hypothetical tool. + * Its up to the programmer to use that nbt to apply it where it belong + *

+ *

Here is a sample code that can be used to mine blocks using items in player inventory, without using player context for mining. + * Obviously, in this case the use of harvest would be much more applicable:

+ *
+     * mine(x,y,z) ->
+     * (
+     *    p = player();
+     *    slot = p~'selected_slot';
+     *    item_tuple = inventory_get(p, slot);
+     *    if (!item_tuple, destroy(x,y,z,'air'); return()); // empty hand, just break with 'air'
+     *    l(item, count, tag) = item_tuple;
+     *    tag_back = destroy(x,y,z, item, tag);
+     *    if (tag_back == false, // failed to break the item
+     * 	     return(tag_back)
+     *    );
+     *    if (tag_back == true, // block broke, tool has no tag
+     * 	     return(tag_back)
+     *    );
+     *    if (tag_back == null, //item broke
+     * 	     delete(tag:'Damage');
+     * 	     inventory_set(p, slot, count-1, item, tag);
+     * 	     return(tag_back)
+     *    );
+     *    if (type(tag_back) == 'nbt', // item didn't break, here is the effective nbt
+     * 	     inventory_set(p, slot, count, item, tag_back);
+     * 	     return(tag_back)
+     *    );
+     *    print('How did we get here?');
+     * )
+     * 
*

harvest(player, pos)

*

Causes a block to be harvested by a specified player entity. Honors player item enchantments, as well as damages the * tool if applicable. If the entity is not a valid player, no block gets destroyed. If a player is not allowed to @@ -1243,25 +1281,40 @@ public class CarpetExpression BlockPos where = locator.block.getPos(); BlockEntity be = world.getBlockEntity(where); long how = 0; - if (lv.size() > locator.offset) - how = NumericValue.asNumber(lv.get(locator.offset).evalValue(cc)).getLong(); Item item = Items.DIAMOND_PICKAXE; boolean playerBreak = false; - if (lv.size() > locator.offset+1) + if (lv.size() > locator.offset) { - playerBreak = true; - String itemString = lv.get(locator.offset+1).evalValue(c).getString(); - item = Registry.ITEM.get(new Identifier(itemString)); - if (item == Items.AIR && !itemString.equals("air")) throw new InternalExpressionException("Incorrect item: "+itemString); + Value val = lv.get(locator.offset).evalValue(c); + if (val instanceof NumericValue) + { + how = ((NumericValue) val).getLong(); + } + else + { + playerBreak = true; + String itemString = val.getString(); + item = Registry.ITEM.get(new Identifier(itemString)); + if (item == Items.AIR && !itemString.equals("air")) + throw new InternalExpressionException("Incorrect item: " + itemString); + } } CompoundTag tag = null; - if (lv.size() > locator.offset+2) + if (lv.size() > locator.offset+1) { - Value tagValue = lv.get(locator.offset+2).evalValue(c); - if (tagValue instanceof NBTSerializableValue) + if (!playerBreak) throw new InternalExpressionException("tag is not necessary with 'destroy' with no item"); + Value tagValue = lv.get(locator.offset+1).evalValue(c); + if (tagValue instanceof NullValue) + tag = null; + else if (tagValue instanceof NBTSerializableValue) tag = ((NBTSerializableValue) tagValue).getCompoundTag(); else - tag = NBTSerializableValue.parseString(tagValue.getString()).getCompoundTag(); + { + NBTSerializableValue readTag = NBTSerializableValue.parseString(tagValue.getString()); + if (readTag == null) + throw new InternalExpressionException("Incorrect tag: "+tagValue.getString()); + tag = readTag.getCompoundTag(); + } } ItemStack tool = new ItemStack(item, 1); @@ -1277,7 +1330,7 @@ public class CarpetExpression if (playerBreak) { boolean isUsingEffectiveTool = state.getMaterial().canBreakByHand() || tool.isEffectiveOn(state); - //postMine durability + //postMine() durability from item classes float hardness = state.getHardness(world, where); int damageAmount = 0; if ((item instanceof MiningToolItem && hardness > 0.0) || item instanceof ShearsItem) @@ -1303,14 +1356,17 @@ public class CarpetExpression { if (how > 0) tool.addEnchantment(Enchantments.FORTUNE, (int) how); - Block.dropStacks(state, world, where, be, null, tool); + Block.dropStacks(state, world, where, be, DUMMY_ENTITY, tool); } } - if (!playerBreak) + if (!playerBreak) // no tool info - block brokwn return (c_, t_) -> Value.TRUE; if (toolBroke) return LazyValue.NULL; - Value ret = new NBTSerializableValue(tool.getTag()); + Tag outtag = tool.getTag(); + if (outtag == null) + return LazyValue.TRUE; + Value ret = new NBTSerializableValue(outtag); return (_c, _t) -> ret; });