diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md
index de176790..59ad59c2 100644
--- a/docs/scarpet/Full.md
+++ b/docs/scarpet/Full.md
@@ -3429,10 +3429,10 @@ If called with `false` value, it will disable AI in the mob. `true` will enable
Sets if the entity obeys any collisions, including collisions with the terrain and basic physics. Not affecting
players, since they are controlled client side.
-### `modify(e, 'effect', name?, duration?, amplifier?, show_particles?, show_icon?)`
+### `modify(e, 'effect', name?, duration?, amplifier?, show_particles?, show_icon?, ambient?)`
-Applies status effect to the living entity. Takes several optional parameters, which default to `0`, `true`
-and `true`. If no duration is specified, or if it's null or 0, the effect is removed. If name is not specified,
+Applies status effect to the living entity. Takes several optional parameters, which default to `0`, `true`,
+`true` and `false`. If no duration is specified, or if it's null or 0, the effect is removed. If name is not specified,
it clears all effects.
### `modify(e, 'home', null), modify(e, 'home', block, distance?), modify(e, 'home', x, y, z, distance?)`
@@ -4432,6 +4432,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.
@@ -4514,6 +4520,18 @@ Example usages:
// not a problem in apps
+### `display_title(players, type, title?, fadeInTicks?, stayTicks?, fadeOutTicks),`
+
+Sends the player (or players if `players` is a list) a title of a specific type, with optionally some times.
+ * `players` is either an online player or a list of players. When sending a single player, it will throw if the player is invalid or offline.
+ * `type` is either `'title'`, `'subtitle'`, `actionbar` or `clear`.
+ Note: `subtitle` will only be displayed if there is a title being displayed (can be an empty one)
+ * `title` is what title to send to the player. It is required except for `clear` type. Can be a text formatted using `format()`
+ * `...Ticks` are the number of ticks the title will stay in that state.
+ If not specified, it will use current defaults (those defaults may have changed from a previous `/title times` execution).
+ Executing with those will set the times to the specified ones.
+ Note that `actionbar` type doesn't support changing times (vanilla bug, see [MC-106167](https://bugs.mojang.com/browse/MC-106167)).
+
### `logger(msg), logger(type, msg)`
Prints the message to system logs, and not to chat. By default prints an info, unless you specify otherwise in the `type` parameter.
@@ -4738,7 +4756,7 @@ Available options in the scarpet app space:
* `world_seed` - a numeric seed of the world
* `world_path` - full path to the world saves folder
* `world_folder` - name of the direct folder in the saves that holds world files
- * `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_change(rule, newValue)` event.
+ * `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event.
Relevant gameplay related properties
* `game_difficulty` - current difficulty of the game: `'peacefu'`, `'easy'`, `'normal'`, or `'hard'`
diff --git a/docs/scarpet/api/Auxiliary.md b/docs/scarpet/api/Auxiliary.md
index 3f2ddcd9..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.
@@ -245,6 +251,18 @@ Example usages:
// not a problem in apps
+### `display_title(players, type, title?, fadeInTicks?, stayTicks?, fadeOutTicks),`
+
+Sends the player (or players if `players` is a list) a title of a specific type, with optionally some times.
+ * `players` is either an online player or a list of players. When sending a single player, it will throw if the player is invalid or offline.
+ * `type` is either `'title'`, `'subtitle'`, `actionbar` or `clear`.
+ Note: `subtitle` will only be displayed if there is a title being displayed (can be an empty one)
+ * `title` is what title to send to the player. It is required except for `clear` type. Can be a text formatted using `format()`
+ * `...Ticks` are the number of ticks the title will stay in that state.
+ If not specified, it will use current defaults (those defaults may have changed from a previous `/title times` execution).
+ Executing with those will set the times to the specified ones.
+ Note that `actionbar` type doesn't support changing times (vanilla bug, see [MC-106167](https://bugs.mojang.com/browse/MC-106167)).
+
### `logger(msg), logger(type, msg)`
Prints the message to system logs, and not to chat. By default prints an info, unless you specify otherwise in the `type` parameter.
@@ -469,7 +487,7 @@ Available options in the scarpet app space:
* `world_seed` - a numeric seed of the world
* `world_path` - full path to the world saves folder
* `world_folder` - name of the direct folder in the saves that holds world files
- * `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_change(rule, newValue)` event.
+ * `world_carpet_rules` - returns all Carpet rules in a map form (`rule`->`value`). Note that the values are always returned as strings, so you can't do boolean comparisons directly. Includes rules from extensions with their namespace (`namespace:rule`->`value`). You can later listen to rule changes with the `on_carpet_rule_changes(rule, newValue)` event.
Relevant gameplay related properties
* `game_difficulty` - current difficulty of the game: `'peacefu'`, `'easy'`, `'normal'`, or `'hard'`
diff --git a/docs/scarpet/api/Entities.md b/docs/scarpet/api/Entities.md
index 794ecc6b..a60d426c 100644
--- a/docs/scarpet/api/Entities.md
+++ b/docs/scarpet/api/Entities.md
@@ -641,10 +641,10 @@ If called with `false` value, it will disable AI in the mob. `true` will enable
Sets if the entity obeys any collisions, including collisions with the terrain and basic physics. Not affecting
players, since they are controlled client side.
-### `modify(e, 'effect', name?, duration?, amplifier?, show_particles?, show_icon?)`
+### `modify(e, 'effect', name?, duration?, amplifier?, show_particles?, show_icon?, ambient?)`
-Applies status effect to the living entity. Takes several optional parameters, which default to `0`, `true`
-and `true`. If no duration is specified, or if it's null or 0, the effect is removed. If name is not specified,
+Applies status effect to the living entity. Takes several optional parameters, which default to `0`, `true`,
+`true` and `false`. If no duration is specified, or if it's null or 0, the effect is removed. If name is not specified,
it clears all effects.
### `modify(e, 'home', null), modify(e, 'home', block, distance?), modify(e, 'home', x, y, z, distance?)`
diff --git a/docs/scarpet/resources/editors/idea/2.txt b/docs/scarpet/resources/editors/idea/2.txt
index ae16592b..642a8bc5 100644
--- a/docs/scarpet/resources/editors/idea/2.txt
+++ b/docs/scarpet/resources/editors/idea/2.txt
@@ -19,11 +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
@@ -61,6 +64,7 @@ modify
nbt
neighbours
opacity
+parse_nbt
particle
particle_line
particle_rect
@@ -86,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
@@ -118,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 92da9036..65a7800d 100644
--- a/docs/scarpet/resources/editors/npp/scarpet.xml
+++ b/docs/scarpet/resources/editors/npp/scarpet.xml
@@ -58,6 +58,8 @@
structure_eligibility structures structure_references set_structure reset_chunk reload_chunk custom_dimension
add_chunk_ticket
+ display_title
+
scoreboard scoreboard_add scoreboard_remove scoreboard_display
team_add team_list team_remove team_leave team_property
@@ -78,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/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..5ef599e9
--- /dev/null
+++ b/src/main/java/carpet/mixins/StatePredicate_scarpetMixin.java
@@ -0,0 +1,57 @@
+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.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(targets = "net.minecraft.command.argument.BlockPredicateArgumentType$StatePredicate")
+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..f64062e0
--- /dev/null
+++ b/src/main/java/carpet/mixins/TagPredicate_scarpetMixin.java
@@ -0,0 +1,52 @@
+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.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(targets = "net.minecraft.command.argument.BlockPredicateArgumentType$TagPredicate")
+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 3a7f080b..a873f804 100644
--- a/src/main/java/carpet/script/api/Auxiliary.java
+++ b/src/main/java/carpet/script/api/Auxiliary.java
@@ -40,13 +40,17 @@ 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;
+import net.minecraft.network.packet.s2c.play.TitleS2CPacket;
+import net.minecraft.network.packet.s2c.play.TitleS2CPacket.Action;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandOutput;
import net.minecraft.server.command.ServerCommandSource;
+import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.sound.SoundCategory;
@@ -73,7 +77,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
import static java.lang.Math.max;
import static java.lang.Math.min;
@@ -400,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");
@@ -434,6 +450,7 @@ public class Auxiliary {
if (lv.size() == 2)
{
ServerPlayerEntity player = EntityValue.getPlayerByValue(s.getMinecraftServer(), res);
+ if (player == null) return LazyValue.NULL;
s = player.getCommandSource();
res = lv.get(1).evalValue(c);
}
@@ -455,6 +472,66 @@ public class Auxiliary {
Value finalRes = res;
return (_c, _t) -> finalRes; // pass through for variables
});
+ expression.addLazyFunction("display_title", -1, (c, t, lv) -> {
+ if (lv.size() < 2) throw new InternalExpressionException("'display_title' needs at least a target, type and message, and optionally times");
+ Value pVal = lv.get(0).evalValue(c);
+ if (!(pVal instanceof ListValue)) pVal = ListValue.of(pVal);
+ MinecraftServer server = ((CarpetContext)c).s.getMinecraftServer();
+ Stream targets = ((ListValue) pVal).getItems().stream().map(v ->
+ {
+ ServerPlayerEntity player = EntityValue.getPlayerByValue(server, v);
+ if (player == null) throw new InternalExpressionException("'display_title' requires a valid online player or a list of players as first argument. "+v.getString()+" is not a player.");
+ return player;
+ });
+ TitleS2CPacket.Action action;
+ switch (lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT))
+ {
+ case "title":
+ action = Action.TITLE;
+ break;
+ case "subtitle":
+ action = Action.SUBTITLE;
+ break;
+ case "actionbar":
+ action = Action.ACTIONBAR;
+ break;
+ case "clear":
+ action = Action.CLEAR;
+ break;
+ default:
+ throw new InternalExpressionException("'display_title' requires 'title', 'subtitle', 'actionbar' or 'clear' as second argument");
+ }
+ if (action != Action.CLEAR && lv.size() < 3)
+ throw new InternalExpressionException("Third argument of 'display_title' must be present except for 'clear' type");
+ Text title = null;
+ if (lv.size() > 2)
+ {
+ pVal = lv.get(2).evalValue(c);
+ if (pVal instanceof FormattedTextValue)
+ title = ((FormattedTextValue) pVal).getText();
+ else
+ title = Text.of(pVal.getString());
+ }
+ TitleS2CPacket timesPacket;
+ if (lv.size() > 3)
+ {
+ int in = NumericValue.asNumber(lv.get(3).evalValue(c),"fade in for display_title" ).getInt();
+ int stay = NumericValue.asNumber(lv.get(4).evalValue(c),"stay for display_title" ).getInt();
+ int out = NumericValue.asNumber(lv.get(5).evalValue(c),"fade out for display_title" ).getInt();
+ timesPacket = new TitleS2CPacket(Action.TIMES, null, in, stay, out);
+ }
+ else timesPacket = null;
+
+ TitleS2CPacket packet = new TitleS2CPacket(action, title);
+ AtomicInteger total = new AtomicInteger(0);
+ targets.forEach(p -> {
+ if (timesPacket != null) p.networkHandler.sendPacket(timesPacket);
+ p.networkHandler.sendPacket(packet);
+ total.getAndIncrement();
+ });
+ Value ret = NumericValue.of(total.get());
+ return (cc, tt) -> ret;
+ });
expression.addLazyFunction("format", -1, (c, t, lv) -> {
if (lv.size() == 0 ) throw new InternalExpressionException("'format' requires at least one component");
diff --git a/src/main/java/carpet/script/api/Entities.java b/src/main/java/carpet/script/api/Entities.java
index a836dec3..361e0e9f 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 258c6b59..75b0c711 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 2327d93f..97234e4d 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/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java
index 0fedc0bc..ce1248ab 100644
--- a/src/main/java/carpet/script/value/EntityValue.java
+++ b/src/main/java/carpet/script/value/EntityValue.java
@@ -1271,7 +1271,10 @@ public class EntityValue extends Value
boolean showIcon = true;
if (lv.size() > 4)
showIcon = lv.get(4).getBoolean();
- le.addStatusEffect(new StatusEffectInstance(effect, duration, amplifier, showParticles, showIcon));
+ boolean ambient = false;
+ if (lv.size() > 5)
+ showIcon = lv.get(5).getBoolean();
+ le.addStatusEffect(new StatusEffectInstance(effect, duration, amplifier, ambient, showParticles, showIcon));
return;
}
}
@@ -1284,7 +1287,7 @@ public class EntityValue extends Value
le.removeStatusEffect(effect);
return;
}
- throw new InternalExpressionException("'effect' needs either no arguments (clear) or effect name, duration, and optional amplifier, show particles and show icon");
+ throw new InternalExpressionException("'effect' needs either no arguments (clear) or effect name, duration, and optional amplifier, show particles, show icon and ambient");
});
put("gamemode", (e,v)->{
diff --git a/src/main/java/carpet/script/value/NBTSerializableValue.java b/src/main/java/carpet/script/value/NBTSerializableValue.java
index 9471b7f3..f8bc58e3 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 a47887ba..adb26099 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.MapColor;
+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.mixins.json b/src/main/resources/carpet.mixins.json
index efb7510a..8bf78b46 100644
--- a/src/main/resources/carpet.mixins.json
+++ b/src/main/resources/carpet.mixins.json
@@ -176,6 +176,8 @@
"RecipeManager_scarpetMixin",
"Ingredient_scarpetMixin",
"BlockStateArgument_scarpetMixin",
+ "StatePredicate_scarpetMixin",
+ "TagPredicate_scarpetMixin",
"HorseBaseEntity_scarpetMixin",
"PillagerEntity_scarpetMixin",