added slot argument type, fixes #564

This commit is contained in:
gnembon committed 2020-11-26 02:52:41 -04:00
1 parent 79cb4a20d8
commit cd3880ea07
3 files changed
+149

No files matched your search

+5
View File
@@ -214,6 +214,11 @@ Here is a list of built-in types, with their return value formats, as well as a
* `'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.
* `'enchantment'`: name of an enchantment
* `'slot'`: provides a list of inventory type and slot. Can be configured with `'restrict'` requiring
`'player'`, `'enderchest'`, `'equipment'`, `'armor'`, `'weapon'`, `'container'`, `'villager'` or `'horse'` restricting selection of
available slots. Scarpet supports all vanilla slots, except for `horse.chest` - chest item, not items themselves. This you would
need to manage yourself via nbt directly. Also, for entities that change their capacity, like llamas, you need to check yourself if
the specified container slot is valid for your entity.
* `'item'`: triple of item type, count of 1, and nbt.
* `'message'`: text with expanded embedded player names
* `'effect'`: string representing a status effect
@@ -47,6 +47,7 @@ import net.minecraft.command.argument.EntitySummonArgumentType;
import net.minecraft.command.argument.GameProfileArgumentType;
import net.minecraft.command.argument.IdentifierArgumentType;
import net.minecraft.command.argument.ItemEnchantmentArgumentType;
import net.minecraft.command.argument.ItemSlotArgumentType;
import net.minecraft.command.argument.ItemStackArgumentType;
import net.minecraft.command.argument.MessageArgumentType;
import net.minecraft.command.argument.MobEffectArgumentType;
@@ -78,11 +79,14 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec2f;
import net.minecraft.util.registry.Registry;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -158,6 +162,7 @@ public abstract class CommandArgument
),
// item_predicate ?? //same as item but accepts tags, not sure right now
// slot // item_slot
new SlotArgument(),
new VanillaUnconfigurableArgument("item", ItemStackArgumentType::itemStack,
(c, p) -> ValueConversions.of(ItemStackArgumentType.getItemStackArgument(c, p).createStack(1, false)), false
),
@@ -849,6 +854,100 @@ public abstract class CommandArgument
return IntArgument::new;
}
}
private static class SlotArgument extends CommandArgument
{
private String restrict;
private static final Map<String, Pair<Set<Integer>, Set<String>>> RESTRICTED_CONTAINERS = new HashMap<String, Pair<Set<Integer>, Set<String>>>(){{
int i;
for (String source : Arrays.asList("player", "enderchest", "equipment", "armor", "weapon", "container", "villager", "horse"))
put(source, Pair.of(new HashSet<>(), new HashSet<>()));
for (i = 0; i < 41; i++) get("player").getLeft().add(i);
for(i = 0; i < 41; i++) get("player").getRight().add("container." + i);
for(i = 0; i < 9; i++) get("player").getRight().add("hotbar." + i);
for(i = 0; i < 27; i++) get("player").getRight().add("inventory." + i);
for (String place : Arrays.asList("weapon", "weapon.mainhand", "weapon.offhand"))
{
get("player").getRight().add(place);
get("equipment").getRight().add(place);
get("weapon").getRight().add(place);
}
for (String place : Arrays.asList("armor.feet","armor.legs", "armor.chest","armor.head"))
{
get("player").getRight().add(place);
get("equipment").getRight().add(place);
get("armor").getRight().add(place);
}
for (i = 0; i < 27; i++) get("enderchest").getLeft().add(200+i);
for(i = 0; i < 27; i++) get("enderchest").getRight().add("enderchest." + i);
for (i = 0; i < 6; i++) get("equipment").getLeft().add(98+i);
for (i = 0; i < 4; i++) get("armor").getLeft().add(100+i);
for (i = 0; i < 2; i++) get("weapon").getLeft().add(98+i);
for (i = 0; i < 54; i++) get("container").getLeft().add(i);
for(i = 0; i < 41; i++) get("container").getRight().add("container." + i);
for (i = 0; i < 8; i++) get("villager").getLeft().add(i);
for(i = 0; i < 8; i++) get("villager").getRight().add("villager." + i);
for (i = 0; i < 15; i++) get("horse").getLeft().add(500+i);
for(i = 0; i < 15; i++) get("horse").getRight().add("horse." + i);
get("horse").getLeft().add(400);
get("horse").getRight().add("horse.saddle");
get("horse").getLeft().add(401);
get("horse").getRight().add("horse.armor");
}};
protected SlotArgument()
{
super("slot", ItemSlotArgumentType.itemSlot().getExamples(), false);
}
@Override
protected ArgumentType<?> getArgumentType() throws CommandSyntaxException
{
return ItemSlotArgumentType.itemSlot();
}
@Override
protected Value getValueFromContext(CommandContext<ServerCommandSource> context, String param) throws CommandSyntaxException
{
int slot = ItemSlotArgumentType.getItemSlot(context, param);
if (restrict != null && !RESTRICTED_CONTAINERS.get(restrict).getLeft().contains(slot))
{
throw new SimpleCommandExceptionType(new LiteralText("Incorrect slot restricted to "+restrict)).create();
}
return ValueConversions.ofVanillaSlotResult(slot);
}
@Override
protected void configure(Map<String, Value> config, CarpetScriptHost host)
{
super.configure(config, host);
if (config.containsKey("restrict"))
{
restrict = config.get("restrict").getString().toLowerCase(Locale.ROOT);
needsMatching = true;
if (!RESTRICTED_CONTAINERS.containsKey(restrict))
throw new InternalExpressionException("Incorrect slot restriction: "+restrict);
}
}
@Override
protected Collection<String> getOptions(CommandContext<ServerCommandSource> context, CarpetScriptHost host) throws CommandSyntaxException
{
return restrict==null?super.getOptions(context, host):RESTRICTED_CONTAINERS.get(restrict).getRight();
}
@Override
protected Supplier<CommandArgument> factory()
{
return SlotArgument::new;
}
}
@FunctionalInterface
private interface ValueExtractor
@@ -330,4 +330,49 @@ public class ValueConversions
}
throw new InternalExpressionException("Unknown property type: "+p.getName());
}
private static final Map<Integer, ListValue> slotIdsToSlotParams = new HashMap<Integer, ListValue>() {{
int n;
//covers blocks, player hotbar and inventory, and all default inventories
for(n = 0; n < 54; ++n) {
put(n, ListValue.of(Value.NULL, NumericValue.of(n)));
}
for(n = 0; n < 27; ++n) {
put(200+n, ListValue.of(StringValue.of("enderchest"), NumericValue.of(n)));
}
// villager
for(n = 0; n < 8; ++n) {
put(300+n, ListValue.of(Value.NULL, NumericValue.of(n)));
}
// horse, llamas, donkeys, etc.
// two first slots are for saddle and armour
for(n = 0; n < 15; ++n) {
put(500+n, ListValue.of(Value.NULL, NumericValue.of(n+2)));
}
Value equipment = StringValue.of("equipment");
// weapon main hand
put(98, ListValue.of(equipment, NumericValue.of(0)));
// offhand
put(99, ListValue.of(equipment, NumericValue.of(5)));
// feet, legs, chest, head
for(n = 0; n < 4; ++n) {
put(100+n, ListValue.of(equipment, NumericValue.of(n+1)));
}
//horse defaults saddle
put(400, ListValue.of(Value.NULL, NumericValue.of(0)));
// armor
put(401, ListValue.of(Value.NULL, NumericValue.of(1)));
// chest itself on the donkey is wierd - use NBT to alter that.
//hashMap.put("horse.chest", 499);
}};
public static Value ofVanillaSlotResult(int itemSlot)
{
Value ret = slotIdsToSlotParams.get(itemSlot);
if (ret == null) return ListValue.of(Value.NULL, NumericValue.of(itemSlot));
return ret;
}
}