diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md index 8f52ecee..e5e9209b 100644 --- a/docs/scarpet/api/Auxiliary.md +++ b/docs/scarpet/api/Auxiliary.md @@ -163,6 +163,12 @@ Consult section about container operations in `Expression` to learn about possib Excapes all the special characters in the string or nbt tag and returns a string that can be stored in nbt directly as a string value. +### `tag_matches(daddy_tag, baby_tag, match_lists?)` + +Utility returning `true` if `baby_tag` is fully contained in `daddy_tag`. Anything matches `null` baby tag, and +Nothing is contained in a `null` daddy tag. If `match_lists` is specified and `false`, content of nested lists is ignored. +Default behaviour is to match them. + ### `parse_nbt(tag)` Converts NBT tag to a scarpet value, which you can navigate through much better. diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt index 05473aff..642a8bc5 100644 --- a/docs/scarpet/resources/editors/idea/2.txt +++ b/docs/scarpet/resources/editors/idea/2.txt @@ -19,12 +19,14 @@ create_marker current_dimension custom_dimension day_time +delete_file destroy diamond display_title draw_shape drop_item emitted_light +encode_nbt entity_area entity_event entity_id @@ -62,6 +64,7 @@ modify nbt neighbours opacity +parse_nbt particle particle_line particle_rect @@ -87,11 +90,13 @@ scoreboard scoreboard_add scoreboard_remove scoreboard_display +tag_matches team_add team_list team_remove team_leave team_property +read_file see_sky set set_biome @@ -119,4 +124,5 @@ update view_distance volume without_updates -world_time \ No newline at end of file +world_time +write_file \ No newline at end of file diff --git a/docs/scarpet/resources/editors/npp/scarpet.xml b/docs/scarpet/resources/editors/npp/scarpet.xml index f4cd1ddd..65a7800d 100644 --- a/docs/scarpet/resources/editors/npp/scarpet.xml +++ b/docs/scarpet/resources/editors/npp/scarpet.xml @@ -80,7 +80,8 @@ plop harvest destroy schedule nbt draw_shape create_marker remove_all_markers - load_app_data store_app_data escape_nbt statistic + load_app_data store_app_data read_file write_file delete_file + escape_nbt parse_nbt encode_nbt tag_matches statistic euler pi null true false x y z p diff --git a/gradle.properties b/gradle.properties index 8894d5cb..8caaf1a1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,7 +6,7 @@ org.gradle.jvmargs=-Xmx1G # or better: https://modmuss50.me/fabric.html minecraft_version=1.16.4 yarn_mappings=1.16.4+build.7 - loader_version=0.10.7 + loader_version=0.10.8 # Mod Properties mod_version = 1.4.19+v201125 diff --git a/src/main/java/carpet/fakes/BlockPredicateInterface.java b/src/main/java/carpet/fakes/BlockPredicateInterface.java new file mode 100644 index 00000000..cd1e4349 --- /dev/null +++ b/src/main/java/carpet/fakes/BlockPredicateInterface.java @@ -0,0 +1,17 @@ +package carpet.fakes; + +import carpet.script.value.Value; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.tag.Tag; + +import java.util.Map; + +public interface BlockPredicateInterface +{ + BlockState getCMBlockState(); + Tag getCMBlockTag(); + Map getCMProperties(); + CompoundTag getCMDataTag(); +} diff --git a/src/main/java/carpet/mixins/StatePredicate_scarpetMixin.java b/src/main/java/carpet/mixins/StatePredicate_scarpetMixin.java new file mode 100644 index 00000000..054e6e67 --- /dev/null +++ b/src/main/java/carpet/mixins/StatePredicate_scarpetMixin.java @@ -0,0 +1,58 @@ +package carpet.mixins; + +import carpet.fakes.BlockPredicateInterface; +import carpet.script.value.StringValue; +import carpet.script.value.Value; +import carpet.script.value.ValueConversions; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.command.argument.BlockPredicateArgumentType; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.state.property.Property; +import net.minecraft.tag.Tag; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Mixin(BlockPredicateArgumentType.StatePredicate.class) +public class StatePredicate_scarpetMixin implements BlockPredicateInterface +{ + + @Shadow @Final private BlockState state; + + @Shadow @Final /*@Nullable*/ private CompoundTag nbt; + + @Shadow @Final private Set> properties; + + @Override + public BlockState getCMBlockState() + { + return state; + } + + @Override + public Tag getCMBlockTag() + { + return null; + } + + @Override + public Map getCMProperties() + { + return properties.stream().collect(Collectors.toMap( + p -> StringValue.of(p.getName()), + p -> ValueConversions.fromProperty(state, p), + (a, b) -> b + )); + } + + @Override + public CompoundTag getCMDataTag() + { + return nbt; + } +} diff --git a/src/main/java/carpet/mixins/TagPredicate_scarpetMixin.java b/src/main/java/carpet/mixins/TagPredicate_scarpetMixin.java new file mode 100644 index 00000000..0a45f4d4 --- /dev/null +++ b/src/main/java/carpet/mixins/TagPredicate_scarpetMixin.java @@ -0,0 +1,53 @@ +package carpet.mixins; + +import carpet.fakes.BlockPredicateInterface; +import carpet.script.value.StringValue; +import carpet.script.value.Value; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.command.argument.BlockPredicateArgumentType; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.tag.Tag; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Map; +import java.util.stream.Collectors; + +@Mixin(BlockPredicateArgumentType.TagPredicate.class) +public class TagPredicate_scarpetMixin implements BlockPredicateInterface +{ + @Shadow @Final private Tag tag; + + @Shadow @Final private Map properties; + + @Shadow @Final /*@Nullable*/ private CompoundTag nbt; + + @Override + public BlockState getCMBlockState() + { + return null; + } + + @Override + public Tag getCMBlockTag() + { + return tag; + } + + @Override + public Map getCMProperties() + { + return properties.entrySet().stream().collect(Collectors.toMap( + e -> new StringValue(e.getKey()), + e -> new StringValue(e.getValue()) + )); + } + + @Override + public CompoundTag getCMDataTag() + { + return nbt; + } +} diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index d1e97972..a835fc5c 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -40,6 +40,7 @@ import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.decoration.ArmorStandEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtHelper; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.network.packet.s2c.play.PlaySoundIdS2CPacket; @@ -405,13 +406,23 @@ public class Auxiliary { Value parsed = ((NBTSerializableValue) v).toValue(); return (cc, tt) -> parsed; } - NBTSerializableValue ret = NBTSerializableValue.parseString(v.getString()); + NBTSerializableValue ret = NBTSerializableValue.parseString(v.getString(), false); if (ret == null) return LazyValue.NULL; Value parsed = ret.toValue(); return (cc, tt) -> parsed; }); + expression.addFunction("tag_matches", (lv) -> { + int numParam = lv.size(); + if (numParam != 2 && numParam != 3) throw new InternalExpressionException("'tag_matches' requires 2 or 3 arguments"); + if (lv.get(1).isNull()) return Value.TRUE; + if (lv.get(0).isNull()) return Value.FALSE; + Tag source = ((NBTSerializableValue)(NBTSerializableValue.fromValue(lv.get(0)))).getTag(); + Tag match = ((NBTSerializableValue)(NBTSerializableValue.fromValue(lv.get(1)))).getTag(); + return new NumericValue(NbtHelper.matches(match, source, numParam == 2 || lv.get(2).getBoolean())); + }); + expression.addLazyFunction("encode_nbt", -1, (c, t, lv) -> { int argSize = lv.size(); if (argSize==0 || argSize > 2) throw new InternalExpressionException("'encode_nbt' requires 1 or 2 parameters"); diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java index 58894bd5..7fac7ef1 100644 --- a/src/main/java/carpet/script/api/Entities.java +++ b/src/main/java/carpet/script/api/Entities.java @@ -137,7 +137,7 @@ public class Entities { { Value nbt = lv.get(position.offset).evalValue(c); NBTSerializableValue v = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt - : NBTSerializableValue.parseString(nbt.getString()); + : NBTSerializableValue.parseString(nbt.getString(), true); hasTag = true; tag = v.getCompoundTag(); diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index 5beb2a25..fa7a6361 100644 --- a/src/main/java/carpet/script/api/WorldAccess.java +++ b/src/main/java/carpet/script/api/WorldAccess.java @@ -808,9 +808,7 @@ public class WorldAccess { tag = ((NBTSerializableValue) tagValue).getCompoundTag(); else { - NBTSerializableValue readTag = NBTSerializableValue.parseString(tagValue.getString()); - if (readTag == null) - throw new InternalExpressionException("Incorrect tag: "+tagValue.getString()); + NBTSerializableValue readTag = NBTSerializableValue.parseString(tagValue.getString(), true); tag = readTag.getCompoundTag(); } } diff --git a/src/main/java/carpet/script/command/CommandArgument.java b/src/main/java/carpet/script/command/CommandArgument.java index c0e5ebef..1ddede7f 100644 --- a/src/main/java/carpet/script/command/CommandArgument.java +++ b/src/main/java/carpet/script/command/CommandArgument.java @@ -36,6 +36,7 @@ import net.minecraft.advancement.Advancement; import net.minecraft.command.CommandSource; import net.minecraft.command.argument.AngleArgumentType; import net.minecraft.command.argument.BlockPosArgumentType; +import net.minecraft.command.argument.BlockPredicateArgumentType; import net.minecraft.command.argument.BlockStateArgument; import net.minecraft.command.argument.BlockStateArgumentType; import net.minecraft.command.argument.ColorArgumentType; @@ -126,6 +127,9 @@ public abstract class CommandArgument }, false ), + new VanillaUnconfigurableArgument( "blockpredicate", BlockPredicateArgumentType::blockPredicate, + (c, p) -> ValueConversions.ofBlockPredicate(c.getSource().getMinecraftServer().getTagManager(), BlockPredicateArgumentType.getBlockPredicate(c, p)), false + ), // block_predicate todo - not sure about the returned format. Needs to match block tags used in the API (future) new VanillaUnconfigurableArgument("teamcolor", ColorArgumentType::color, (c, p) -> { diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java index 81560643..938acd20 100644 --- a/src/main/java/carpet/script/value/NBTSerializableValue.java +++ b/src/main/java/carpet/script/value/NBTSerializableValue.java @@ -104,7 +104,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa return id.toString(); } - public static NBTSerializableValue parseString(String nbtString) + public static NBTSerializableValue parseString(String nbtString, boolean fail) { Tag tag; try @@ -113,7 +113,8 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa } catch (CommandSyntaxException e) { - throw new InternalExpressionException("Incorrect NBT tag: nbtString"); + if (fail) throw new InternalExpressionException("Incorrect NBT tag: "+ nbtString); + return null; } NBTSerializableValue value = new NBTSerializableValue(tag); value.nbtString = null; @@ -331,7 +332,7 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa return v; if (v instanceof NullValue) return Value.NULL; - return NBTSerializableValue.parseString(v.getString()); + return NBTSerializableValue.parseString(v.getString(), true); } diff --git a/src/main/java/carpet/script/value/NumericValue.java b/src/main/java/carpet/script/value/NumericValue.java index b4e47501..caec9776 100644 --- a/src/main/java/carpet/script/value/NumericValue.java +++ b/src/main/java/carpet/script/value/NumericValue.java @@ -227,7 +227,7 @@ public class NumericValue extends Value } public NumericValue(boolean boolval) { - this(boolval?1.0D:0.0D); + this(boolval?1L:0L); } @Override diff --git a/src/main/java/carpet/script/value/ValueConversions.java b/src/main/java/carpet/script/value/ValueConversions.java index 1108b1e2..b3344f40 100644 --- a/src/main/java/carpet/script/value/ValueConversions.java +++ b/src/main/java/carpet/script/value/ValueConversions.java @@ -1,9 +1,11 @@ package carpet.script.value; +import carpet.fakes.BlockPredicateInterface; import carpet.script.exception.InternalExpressionException; import carpet.utils.BlockInfo; import net.minecraft.block.BlockState; import net.minecraft.block.MaterialColor; +import net.minecraft.block.pattern.CachedBlockPosition; import net.minecraft.entity.Entity; import net.minecraft.entity.ai.brain.LookTarget; import net.minecraft.entity.ai.brain.WalkTarget; @@ -21,6 +23,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.state.property.Property; import net.minecraft.structure.StructurePiece; import net.minecraft.structure.StructureStart; +import net.minecraft.tag.TagManager; import net.minecraft.util.Identifier; import net.minecraft.util.StringIdentifiable; @@ -40,6 +43,7 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.function.Predicate; import java.util.stream.Collectors; public class ValueConversions @@ -379,4 +383,15 @@ public class ValueConversions if (ret == null) return ListValue.of(Value.NULL, NumericValue.of(itemSlot)); return ret; } + + public static Value ofBlockPredicate(TagManager tagManager, Predicate blockPredicate) + { + BlockPredicateInterface predicateData = (BlockPredicateInterface) blockPredicate; + return ListValue.of( + predicateData.getCMBlockState()==null?Value.NULL:of(Registry.BLOCK.getId(predicateData.getCMBlockState().getBlock())), + predicateData.getCMBlockTag()==null?Value.NULL:of(tagManager.getBlocks().getTagId(predicateData.getCMBlockTag())), + MapValue.wrap(predicateData.getCMProperties()), + predicateData.getCMDataTag() == null?Value.NULL:new NBTSerializableValue(predicateData.getCMDataTag()) + ); + } } diff --git a/src/main/resources/carpet.accesswidener b/src/main/resources/carpet.accesswidener index e9dad565..ede3ac69 100644 --- a/src/main/resources/carpet.accesswidener +++ b/src/main/resources/carpet.accesswidener @@ -2,4 +2,6 @@ accessWidener v1 named accessible class net/minecraft/server/world/ThreadedAnvilChunkStorage$TicketManager accessible class net/minecraft/server/world/ServerLightingProvider$Stage -accessible class net/minecraft/recipe/Ingredient$Entry \ No newline at end of file +accessible class net/minecraft/recipe/Ingredient$Entry +accessible class net/minecraft/command/argument/BlockPredicateArgumentType$StatePredicate +accessible class net/minecraft/command/argument/BlockPredicateArgumentType$TagPredicate \ No newline at end of file diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 9806f587..8a90de0a 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -174,6 +174,8 @@ "RecipeManager_scarpetMixin", "Ingredient_scarpetMixin", "BlockStateArgument_scarpetMixin", + "StatePredicate_scarpetMixin", + "TagPredicate_scarpetMixin", "HorseBaseEntity_scarpetMixin", "PillagerEntity_scarpetMixin",