package carpet.script.annotation; import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.lang.reflect.AnnotatedType; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.BiFunction; import carpet.CarpetServer; import carpet.script.Context; import carpet.script.value.BooleanValue; import carpet.script.value.EntityValue; import carpet.script.value.FormattedTextValue; import carpet.script.value.NumericValue; import carpet.script.value.StringValue; import carpet.script.value.Value; import net.minecraft.network.chat.Component; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import javax.annotation.Nullable; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.ElementType.TYPE_USE; import static java.lang.annotation.RetentionPolicy.RUNTIME; /** *
Class that holds annotations for Scarpet parameters.
* * @see Param.Strict * @see Param.AllowSingleton * @see Param.Custom * @see Locator.Block * @see Locator.Vec3d * @see Locator.Function * */ public interface Param { /** *Determines that this parameter accepts being passing a value directly instead of a list of those values.
* *Can only be used in {@link List} parameters.
* *The function method will receive a singleton of the item in question if there's a single value.
*/ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @interface AllowSingleton { } /** *Determines that this (and optionally the following parameters) accept either a map of the specified key-value pairs, a list type [key, * value, key2, value2,...] or the same as the list but directly in the parameters (can be disabled in {@link #allowMultiparam()}).
* *Can only be used in {@link Map} types, and {@link #allowMultiparam()} requires it to not be in a type parameter (since lists and maps * contains groups of single items)
* *IMPORTANT: Using this annotation with {@link #allowMultiparam()} will make this element consume each and every remaining value in the
* function call, therefore it will cause any other parameters (that are not varargs) to throw as if they were not present, unless they are
* optional (defined by using Java's {@link Optional} type). They could only be accessed if the parameter at this location is specifically a list
* or map.
Having it as {@code true} will also cause the function to be considered of variable arguments even if it doesn't have varargs.
Whether or not this accepts the key-value pairs directly in the function call as myFunction(..., key, value, key2, value2)
* *Having this set to {@code true} (as it is by default) has the side effects of effectively converting the method in a variable parameter * count method, and consuming everything remaining in the parameter list unless it finds as first parameter a map or list to generate the map * from, causing any following parameters (except varargs) to throw as if they were not present, unless they are optional.
*/ boolean allowMultiparam() default true; } /** *Defines that the parameter's converter has to be retrieved from the custom converter storage, in order to allow extensions to register * complex {@link ValueConverter}s. You can register such converters in {@link Params#registerCustomConverterFactory(BiFunction)}, although * if you only need a simple {@link Value}->something converter you should be looking at {@link SimpleTypeConverter} instead
*/ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @interface Custom { } /** *Defines that a parameter of type {@link String}, {@link Component}, {@link ServerPlayer}, {@link Boolean} or other registered strict type * must be of its corresponding {@link Value} in order to be accepted (respectively {@link StringValue}, {@link FormattedTextValue}, * {@link EntityValue} or {@link BooleanValue}).
* *If this annotation is not specified, Carpet will accept any other {@link Value} and call respectively {@link Value#getString()}, * {@code new LiteralText(Value#getString())}, {@link EntityValue#getPlayerByValue(MinecraftServer, Value)} or {@link Value#getBoolean()}.
* *You can define "shallow strictness" ({@link #shallow()}) if you want to allow passing both a {@link StringValue} or a * {@link FormattedTextValue} to a {@link Component} parameter or a {@link NumericValue} to a {@link BooleanValue}, but not any {@link Value}.
* */ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @interface Strict { /** *Defines whether this parameter can accept types with "shallow strictness", that is, in order to get a {@link Component}, accepting either a * {@link StringValue} or a {@link FormattedTextValue} as the parameter, or in order to get a {@link Boolean}, accepting either a * {@link NumericValue} or a {@link BooleanValue}.
* *Without shallow mode, it would only accept from specifically a {@link FormattedTextValue} or {@link BooleanValue} respectively. * *
Using this in an unsupported type will throw {@link IllegalArgumentException}, just as if you used the annotation in an unsupported * type.
* *This is {@code false} by default.
*/ boolean shallow() default false; } /** *Class that holds the actual converters and converter getting logic for those annotated types and things.
* *It also holds the registry for strict and custom {@link ValueConverter}s.
* * @see #registerStrictConverter(Class, boolean, ValueConverter) * @see #registerCustomConverterFactory(BiFunction) * */ final class Params { /** *A {@link ValueConverter} that outputs the {@link Context} in which the function has been called, and throws {@link UnsupportedOperationException} when trying to convert a {@link Value} * directly.
*/ static final ValueConverterA {@link ValueConverter} that outputs the {@link Context.Type} which the function has been called, or throws {@link UnsupportedOperationException} when trying to convert a {@link Value} * directly.
*/ static final ValueConverterRegisters a new {@link Param.Strict} parameter converter with the specified shallowness.
* *Registered types should follow the general contract of the rest of {@link Param.Strict} parameter converters, that is, don't have a * shallow-strict converter registered without having a fully-strict converter available. In order to register completely non-strict * converters, those should be registered in their respective {@link ValueConverter} classes, usually in {@link SimpleTypeConverter}.
* * @paramAllows extensions to register COMPLEX {@link ValueConverter} factories in order to be used with the {@link Param.Custom} * annotation.
If you only need to register a converter from a {@link Value} to a type, use * {@link SimpleTypeConverter#registerType(Class, Class, java.util.function.Function, String)} instead. This is intended to be used when you * need more granular control over the conversion, such as custom extra parameters via annotations, converters using multiple values, or even * a variable number of values.
The annotation parser will loop through all registered custom converter factories when searching * for the appropriate {@link ValueConverter} for a parameter annotated with the {@link Param.Custom} annotation.
Factories are * expected to return {@code null} when the provided arguments don't match a {@link ValueConverter} they are able to create (or reuse).
*You have {@link ValueCaster#get(Class)} and {@link ValueConverter#fromAnnotatedType(AnnotatedType)} available in case you need to get * valid {@link ValueConverter}s for things such as nested types, intermediary conversions or whatever you really need them for.
* * @param