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",