Add CommandsDeclareEvent to declare commands with brigadier API

This commit is contained in:
2020-06-08 00:51:21 +02:00
parent 9c078b78c3
commit a67028ec39
3 changed files with 794 additions and 29 deletions

View File

@@ -4,6 +4,7 @@ import com.google.common.base.Preconditions;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.DoubleArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
@@ -36,6 +37,7 @@ import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import net.md_5.bungee.protocol.AbstractPacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.ProtocolConstants;
@Data
@NoArgsConstructor
@@ -126,7 +128,7 @@ public class Commands extends DefinedPacket
}
@Override
public void write(ByteBuf buf)
public void write(ByteBuf buf, ProtocolConstants.Direction direction, int protocolVersion)
{
Map<CommandNode, Integer> indexMap = new LinkedHashMap<>();
Deque<CommandNode> nodeQueue = new ArrayDeque<>();
@@ -210,7 +212,7 @@ public class Commands extends DefinedPacket
ArgumentCommandNode argumentNode = (ArgumentCommandNode) node;
writeString( argumentNode.getName(), buf );
ArgumentRegistry.write( argumentNode.getType(), buf );
ArgumentRegistry.write( argumentNode.getType(), buf, protocolVersion );
if ( argumentNode.getCustomSuggestions() != null )
{
@@ -304,11 +306,12 @@ public class Commands extends DefinedPacket
}
@Data
private static class ArgumentRegistry
public static class ArgumentRegistry
{
private static final Map<String, ArgumentSerializer> PROVIDERS = new HashMap<>();
private static final Map<Class<?>, ProperArgumentSerializer<?>> PROPER_PROVIDERS = new HashMap<>();
private static final Map<String, ProtocolConversionProvider> CONVERSION_PROVIDERS = new HashMap<>();
//
private static final ArgumentSerializer<Void> VOID = new ArgumentSerializer<Void>()
{
@@ -323,18 +326,23 @@ public class Commands extends DefinedPacket
{
}
};
private static final ArgumentSerializer<Boolean> BOOLEAN = new ArgumentSerializer<Boolean>()
private static final ProperArgumentSerializer<BoolArgumentType> BOOLEAN = new ProperArgumentSerializer<BoolArgumentType>()
{
@Override
protected Boolean read(ByteBuf buf)
protected BoolArgumentType read(ByteBuf buf)
{
return buf.readBoolean();
return BoolArgumentType.bool();
}
@Override
protected void write(ByteBuf buf, Boolean t)
protected void write(ByteBuf buf, BoolArgumentType t)
{
buf.writeBoolean( t );
}
@Override
protected String getKey()
{
return "brigadier:bool";
}
};
private static final ArgumentSerializer<Byte> BYTE = new ArgumentSerializer<Byte>()
@@ -351,7 +359,7 @@ public class Commands extends DefinedPacket
buf.writeByte( t );
}
};
private static final ArgumentSerializer<FloatArgumentType> FLOAT = new ArgumentSerializer<FloatArgumentType>()
private static final ProperArgumentSerializer<FloatArgumentType> FLOAT = new ProperArgumentSerializer<FloatArgumentType>()
{
@Override
protected FloatArgumentType read(ByteBuf buf)
@@ -379,8 +387,14 @@ public class Commands extends DefinedPacket
buf.writeFloat( t.getMaximum() );
}
}
@Override
protected String getKey()
{
return "brigadier:float";
}
};
private static final ArgumentSerializer<DoubleArgumentType> DOUBLE = new ArgumentSerializer<DoubleArgumentType>()
private static final ProperArgumentSerializer<DoubleArgumentType> DOUBLE = new ProperArgumentSerializer<DoubleArgumentType>()
{
@Override
protected DoubleArgumentType read(ByteBuf buf)
@@ -408,8 +422,14 @@ public class Commands extends DefinedPacket
buf.writeDouble( t.getMaximum() );
}
}
@Override
protected String getKey()
{
return "brigadier:double";
}
};
private static final ArgumentSerializer<IntegerArgumentType> INTEGER = new ArgumentSerializer<IntegerArgumentType>()
private static final ProperArgumentSerializer<IntegerArgumentType> INTEGER = new ProperArgumentSerializer<IntegerArgumentType>()
{
@Override
protected IntegerArgumentType read(ByteBuf buf)
@@ -437,8 +457,14 @@ public class Commands extends DefinedPacket
buf.writeInt( t.getMaximum() );
}
}
@Override
protected String getKey()
{
return "brigadier:integer";
}
};
private static final ArgumentSerializer<LongArgumentType> LONG = new ArgumentSerializer<LongArgumentType>()
private static final ProperArgumentSerializer<LongArgumentType> LONG = new ProperArgumentSerializer<LongArgumentType>()
{
@Override
protected LongArgumentType read(ByteBuf buf)
@@ -466,6 +492,12 @@ public class Commands extends DefinedPacket
buf.writeLong( t.getMaximum() );
}
}
@Override
protected String getKey()
{
return "brigadier:long";
}
};
private static final ProperArgumentSerializer<StringArgumentType> STRING = new ProperArgumentSerializer<StringArgumentType>()
{
@@ -501,11 +533,31 @@ public class Commands extends DefinedPacket
static
{
PROVIDERS.put( "brigadier:bool", VOID );
PROVIDERS.put( "brigadier:bool", BOOLEAN );
PROPER_PROVIDERS.put( BoolArgumentType.class, BOOLEAN );
PROVIDERS.put( "brigadier:float", FLOAT );
PROPER_PROVIDERS.put( FloatArgumentType.class, FLOAT );
PROVIDERS.put( "brigadier:double", DOUBLE );
PROPER_PROVIDERS.put( DoubleArgumentType.class, DOUBLE );
PROVIDERS.put( "brigadier:integer", INTEGER );
PROVIDERS.put( "brigadier:long", LONG );
PROPER_PROVIDERS.put( IntegerArgumentType.class, INTEGER );
PROVIDERS.put( "brigadier:long", LONG ); // 1.14+
PROPER_PROVIDERS.put( LongArgumentType.class, LONG );
CONVERSION_PROVIDERS.put( "brigadier:long", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
LongArgumentType type = (LongArgumentType) originalType;
int min = (int) Math.max( Integer.MIN_VALUE, Math.min( Integer.MAX_VALUE, type.getMinimum() ) );
int max = (int) Math.max( Integer.MIN_VALUE, Math.min( Integer.MAX_VALUE, type.getMaximum() ) );
return IntegerArgumentType.integer( min, max );
}
return originalType;
} );
PROVIDERS.put( "brigadier:string", STRING );
PROPER_PROVIDERS.put( StringArgumentType.class, STRING );
@@ -523,9 +575,37 @@ public class Commands extends DefinedPacket
PROVIDERS.put( "minecraft:color", VOID );
PROVIDERS.put( "minecraft:component", VOID );
PROVIDERS.put( "minecraft:message", VOID );
PROVIDERS.put( "minecraft:nbt_compound_tag", VOID ); // 1.14
PROVIDERS.put( "minecraft:nbt_tag", VOID ); // 1.14
PROVIDERS.put( "minecraft:nbt_compound_tag", VOID ); // 1.14+, replaces minecraft:nbt
CONVERSION_PROVIDERS.put( "minecraft:nbt_compound_tag", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
return minecraftNBT();
}
return originalType;
} );
PROVIDERS.put( "minecraft:nbt_tag", VOID ); // 1.14+
CONVERSION_PROVIDERS.put( "minecraft:nbt_tag", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
return minecraftNBT();
}
return originalType;
} );
PROVIDERS.put( "minecraft:nbt", VOID ); // 1.13
CONVERSION_PROVIDERS.put( "minecraft:nbt", ( originalType, protocolVersion ) ->
{
if ( protocolVersion >= ProtocolConstants.MINECRAFT_1_14 )
{
return minecraftNBTCompoundTag();
}
return originalType;
} );
PROVIDERS.put( "minecraft:nbt_path", VOID );
PROVIDERS.put( "minecraft:objective", VOID );
PROVIDERS.put( "minecraft:objective_criteria", VOID );
@@ -546,11 +626,417 @@ public class Commands extends DefinedPacket
PROVIDERS.put( "minecraft:item_enchantment", VOID );
PROVIDERS.put( "minecraft:entity_summon", VOID );
PROVIDERS.put( "minecraft:dimension", VOID );
PROVIDERS.put( "minecraft:time", VOID ); // 1.14
PROVIDERS.put( "minecraft:uuid", VOID ); // 1.16
PROVIDERS.put( "minecraft:test_argument", VOID ); // 1.16, debug
PROVIDERS.put( "minecraft:test_class", VOID ); // 1.16, debug
PROVIDERS.put( "minecraft:angle", VOID ); // 1.16.2
PROVIDERS.put( "minecraft:time", VOID ); // 1.14+
CONVERSION_PROVIDERS.put( "minecraft:time", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_14 )
{
return StringArgumentType.word();
}
return originalType;
} );
PROVIDERS.put( "minecraft:uuid", VOID ); // 1.16+
CONVERSION_PROVIDERS.put( "minecraft:uuid", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16 )
{
return StringArgumentType.word();
}
return originalType;
} );
PROVIDERS.put( "minecraft:test_argument", VOID ); // 1.16+, debug
PROVIDERS.put( "minecraft:test_class", VOID ); // 1.16+, debug
PROVIDERS.put( "minecraft:angle", VOID ); // 1.16.2+
CONVERSION_PROVIDERS.put( "minecraft:angle", ( originalType, protocolVersion ) ->
{
if ( protocolVersion < ProtocolConstants.MINECRAFT_1_16_2 )
{
return FloatArgumentType.floatArg();
}
return originalType;
} );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity}.
* @param singleEntity if the argument restrict to only one entity
* @param onlyPlayers if the argument restrict to players only
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntity(boolean singleEntity, boolean onlyPlayers)
{
byte flags = 0;
if ( singleEntity )
{
flags |= 1;
}
if ( onlyPlayers )
{
flags |= 2;
}
return minecraftArgumentType( "minecraft:entity", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:game_profile}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftGameProfile()
{
return minecraftArgumentType( "minecraft:game_profile", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPos()
{
return minecraftArgumentType( "minecraft:block_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:column_pos}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColumnPos()
{
return minecraftArgumentType( "minecraft:column_pos", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec3}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec3()
{
return minecraftArgumentType( "minecraft:vec3", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:vec2}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftVec2()
{
return minecraftArgumentType( "minecraft:vec2", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_state}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockState()
{
return minecraftArgumentType( "minecraft:block_state", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:block_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftBlockPredicate()
{
return minecraftArgumentType( "minecraft:block_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_stack}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemStack()
{
return minecraftArgumentType( "minecraft:item_stack", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_predicate}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemPredicate()
{
return minecraftArgumentType( "minecraft:item_predicate", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:color}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftColor()
{
return minecraftArgumentType( "minecraft:color", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:component}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftComponent()
{
return minecraftArgumentType( "minecraft:component", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:message}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMessage()
{
return minecraftArgumentType( "minecraft:message", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_compound_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTCompoundTag()
{
return minecraftArgumentType( "minecraft:nbt_compound_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_tag}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTTag()
{
return minecraftArgumentType( "minecraft:nbt_tag", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBT()
{
return minecraftArgumentType( "minecraft:nbt", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:nbt_path}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftNBTPath()
{
return minecraftArgumentType( "minecraft:nbt_path", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjective()
{
return minecraftArgumentType( "minecraft:objective", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:objective_criteria}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftObjectiveCriteria()
{
return minecraftArgumentType( "minecraft:objective_criteria", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:operation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftOperation()
{
return minecraftArgumentType( "minecraft:operation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:particle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftParticle()
{
return minecraftArgumentType( "minecraft:particle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:rotation}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftRotation()
{
return minecraftArgumentType( "minecraft:rotation", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:scoreboard_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreboardSlot()
{
return minecraftArgumentType( "minecraft:scoreboard_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:score_holder}.
* @param allowMultiple if the argument allows multiple entities
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftScoreHolder(boolean allowMultiple)
{
byte flags = 0;
if ( allowMultiple )
{
flags |= 1;
}
return minecraftArgumentType( "minecraft:score_holder", flags );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:swizzle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftSwizzle()
{
return minecraftArgumentType( "minecraft:swizzle", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:team}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTeam()
{
return minecraftArgumentType( "minecraft:team", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_slot}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemSlot()
{
return minecraftArgumentType( "minecraft:item_slot", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:resource_location}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftResourceLocation()
{
return minecraftArgumentType( "minecraft:resource_location", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:mob_effect}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftMobEffect()
{
return minecraftArgumentType( "minecraft:mob_effect", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:function}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFunction()
{
return minecraftArgumentType( "minecraft:function", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_anchor}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntityAnchor()
{
return minecraftArgumentType( "minecraft:entity_anchor", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:int_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftIntRange()
{
return minecraftArgumentType( "minecraft:int_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:float_range}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftFloatRange()
{
return minecraftArgumentType( "minecraft:float_range", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:item_enchantment}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftItemEnchantment()
{
return minecraftArgumentType( "minecraft:item_enchantment", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:entity_summon}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftEntitySummon()
{
return minecraftArgumentType( "minecraft:entity_summon", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:dimension}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftDimension()
{
return minecraftArgumentType( "minecraft:dimension", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:time}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftTime()
{
return minecraftArgumentType( "minecraft:time", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:uuid}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftUUID()
{
return minecraftArgumentType( "minecraft:uuid", null );
}
/**
* Returns the Minecraft ArgumentType {@code minecraft:angle}.
* @return an ArgumentType instance
*/
public static ArgumentType<?> minecraftAngle()
{
return minecraftArgumentType( "minecraft:angle", null );
}
private static ArgumentType<?> minecraftArgumentType(String key, Object rawValue)
{
ArgumentSerializer reader = PROVIDERS.get( key );
Preconditions.checkArgument( reader != null, "No provider for argument " + key );
return new DummyType( key, reader, rawValue );
}
private static ArgumentType<?> read(String key, ByteBuf buf)
@@ -562,8 +1048,10 @@ public class Commands extends DefinedPacket
return val != null && PROPER_PROVIDERS.containsKey( val.getClass() ) ? (ArgumentType<?>) val : new DummyType( key, reader, val );
}
private static void write(ArgumentType<?> arg, ByteBuf buf)
private static void write(ArgumentType<?> arg, ByteBuf buf, int protocolVersion)
{
arg = convertToVersion( arg, protocolVersion );
ProperArgumentSerializer proper = PROPER_PROVIDERS.get( arg.getClass() );
if ( proper != null )
{
@@ -579,6 +1067,34 @@ public class Commands extends DefinedPacket
}
}
// Convert the provided argument type to a new one compatible with the provided protocol version
private static ArgumentType<?> convertToVersion(ArgumentType<?> arg, int protocolVersion)
{
ProperArgumentSerializer proper = PROPER_PROVIDERS.get( arg.getClass() );
String key;
if ( proper != null )
{
key = proper.getKey();
} else
{
Preconditions.checkArgument( arg instanceof DummyType, "Non dummy arg " + arg.getClass() );
key = ( (DummyType) arg ).key;
}
ProtocolConversionProvider converter = CONVERSION_PROVIDERS.get( key );
if ( converter != null )
{
return converter.convert( arg, protocolVersion );
}
return arg;
}
private interface ProtocolConversionProvider
{
public ArgumentType<?> convert(ArgumentType<?> originalType, int protocolVersion);
}
@Data
private static class DummyType<T> implements ArgumentType<T>
{
@@ -612,17 +1128,39 @@ public class Commands extends DefinedPacket
@Data
public static class SuggestionRegistry
{
/**
* Tells the client to ask suggestions to the server.
*/
public static final SuggestionProvider ASK_SERVER = new DummyProvider( "minecraft:ask_server" );
/**
* Tells the client to suggest all the available recipes. The suggestions are stored client side.
*/
public static final SuggestionProvider ALL_RECIPES = new DummyProvider( "minecraft:all_recipes" );
/**
* Tells the client to suggest all the available sounds. The suggestions are stored client side.
*/
public static final SuggestionProvider AVAILABLE_SOUNDS = new DummyProvider( "minecraft:available_sounds" );
/**
* Tells the client to suggest all the available biomes. The suggestions are stored client side.
*/
public static final SuggestionProvider AVAILABLE_BIOMES = new DummyProvider( "minecraft:available_biomes" );
/**
* Tells the client to suggest all the available entities. The suggestions are stored client side.
*/
public static final SuggestionProvider SUMMONABLE_ENTITIES = new DummyProvider( "minecraft:summonable_entities" );
private static final Map<String, SuggestionProvider<DummyProvider>> PROVIDERS = new HashMap<>();
static
{
PROVIDERS.put( "minecraft:ask_server", ASK_SERVER );
registerDummy( "minecraft:all_recipes" );
registerDummy( "minecraft:available_sounds" );
registerDummy( "minecraft:available_biomes" );
registerDummy( "minecraft:summonable_entities" );
PROVIDERS.put( "minecraft:all_recipes", ALL_RECIPES );
PROVIDERS.put( "minecraft:available_sounds", AVAILABLE_SOUNDS );
PROVIDERS.put( "minecraft:available_biomes", AVAILABLE_BIOMES );
PROVIDERS.put( "minecraft:summonable_entities", SUMMONABLE_ENTITIES );
}
private static void registerDummy(String name)
@@ -640,9 +1178,13 @@ public class Commands extends DefinedPacket
private static String getKey(SuggestionProvider<DummyProvider> provider)
{
Preconditions.checkArgument( provider instanceof DummyProvider, "Non dummy provider " + provider );
Preconditions.checkNotNull( provider );
if ( provider instanceof DummyProvider )
{
return ( (DummyProvider) provider ).key;
}
return ( (DummyProvider) provider ).key;
return ( (DummyProvider) ASK_SERVER ).key;
}
@Data