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.Iterator; import org.apache.commons.lang3.NotImplementedException; import carpet.script.Context; import carpet.script.argument.Argument; import carpet.script.argument.BlockArgument; import carpet.script.argument.FunctionArgument; import carpet.script.argument.Vector3Argument; import carpet.script.bundled.Module; import carpet.script.value.BlockValue; import carpet.script.value.FunctionValue; import carpet.script.value.Value; 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 annotation for {@link Argument} locators to be used in Scarpet functions.

* *

Note: Nothing in this class has been implemented at this point in time, since it requires Carpet changes. There is an implementation for * Locator.Block working, but not implemented.

*/ public interface Locator { /** *

Represents that the annotated argument must be gotten by passing the arguments in there into a {@link BlockArgument} locator.

* *

Must be used in either {@link BlockValue} or {@link BlockArgument} parameters

*/ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @Deprecated // Not implemented, although implementation available public @interface Block { /** *

Whether or not should the locator accept a single {@link String} as the parameter and let parsing to {@link BlockValue}.

*/ boolean acceptString() default false; /** *

Whether or not should the {@link BlockValue} argument be optional.

Requires the annotation to be present in a * {@link BlockArgument} type, since it may return that the {@link BlockValue} is {@code null}, which would be considered as an incorrect * type.

*/ boolean optional() default false; /** *

Whether or not should the {@link BlockArgument} locator accept any string as the argument.

Requires the annotation to be present * in a {@link BlockArgument} type, since it may just return a {@link String}

*/ boolean anyString() default false; } /** *

Represents that the annotated argument must be gotten by passing the arguments in there into a {@link Vector3Argument} locator.

* *

Must be used in either a {@link Vector3Argument} or a {@link Vec3d} parameter, though the latest may not get all the data.

* *

Note: This locator has not been implemented yet (TODO)

*/ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @Deprecated // Not implemented public @interface Vec3d { /** *

Whether or not should the {@link Vector3Argument} locator accept an optional direction aside from the * {@link net.minecraft.util.math.Vec3d}

This parameter can only be used in a {@link Vector3Argument} type, since else there is no way * to get the direction too.

*/ boolean optionalDirection() default false; /** *

Whether or not should the {@link Vector3Argument} locator accept an entity aside to get the {@link Vec3d} from and return that entity * too

Note that you will only be able to get that entity if the annotation is present in a {@link Vector3Argument}

*/ boolean optionalEntity() default false; } /** *

Represents that the annotated argument must be gotten by passing the arguments in this annotation into a {@link FunctionArgument} * locator

* *

Can be used in both {@link FunctionArgument} and {@link FunctionValue} types, but the last won't have access to arguments provided to the * function, even though they will still be consumed from the arguments the function was called with.

* *

This will consume any remaining parameters passed to the function, therefore any other parameters after this will throw.

* *

Note: This locator has not been implemented yet (TODO)

*/ @Documented @Retention(RUNTIME) @Target({ PARAMETER, TYPE_USE }) @Deprecated // Not implemented public @interface Function { /** *

Whether this Locator should allow no function to be passed.

This is not compatible with {@link FunctionValue} type, since a * converter returning {@code null} will throw as if the passed argument was incorrect. You can still use it when targeting * {@link FunctionArgument}

*/ boolean allowNone() default false; /** *

Whether the locator should check that the number of arguments passed along with the function matches the number of arguments that the * located function requires. Note that FunctionLocators consume all remaining arguments even if this is set to {@code false}.

*/ boolean checkArgs(); } /** *

Class that holds locators and methods to get them

* *

Not part of the public API, just that interfaces must have all members public

*/ static final class Locators { private Locators() {} static ValueConverter fromAnnotatedType(AnnotatedType annoType, Class type) { if (annoType.isAnnotationPresent(Block.class)) return new BlockLocator(annoType.getAnnotation(Block.class), type); if (annoType.isAnnotationPresent(Function.class)) return new FunctionLocator(annoType.getAnnotation(Function.class), type); if (annoType.isAnnotationPresent(Vec3d.class)) return new Vec3dLocator(annoType.getAnnotation(Vec3d.class), type); throw new IllegalStateException("Locator#fromAnnotatedType got called with an incompatible AnnotatedType"); } private static class BlockLocator extends AbstractLocator { private final boolean returnBlockValue; private final boolean acceptString; private final boolean anyString; private final boolean optional; public BlockLocator(Block annotation, Class type) { this.acceptString = annotation.acceptString(); this.anyString = annotation.anyString(); this.optional = annotation.optional(); this.returnBlockValue = type == BlockValue.class; if (returnBlockValue && (anyString || optional)) throw new IllegalArgumentException("Can only use anyString or optional parameters of Locator.Block if targeting a BlockArgument"); if (!returnBlockValue && type != BlockArgument.class) throw new IllegalArgumentException("Locator.Block can only be used against BlockArgument or BlockValue types!"); } @Override public String getTypeName() { return "block"; } @Override public R checkAndConvert(Iterator valueIterator, Context context, Context.Type theLazyT) { BlockArgument locator = null; // BlockArgument.findIn((CarpetContext)context, valueIterator (requires changing to Value), 0, // acceptString, optional, anyString); // return (R) (returnBlockValue ? locator.block : locator); throw new NotImplementedException("Locator.Block still requires adapting BlockArgument to accept iterators (which is actually simple)"); } } private static class Vec3dLocator extends AbstractLocator { private final boolean optionalDirection; private final boolean optionalEntity; private final boolean returnVec3d; public Vec3dLocator(Vec3d annotation, Class type) { this.optionalDirection = annotation.optionalDirection(); this.optionalEntity = annotation.optionalEntity(); this.returnVec3d = type == net.minecraft.util.math.Vec3d.class; // Because of the locator if (returnVec3d && optionalDirection) throw new IllegalArgumentException("optionalDirection Locator.Vec3d cannot be used for Vec3d type, use Vector3Argument instead"); if (!returnVec3d && type != Vector3Argument.class) throw new IllegalArgumentException("Locator.Vec3d can only be used in Vector3Argument or Vec3d types"); } @Override public String getTypeName() { return "position"; } @Override public R checkAndConvert(Iterator valueIterator, Context context, Context.Type theLazyT) { Vector3Argument locator = null; // TODO Make the locator // return (R) (returnVec3d ? locator.vec : locator); throw new NotImplementedException("Locator.Vec3d still require adapting Vector3Argument to accept iterators!"); } } private static class FunctionLocator extends AbstractLocator { private final boolean returnFunctionValue; private final boolean allowNone; private final boolean checkArgs; FunctionLocator(Function annotation, Class type) { this.returnFunctionValue = type == FunctionValue.class; if (!returnFunctionValue && type != FunctionArgument.class) throw new IllegalArgumentException( "Params annotated with Locator.Function must be of either FunctionArgument or FunctionValue type"); this.allowNone = annotation.allowNone(); this.checkArgs = annotation.checkArgs(); if (returnFunctionValue && allowNone) throw new IllegalArgumentException("Cannot use allowNone of Locator.Function in FunctionValue types, use FunctionArgument"); } @Override public R checkAndConvert(Iterator valueIterator, Context context, Context.Type theLazyT) { Module module = context.host.main; FunctionArgument locator = null; // TODO Make the locator // return (R) (returnFunctionValue ? locator.function : locator); throw new NotImplementedException("Locator.FunctionValue still requires adapting the annotation system to somehow get lv size" + "or FunctionArgument to not depend on it!"); } @Override public String getTypeName() { return "function"; } } private static abstract class AbstractLocator implements ValueConverter, Locator { @Override public R convert(Value value) { throw new UnsupportedOperationException("Cannot call a locator in a parameter that doesn't contain a context!"); } @Override public boolean consumesVariableArgs() { return true; } @Override public int valueConsumption() { return 1; } @Override public abstract R checkAndConvert(Iterator valueIterator, Context context, Context.Type theLazyT); } } }