From 461c03ac09a5aaed06995651df5d16fdbe0557ef Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 2 Jul 2021 03:47:39 +0000 Subject: [PATCH 1/2] Merge docs for 'Carpet Mod 1.4.42 for Minecraft 1.17.1 and 1.16.5' --- docs/scarpet/Full.md | 47 ++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/docs/scarpet/Full.md b/docs/scarpet/Full.md index b1ea600a..64aec780 100644 --- a/docs/scarpet/Full.md +++ b/docs/scarpet/Full.md @@ -1464,6 +1464,10 @@ but if symbols are used directly in the module body rather than functions, it ma Returns full list of available symbols that could be imported from this module, which can be used to debug import issues, and list contents of libraries. +You can load and import functions from dependencies in a remote app store's source specified in your config's `libraries` block, but make sure +to place your config _before_ the import in order to allow the remote dependency to be downloaded (currently, app resources are only downloaded +when using the `/carpet download` command). + ### `call(function, ? args ...)` calls a user defined function with specified arguments. It is equivalent to calling `function(args...)` directly @@ -2019,30 +2023,46 @@ in a list and contain of map-like resources descriptors, looking like 'resources' -> [ { 'source' -> 'https://raw.githubusercontent.com/gnembon/fabric-carpet/master/src/main/resources/assets/carpet/icon.png', - 'type' -> 'url', 'target' -> 'foo/photos.zip/foo/cm.png', }, { - 'source' -> 'survival/README.md', - 'type' -> 'store', + 'source' -> '/survival/README.md', 'target' -> 'survival_readme.md', 'shared' -> true, }, { - 'source' -> 'carpets.sc', - 'type' -> 'app', - 'target' -> 'apps/flying_carpets.sc', - 'shared' -> true, + 'source' -> 'circle.sc', // Relative path + 'target' -> 'apps/circle.sc', // This won't install the app, use 'libraries' for that }, ] ``` - `source` and `type` indicate resource location: either an arbitrary url (type `'url'`), - absolute location of a file in the app store (type `'store'`), -or a relative location in the same folder as the app in question (type `'app'`). -`'target'` points to the path in app data, or shared app data folder + `source` indicates resource location: either an arbitrary url (starting with `http://` or `https://`), + absolute location of a file in the app store (starting with a slash `/`), +or a relative location in the same folder as the app in question (the relative location directly). +`'target'` points to the path in app data, or shared app data folder. If not specified it will place the app into the main data folder with the name it has. if `'shared'` is specified and `true`. When re-downloading the app, all resources will be re-downloaded as well. -Currently, app resources -are only downloaded when using `/carpet download` command. +Currently, app resources are only downloaded when using `/carpet download` command. +* `libraries` - list of libraries or apps to be downloaded when installing the app from the app store. It needs to be a list of map-like resource +descriptors, like the above `resources` field. + ``` + 'libraries' -> [ + { + 'source' -> '/tutorial/carpets.sc' + }, + { + 'source' -> '/fundamentals/heap.sc', + 'target' -> 'heap-lib.sc' + } + ] + ``` + `source` indicates resource location and must point to a scarpet app or library. It can be either an arbitrary url (starting with `http://` + or `https://`), absolute location of a file in the app store (starting with a slash `/`), or a relative location in the same folder as the app + in question (the relative location directly). + `target` is an optional field indicating the new name of the app. If not specified it will place the app into the main data folder with the name it has. +If the app has relative resources dependencies, Carpet will use the app's path for relatives if the app was loaded from the same app store, or none if the +app was loaded from an external url. +If you need to `import()` from dependencies indicated in this block, make sure to have the `__config()` map before any import that references your +remote dependencies, in order to allow them to be downloaded and initialized before the import is executed. * `'arguments'` - defines custom argument types for legacy commands with `'legacy_command_type_support'` as well as for the custom commands defined with `'commands'`, see below. * `'commands'` - defines custom commands for the app to be executed with `/` command, see below. @@ -2223,6 +2243,7 @@ Here is a list of built-in types, with their return value formats, as well as a * `'dimension'`: string representing a valid dimension in the world. * `'anchor'`: string of `feet` or `eyes`. * `'entitytype'`: string representing a type of entity + * `'entities'`: entity selector, returns a list of entities directly. Can be configured with `'single'` to only accept a single entity (will return the entity instead of a singleton) and with `'players'` to only accept players. * `'floatrange'`: pair of two numbers where one is smaller than the other * `'players'`: returning a list of valid player name string, logged in or not. If configured with `'single'` returns only one player or `null`. * `'intrange'`: same as `'floatrange'`, but requiring integers. From d07fe18bb593ecf4b7f5b2f5b7b430398ce46417 Mon Sep 17 00:00:00 2001 From: gnembon Date: Mon, 5 Jul 2021 16:52:08 -0300 Subject: [PATCH 2/2] handle invalid identifiers, fixes #980 --- .../java/carpet/script/api/Auxiliary.java | 17 +++++---------- .../java/carpet/script/api/Inventories.java | 18 ++++++---------- .../java/carpet/script/api/Scoreboards.java | 10 ++------- .../java/carpet/script/api/WorldAccess.java | 21 ++++++++++--------- .../carpet/script/utils/InputValidator.java | 15 +++++++++++++ .../java/carpet/script/value/EntityValue.java | 15 ++++++------- 6 files changed, 47 insertions(+), 49 deletions(-) diff --git a/src/main/java/carpet/script/api/Auxiliary.java b/src/main/java/carpet/script/api/Auxiliary.java index f59b4584..e372b03f 100644 --- a/src/main/java/carpet/script/api/Auxiliary.java +++ b/src/main/java/carpet/script/api/Auxiliary.java @@ -154,7 +154,7 @@ public class Auxiliary { return ListValue.wrap(Registry.SOUND_EVENT.getIds().stream().map(ValueConversions::of)); } String rawString = lv.get(0).getString(); - Identifier soundName = new Identifier(rawString); + Identifier soundName = InputValidator.identifierOf(rawString); Vector3Argument locator = Vector3Argument.findIn(lv, 1); if (Registry.SOUND_EVENT.get(soundName) == null) throw new ThrowStatement(rawString, Throwables.UNKNOWN_SOUND); @@ -950,15 +950,8 @@ public class Auxiliary { if (player == null) return Value.NULL; Identifier category; Identifier statName; - try - { - category = new Identifier(lv.get(1).getString()); - statName = new Identifier(lv.get(2).getString()); - } - catch (InvalidIdentifierException e) - { - return Value.NULL; - } + category = InputValidator.identifierOf(lv.get(1).getString()); + statName = InputValidator.identifierOf(lv.get(2).getString()); StatType type = Registry.STAT_TYPE.get(category); if (type == null) return Value.NULL; Stat stat = getStat(type, statName); @@ -1011,12 +1004,12 @@ public class Auxiliary { if (lv.size() == 0) return ListValue.wrap(storage.getIds().map(i -> new StringValue(nameFromRegistryId(i))).collect(Collectors.toList())); String key = lv.get(0).getString(); - CompoundTag old_nbt = storage.get(new Identifier(key)); + CompoundTag old_nbt = storage.get(InputValidator.identifierOf(key)); if (lv.size() == 2) { Value nbt = lv.get(1); NBTSerializableValue new_nbt = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt : NBTSerializableValue.parseString(nbt.getString(), true); - storage.set(new Identifier(key), new_nbt.getCompoundTag()); + storage.set(InputValidator.identifierOf(key), new_nbt.getCompoundTag()); } return NBTSerializableValue.of(old_nbt); }); diff --git a/src/main/java/carpet/script/api/Inventories.java b/src/main/java/carpet/script/api/Inventories.java index 389bd7a6..f062d484 100644 --- a/src/main/java/carpet/script/api/Inventories.java +++ b/src/main/java/carpet/script/api/Inventories.java @@ -7,6 +7,7 @@ import carpet.script.Expression; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ThrowStatement; import carpet.script.exception.Throwables; +import carpet.script.utils.InputValidator; import carpet.script.value.BooleanValue; import carpet.script.value.ListValue; import carpet.script.value.NBTSerializableValue; @@ -66,7 +67,7 @@ public class Inventories { CarpetContext cc = (CarpetContext)c; TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); String tag = lv.get(0).getString(); - net.minecraft.tag.Tag itemTag = tagManager.getItems().getTag(new Identifier(tag)); + net.minecraft.tag.Tag itemTag = tagManager.getItems().getTag(InputValidator.identifierOf(tag)); if (itemTag == null) return Value.NULL; return ListValue.wrap(itemTag.values().stream().map(b -> ValueConversions.of(Registry.ITEM.getId(b))).collect(Collectors.toList())); }); @@ -81,7 +82,7 @@ public class Inventories { if (lv.size() == 1) return ListValue.wrap(tagManager.getItems().getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList())); String tag = lv.get(1).getString(); - net.minecraft.tag.Tag itemTag = tagManager.getItems().getTag(new Identifier(tag)); + net.minecraft.tag.Tag itemTag = tagManager.getItems().getTag(InputValidator.identifierOf(tag)); if (itemTag == null) return Value.NULL; return BooleanValue.of(item.isIn(itemTag)); }); @@ -95,17 +96,10 @@ public class Inventories { if (lv.size() > 1) { String recipeType = lv.get(1).getString(); - try - { - type = Registry.RECIPE_TYPE.get(new Identifier(recipeType)); - } - catch (InvalidIdentifierException ignored) - { - throw new InternalExpressionException("Unknown crafting category: " + recipeType); - } + type = Registry.RECIPE_TYPE.get(InputValidator.identifierOf(recipeType)); } List> recipes; - recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName)); + recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, InputValidator.identifierOf(recipeName)); if (recipes.isEmpty()) return Value.NULL; List recipesOutput = new ArrayList<>(); @@ -175,7 +169,7 @@ public class Inventories { { String itemStr = v.getString(); Item item; - Identifier id = new Identifier(itemStr); + Identifier id = InputValidator.identifierOf(itemStr); item = Registry.ITEM.getOrEmpty(id).orElseThrow(() -> new ThrowStatement(itemStr, Throwables.UNKNOWN_ITEM)); if (!item.hasRecipeRemainder()) return Value.NULL; return new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder()))); diff --git a/src/main/java/carpet/script/api/Scoreboards.java b/src/main/java/carpet/script/api/Scoreboards.java index ec74ddce..06277159 100644 --- a/src/main/java/carpet/script/api/Scoreboards.java +++ b/src/main/java/carpet/script/api/Scoreboards.java @@ -9,6 +9,7 @@ import carpet.script.LazyValue; import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ThrowStatement; import carpet.script.exception.Throwables; +import carpet.script.utils.InputValidator; import carpet.script.value.BooleanValue; import carpet.script.value.EntityValue; import carpet.script.value.ListValue; @@ -407,14 +408,7 @@ public class Scoreboards { String id = lv.get(0).getString(); Identifier identifier; - try - { - identifier = new Identifier(id); - } - catch (InvalidIdentifierException invalidIdentifierException) - { - return Value.NULL; - } + identifier = InputValidator.identifierOf(id); if(lv.size() == 1) { diff --git a/src/main/java/carpet/script/api/WorldAccess.java b/src/main/java/carpet/script/api/WorldAccess.java index 1f636619..ff74c30d 100644 --- a/src/main/java/carpet/script/api/WorldAccess.java +++ b/src/main/java/carpet/script/api/WorldAccess.java @@ -22,6 +22,7 @@ import carpet.script.exception.InternalExpressionException; import carpet.script.exception.ThrowStatement; import carpet.script.exception.Throwables; import carpet.script.utils.BiomeInfo; +import carpet.script.utils.InputValidator; import carpet.script.utils.WorldTools; import carpet.script.value.BlockValue; import carpet.script.value.BooleanValue; @@ -322,7 +323,7 @@ public class WorldAccess { String poiType = lv.get(locator.offset+1).getString().toLowerCase(Locale.ROOT); if (!"any".equals(poiType)) { - PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiType)) + PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(InputValidator.identifierOf(poiType)) .orElseThrow(() -> new ThrowStatement(poiType, Throwables.UNKNOWN_POI)); condition = (tt) -> tt == type; } @@ -372,7 +373,7 @@ public class WorldAccess { return Value.TRUE; } String poiTypeString = poi.getString().toLowerCase(Locale.ROOT); - PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(new Identifier(poiTypeString)) + PointOfInterestType type = Registry.POINT_OF_INTEREST_TYPE.getOrEmpty(InputValidator.identifierOf(poiTypeString)) .orElseThrow(() -> new ThrowStatement(poiTypeString, Throwables.UNKNOWN_POI)); int occupancy = 0; if (locator.offset + 1 < lv.size()) @@ -827,7 +828,7 @@ public class WorldAccess { { playerBreak = true; String itemString = val.getString(); - item = Registry.ITEM.getOrEmpty(new Identifier(itemString)) + item = Registry.ITEM.getOrEmpty(InputValidator.identifierOf(itemString)) .orElseThrow(() -> new ThrowStatement(itemString, Throwables.UNKNOWN_ITEM)); } } @@ -1136,7 +1137,7 @@ public class WorldAccess { CarpetContext cc = (CarpetContext)c; TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); String tag = lv.get(0).getString(); - net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(new Identifier(tag)); + net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(InputValidator.identifierOf(tag)); if (blockTag == null) return Value.NULL; return ListValue.wrap(blockTag.values().stream().map(b -> ValueConversions.of(Registry.BLOCK.getId(b))).collect(Collectors.toList())); }); @@ -1154,7 +1155,7 @@ public class WorldAccess { return ListValue.wrap(tagManager.getBlocks().getTags().entrySet().stream().filter(e -> e.getValue().contains(target)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList())); } String tag = lv.get(blockLocator.offset).getString(); - net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(new Identifier(tag)); + net.minecraft.tag.Tag blockTag = tagManager.getBlocks().getTag(InputValidator.identifierOf(tag)); if (blockTag == null) return Value.NULL; return BooleanValue.of(blockLocator.block.getBlockState().isIn(blockTag)); }); @@ -1170,7 +1171,7 @@ public class WorldAccess { Biome biome; if (locator.replacement != null) { - biome = world.getRegistryManager().get(Registry.BIOME_KEY).get(new Identifier(locator.replacement)); + biome = world.getRegistryManager().get(Registry.BIOME_KEY).get(InputValidator.identifierOf(locator.replacement)); if (biome == null) throw new ThrowStatement(locator.replacement, Throwables.UNKNOWN_BIOME) ; } else @@ -1198,7 +1199,7 @@ public class WorldAccess { throw new InternalExpressionException("'set_biome' needs a biome name as an argument"); String biomeName = lv.get(locator.offset+0).getString(); // from locatebiome command code - Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getOrEmpty(new Identifier(biomeName)) + Biome biome = cc.s.getMinecraftServer().getRegistryManager().get(Registry.BIOME_KEY).getOrEmpty(InputValidator.identifierOf(biomeName)) .orElseThrow(() -> new ThrowStatement(biomeName, Throwables.UNKNOWN_BIOME)); boolean doImmediateUpdate = true; if (lv.size() > locator.offset+1) @@ -1235,7 +1236,7 @@ public class WorldAccess { String simpleStructureName = lv.get(locator.offset).getString().toLowerCase(Locale.ROOT); //CarpetSettings.LOG.error(FeatureGenerator.featureToStructure.keySet().stream().collect(Collectors.joining(","))); //CarpetSettings.LOG.error(FeatureGenerator.featureToStructure.values().stream().collect(Collectors.joining(","))); - StructureFeature structureName = Registry.STRUCTURE_FEATURE.get(new Identifier(simpleStructureName)); + StructureFeature structureName = Registry.STRUCTURE_FEATURE.get(InputValidator.identifierOf(simpleStructureName)); if (structureName == null) return Value.NULL; LongSet structureReferences = references.get(structureName); if (structureReferences == null || structureReferences.isEmpty()) return ListValue.of(); @@ -1264,7 +1265,7 @@ public class WorldAccess { if (!(requested instanceof NullValue)) { String reqString = requested.getString(); - structure = Registry.STRUCTURE_FEATURE.getOrEmpty(new Identifier(reqString)) + structure = Registry.STRUCTURE_FEATURE.getOrEmpty(InputValidator.identifierOf(reqString)) .orElseThrow(() -> new ThrowStatement(reqString, Throwables.UNKNOWN_STRUCTURE)); } if (lv.size() > locator.offset+1) @@ -1325,7 +1326,7 @@ public class WorldAccess { return MapValue.wrap(structureList); } String structureName = lv.get(locator.offset).getString().toLowerCase(Locale.ROOT); - return ValueConversions.of(structures.get(Registry.STRUCTURE_FEATURE.get(new Identifier(structureName)))); + return ValueConversions.of(structures.get(Registry.STRUCTURE_FEATURE.get(InputValidator.identifierOf(structureName)))); }); expression.addContextFunction("set_structure", -1, (c, t, lv) -> diff --git a/src/main/java/carpet/script/utils/InputValidator.java b/src/main/java/carpet/script/utils/InputValidator.java index 67405ab3..9c5ff322 100644 --- a/src/main/java/carpet/script/utils/InputValidator.java +++ b/src/main/java/carpet/script/utils/InputValidator.java @@ -1,6 +1,9 @@ package carpet.script.utils; import carpet.script.exception.InternalExpressionException; +import net.minecraft.util.Identifier; +import net.minecraft.util.InvalidIdentifierException; +import org.lwjgl.system.CallbackI; import java.util.Locale; @@ -13,4 +16,16 @@ public class InputValidator { return simplified; } + public static Identifier identifierOf(String string) + { + try + { + return new Identifier(string); + } + catch (InvalidIdentifierException iie) + { + throw new InternalExpressionException("Incorrect identifier format '"+string+"': "+iie.getMessage()); + } + } + } diff --git a/src/main/java/carpet/script/value/EntityValue.java b/src/main/java/carpet/script/value/EntityValue.java index c83b8585..c68bd9c0 100644 --- a/src/main/java/carpet/script/value/EntityValue.java +++ b/src/main/java/carpet/script/value/EntityValue.java @@ -17,6 +17,7 @@ import carpet.script.CarpetScriptServer; import carpet.script.EntityEventsGroup; import carpet.script.argument.Vector3Argument; import carpet.script.exception.InternalExpressionException; +import carpet.script.utils.InputValidator; import com.google.common.collect.Sets; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; @@ -249,7 +250,7 @@ public class EntityValue extends Value positive = false; who = who.substring(1); } - net.minecraft.tag.Tag> eTag = server.getTagManager().getEntityTypes().getTag(new Identifier(who)); + net.minecraft.tag.Tag> eTag = server.getTagManager().getEntityTypes().getTag(InputValidator.identifierOf(who)); if (eTag == null) throw new InternalExpressionException(who+" is not a valid entity descriptor"); if (positive) { @@ -444,7 +445,7 @@ public class EntityValue extends Value put("has_scoreboard_tag", (e, a) -> BooleanValue.of(e.getScoreboardTags().contains(a.getString()))); put("has_entity_tag", (e, a) -> { - net.minecraft.tag.Tag> tag = e.getServer().getTagManager().getEntityTypes().getTag(new Identifier(a.getString())); + net.minecraft.tag.Tag> tag = e.getServer().getTagManager().getEntityTypes().getTag(InputValidator.identifierOf(a.getString())); if (tag == null) return Value.NULL; return BooleanValue.of(e.getType().isIn(tag)); }); @@ -609,7 +610,7 @@ public class EntityValue extends Value put("brain", (e, a) -> { String module = a.getString(); - MemoryModuleType moduleType = Registry.MEMORY_MODULE_TYPE.get(new Identifier(module)); + MemoryModuleType moduleType = Registry.MEMORY_MODULE_TYPE.get(InputValidator.identifierOf(module)); if (moduleType == MemoryModuleType.DUMMY) return Value.NULL; if (e instanceof LivingEntity) { @@ -704,7 +705,7 @@ public class EntityValue extends Value return ListValue.wrap(effects); } String effectName = a.getString(); - StatusEffect potion = Registry.STATUS_EFFECT.get(new Identifier(effectName)); + StatusEffect potion = Registry.STATUS_EFFECT.get(InputValidator.identifierOf(effectName)); if (potion == null) throw new InternalExpressionException("No such an effect: "+effectName); if (!((LivingEntity) e).hasStatusEffect(potion)) @@ -848,7 +849,7 @@ public class EntityValue extends Value AttributeContainer container = el.getAttributes(); return MapValue.wrap(Registry.ATTRIBUTE.stream().filter(container::hasAttribute).collect(Collectors.toMap(aa -> ValueConversions.of(Registry.ATTRIBUTE.getId(aa)), aa -> NumericValue.of(container.getValue(aa))))); } - Identifier id = new Identifier(a.getString()); + Identifier id = InputValidator.identifierOf(a.getString()); EntityAttribute attrib = Registry.ATTRIBUTE.getOrEmpty(id).orElseThrow( () -> new InternalExpressionException("Unknown attribute: "+a.getString()) ); @@ -1360,7 +1361,7 @@ public class EntityValue extends Value if (lv.size() >= 1 && lv.size() <= 6) { String effectName = lv.get(0).getString(); - StatusEffect effect = Registry.STATUS_EFFECT.get(new Identifier(effectName)); + StatusEffect effect = Registry.STATUS_EFFECT.get(InputValidator.identifierOf(effectName)); if (effect == null) throw new InternalExpressionException("Wrong effect name: "+effectName); if (lv.size() == 1) @@ -1393,7 +1394,7 @@ public class EntityValue extends Value else { String effectName = v.getString(); - StatusEffect effect = Registry.STATUS_EFFECT.get(new Identifier(effectName)); + StatusEffect effect = Registry.STATUS_EFFECT.get(InputValidator.identifierOf(effectName)); if (effect == null) throw new InternalExpressionException("Wrong effect name: "+effectName); le.removeStatusEffect(effect);