Search in sources :

Example 11 with Tuple

use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.

the class GetterFilterSourceDelegate method write.

@Override
public Tuple<Integer, Integer> write(final ClassWriter cw, final MethodVisitor mv, final ListenerClassVisitor.DiscoveredMethod method, final int paramIdx, int local, final int[] plocals, final ListenerClassVisitor.ListenerParameter[] params) throws ClassNotFoundException {
    final Class<?> targetType = method.classByLoader(params[paramIdx].type().getClassName());
    final Class<?> eventClass = method.classByLoader(params[0].type().getClassName());
    final String targetMethod = this.anno.value();
    Method targetMethodObj = null;
    try {
        targetMethodObj = eventClass.getMethod(targetMethod);
    } catch (final NoSuchMethodException e) {
        throw new IllegalArgumentException(String.format("Method %s specified by getter annotation was not found in type %s", targetMethod, eventClass.getName()));
    }
    if (targetMethodObj.getParameterCount() != 0) {
        throw new IllegalArgumentException("Method " + targetMethodObj.toGenericString() + " specified by getter annotation has non-zero parameter count");
    }
    if (!targetMethodObj.getReturnType().equals(Optional.class) && !targetMethodObj.getReturnType().isAssignableFrom(targetType)) {
        throw new IllegalArgumentException("Method " + targetMethodObj.toGenericString() + " does not return the correct type. Expected: " + targetType.getName() + " Found: " + targetMethodObj.getReturnType().getName());
    }
    final Type returnType = Type.getReturnType(targetMethodObj);
    final Class<?> declaringClass = targetMethodObj.getDeclaringClass();
    mv.visitVarInsn(ALOAD, 1);
    mv.visitTypeInsn(CHECKCAST, Type.getInternalName(declaringClass));
    final int op = declaringClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL;
    mv.visitMethodInsn(op, Type.getInternalName(declaringClass), targetMethod, "()" + returnType.getDescriptor(), declaringClass.isInterface());
    final int paramLocal = local++;
    mv.visitVarInsn(returnType.getOpcode(ISTORE), paramLocal);
    if (!targetMethodObj.getReturnType().isPrimitive()) {
        final Label failure = new Label();
        final Label success = new Label();
        if (Optional.class.equals(targetMethodObj.getReturnType()) && !Optional.class.equals(targetType)) {
            // Unwrap the optional
            mv.visitVarInsn(ALOAD, paramLocal);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Optional", "isPresent", "()Z", false);
            mv.visitJumpInsn(IFEQ, failure);
            mv.visitVarInsn(ALOAD, paramLocal);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Optional", "get", "()Ljava/lang/Object;", false);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ASTORE, paramLocal);
        } else {
            mv.visitVarInsn(returnType.getOpcode(ILOAD), paramLocal);
        }
        mv.visitTypeInsn(INSTANCEOF, Type.getInternalName(targetType));
        mv.visitJumpInsn(IFNE, success);
        mv.visitLabel(failure);
        mv.visitInsn(ACONST_NULL);
        mv.visitInsn(ARETURN);
        mv.visitLabel(success);
    }
    return new Tuple<>(local, paramLocal);
}
Also used : Type(org.objectweb.asm.Type) Optional(java.util.Optional) Label(org.objectweb.asm.Label) Method(java.lang.reflect.Method) Tuple(org.spongepowered.api.util.Tuple)

Example 12 with Tuple

use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.

the class GetterFilterSourceDelegate method write.

@Override
public Tuple<Integer, Integer> write(ClassWriter cw, MethodVisitor mv, Method method, Parameter param, int local) {
    Class<?> targetType = param.getType();
    Class<?> eventClass = method.getParameterTypes()[0];
    String targetMethod = this.anno.value();
    Method targetMethodObj = null;
    try {
        targetMethodObj = eventClass.getMethod(targetMethod);
    } catch (NoSuchMethodException e) {
        throw new IllegalArgumentException(String.format("Method %s specified by getter annotation was not found in type %s", targetMethod, eventClass.getName()));
    }
    if (targetMethodObj.getParameterCount() != 0) {
        throw new IllegalArgumentException("Method " + targetMethodObj.toGenericString() + " specified by getter annotation has non-zero parameter count");
    }
    if (!targetMethodObj.getReturnType().equals(Optional.class) && !targetMethodObj.getReturnType().isAssignableFrom(targetType)) {
        throw new IllegalArgumentException("Method " + targetMethodObj.toGenericString() + " does not return the correct type. Expected: " + targetType.getName() + " Found: " + targetMethodObj.getReturnType().getName());
    }
    Type returnType = Type.getReturnType(targetMethodObj);
    Class<?> declaringClass = targetMethodObj.getDeclaringClass();
    mv.visitVarInsn(ALOAD, 1);
    mv.visitTypeInsn(CHECKCAST, Type.getInternalName(declaringClass));
    int op = declaringClass.isInterface() ? INVOKEINTERFACE : INVOKEVIRTUAL;
    mv.visitMethodInsn(op, Type.getInternalName(declaringClass), targetMethod, "()" + returnType.getDescriptor(), declaringClass.isInterface());
    int paramLocal = local++;
    mv.visitVarInsn(returnType.getOpcode(ISTORE), paramLocal);
    if (!targetMethodObj.getReturnType().isPrimitive()) {
        Label failure = new Label();
        Label success = new Label();
        if (Optional.class.equals(targetMethodObj.getReturnType()) && !Optional.class.equals(targetType)) {
            // Unwrap the optional
            mv.visitVarInsn(ALOAD, paramLocal);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Optional", "isPresent", "()Z", false);
            mv.visitJumpInsn(IFEQ, failure);
            mv.visitVarInsn(ALOAD, paramLocal);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Optional", "get", "()Ljava/lang/Object;", false);
            mv.visitInsn(DUP);
            mv.visitVarInsn(ASTORE, paramLocal);
        } else {
            mv.visitVarInsn(returnType.getOpcode(ILOAD), paramLocal);
        }
        mv.visitTypeInsn(INSTANCEOF, Type.getInternalName(targetType));
        mv.visitJumpInsn(IFNE, success);
        mv.visitLabel(failure);
        mv.visitInsn(ACONST_NULL);
        mv.visitInsn(ARETURN);
        mv.visitLabel(success);
    }
    return new Tuple<>(local, paramLocal);
}
Also used : Type(org.objectweb.asm.Type) Optional(java.util.Optional) Label(org.objectweb.asm.Label) Method(java.lang.reflect.Method) Tuple(org.spongepowered.api.util.Tuple)

Example 13 with Tuple

use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.

the class FilterGenerator method generateClass.

public byte[] generateClass(String name, Method method) {
    name = name.replace('.', '/');
    Parameter[] params = method.getParameters();
    ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
    MethodVisitor mv;
    cw.visit(V1_6, ACC_PUBLIC + ACC_FINAL + ACC_SUPER, name, null, "java/lang/Object", new String[] { Type.getInternalName(EventFilter.class) });
    SubtypeFilterDelegate sfilter = null;
    List<FilterDelegate> additional = Lists.newArrayList();
    boolean cancellation = false;
    for (Annotation anno : method.getAnnotations()) {
        Object obj = filterFromAnnotation(anno.annotationType());
        if (obj == null) {
            continue;
        }
        if (obj instanceof SubtypeFilter) {
            if (sfilter != null) {
                throw new IllegalStateException("Cannot have both @Include and @Exclude annotations present at once");
            }
            sfilter = ((SubtypeFilter) obj).getDelegate(anno);
        } else if (obj instanceof EventTypeFilter) {
            EventTypeFilter etf = (EventTypeFilter) obj;
            additional.add(etf.getDelegate(anno));
            if (etf == EventTypeFilter.CANCELLATION) {
                cancellation = true;
            }
        }
    }
    if (!cancellation && Cancellable.class.isAssignableFrom(method.getParameterTypes()[0])) {
        additional.add(new CancellationEventFilterDelegate(Tristate.FALSE));
    }
    if (sfilter != null) {
        sfilter.createFields(cw);
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
        if (sfilter != null) {
            sfilter.writeCtor(name, cw, mv);
        }
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    {
        mv = cw.visitMethod(ACC_PUBLIC, "filter", "(" + Type.getDescriptor(Event.class) + ")[Ljava/lang/Object;", null, null);
        mv.visitCode();
        // index of the next available local variable
        int local = 2;
        if (sfilter != null) {
            local = sfilter.write(name, cw, mv, method, local);
        }
        for (FilterDelegate eventFilter : additional) {
            local = eventFilter.write(name, cw, mv, method, local);
        }
        // local var indices of the parameters values
        int[] plocals = new int[params.length - 1];
        for (int i = 1; i < params.length; i++) {
            Parameter param = params[i];
            ParameterFilterSourceDelegate source = null;
            List<ParameterFilterDelegate> paramFilters = Lists.newArrayList();
            for (Annotation anno : param.getAnnotations()) {
                Object obj = filterFromAnnotation(anno.annotationType());
                if (obj == null) {
                    continue;
                }
                if (obj instanceof ParameterSource) {
                    if (source != null) {
                        throw new IllegalStateException("Cannot have multiple parameter filter source annotations (for " + param.getName() + ")");
                    }
                    source = ((ParameterSource) obj).getDelegate(anno);
                } else if (obj instanceof ParameterFilter) {
                    paramFilters.add(((ParameterFilter) obj).getDelegate(anno));
                }
            }
            if (source == null) {
                throw new IllegalStateException("Cannot have additional parameters filters without a source (for " + param.getName() + ")");
            }
            if (source instanceof AllCauseFilterSourceDelegate && !paramFilters.isEmpty()) {
                // TODO until better handling for filtering arrays is added
                throw new IllegalStateException("Cannot have additional parameters filters without an array source (for " + param.getName() + ")");
            }
            Tuple<Integer, Integer> localState = source.write(cw, mv, method, param, local);
            local = localState.getFirst();
            plocals[i - 1] = localState.getSecond();
            for (ParameterFilterDelegate paramFilter : paramFilters) {
                paramFilter.write(cw, mv, method, param, plocals[i - 1]);
            }
        }
        // create the return array
        if (params.length == 1) {
            mv.visitInsn(ICONST_1);
        } else {
            mv.visitIntInsn(BIPUSH, params.length);
        }
        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        // load the event into the array
        mv.visitInsn(DUP);
        mv.visitInsn(ICONST_0);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitInsn(AASTORE);
        // load all the params into the array
        for (int i = 1; i < params.length; i++) {
            mv.visitInsn(DUP);
            mv.visitIntInsn(BIPUSH, i);
            Type paramType = Type.getType(params[i].getType());
            mv.visitVarInsn(paramType.getOpcode(ILOAD), plocals[i - 1]);
            GeneratorUtils.visitBoxingMethod(mv, paramType);
            mv.visitInsn(AASTORE);
        }
        mv.visitInsn(ARETURN);
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }
    cw.visitEnd();
    byte[] data = cw.toByteArray();
    if (FILTER_DEBUG) {
        File outDir = new File(".sponge.debug.out");
        File outFile = new File(outDir, name + ".class");
        if (!outFile.getParentFile().exists()) {
            outFile.getParentFile().mkdirs();
        }
        try (FileOutputStream out = new FileOutputStream(outFile)) {
            out.write(data);
        } catch (IOException ignored) {
            ignored.printStackTrace();
        }
    }
    return data;
}
Also used : CancellationEventFilterDelegate(org.spongepowered.common.event.filter.delegate.CancellationEventFilterDelegate) Cancellable(org.spongepowered.api.event.Cancellable) ParameterFilterDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate) MethodVisitor(org.objectweb.asm.MethodVisitor) List(java.util.List) SubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.SubtypeFilterDelegate) SupportsDataFilterDelegate(org.spongepowered.common.event.filter.delegate.SupportsDataFilterDelegate) IncludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.IncludeSubtypeFilterDelegate) FilterDelegate(org.spongepowered.common.event.filter.delegate.FilterDelegate) ParameterFilterDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterDelegate) HasDataFilterDelegate(org.spongepowered.common.event.filter.delegate.HasDataFilterDelegate) ExcludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.ExcludeSubtypeFilterDelegate) CancellationEventFilterDelegate(org.spongepowered.common.event.filter.delegate.CancellationEventFilterDelegate) ParameterFilterSourceDelegate(org.spongepowered.common.event.filter.delegate.ParameterFilterSourceDelegate) AllCauseFilterSourceDelegate(org.spongepowered.common.event.filter.delegate.AllCauseFilterSourceDelegate) IOException(java.io.IOException) ClassWriter(org.objectweb.asm.ClassWriter) Annotation(java.lang.annotation.Annotation) SubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.SubtypeFilterDelegate) IncludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.IncludeSubtypeFilterDelegate) ExcludeSubtypeFilterDelegate(org.spongepowered.common.event.filter.delegate.ExcludeSubtypeFilterDelegate) Type(org.objectweb.asm.Type) FileOutputStream(java.io.FileOutputStream) Parameter(java.lang.reflect.Parameter) Event(org.spongepowered.api.event.Event) File(java.io.File) Tuple(org.spongepowered.api.util.Tuple)

Example 14 with Tuple

use of org.spongepowered.api.util.Tuple in project SpongeAPI by SpongePowered.

the class BlockRay method advanceOneBlock.

private boolean advanceOneBlock() {
    if (this.direction.getX() == 0) {
        if (this.direction.getY() == 0) {
            // Only zPlaneT exists
            zIntersect();
        } else if (this.direction.getZ() == 0) {
            // Only yPlaneT exists
            yIntersect();
        } else {
            // yPlaneT and zPlaneT exist
            solveIntersections();
        }
    } else if (this.direction.getY() == 0) {
        if (this.direction.getZ() == 0) {
            // Only xPlaneT exists
            xIntersect();
        } else {
            // xPlaneT and zPlaneT exist
            solveIntersections();
        }
    } else {
        // xPlaneT and yPlaneT exist
        solveIntersections();
    }
    BlockRayHit<E> hit = new BlockRayHit<>(this.extent, this.xCurrent, this.yCurrent, this.zCurrent, this.direction, this.normalCurrent);
    // Make sure we actually have a block
    if (!hit.mapBlock(Extent::containsBlock)) {
        throw new NoSuchElementException("Extent limit reached");
    }
    // Now if using the narrow phase, test on small selection boxes, if needed
    if (this.narrowPhase && !hit.getExtent().getProperty(hit.getBlockPosition(), FullBlockSelectionBoxProperty.class).map(FullBlockSelectionBoxProperty::getValue).orElse(true)) {
        // Get the selection box and perform the narrow phase intersection test
        final Optional<Tuple<Vector3d, Vector3d>> intersection = hit.mapBlock(Extent::getBlockSelectionBox).flatMap(aabb -> aabb.intersects(this.position, this.direction));
        // Create the new narrow hit if there was an intersection
        if (intersection.isPresent()) {
            final Tuple<Vector3d, Vector3d> pair = intersection.get();
            final Vector3d narrowHit = pair.getFirst();
            hit = new BlockRayHit<>(this.extent, narrowHit.getX(), narrowHit.getY(), narrowHit.getZ(), this.direction, pair.getSecond());
        } else {
            // Otherwise return false to attempt the next block
            return false;
        }
    }
    // Check the distance limit if in use
    if (this.distanceLimit >= 0 && this.position.distanceSquared(hit.getPosition()) > this.distanceLimit * this.distanceLimit) {
        throw new NoSuchElementException("Distance limit reached");
    }
    // Check the block end filter
    if (!this.stopFilter.test(hit)) {
        throw new NoSuchElementException("Filter limit reached");
    }
    // Check the block skip filter
    if (!this.skipFilter.test(hit)) {
        return false;
    }
    this.hit = hit;
    return true;
}
Also used : Vector3d(com.flowpowered.math.vector.Vector3d) NoSuchElementException(java.util.NoSuchElementException) Tuple(org.spongepowered.api.util.Tuple)

Example 15 with Tuple

use of org.spongepowered.api.util.Tuple in project SpongeCommon by SpongePowered.

the class VanillaDataStore method serialize.

@Override
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public DataView serialize(DataManipulator dataManipulator, DataView view) {
    for (Map.Entry<Key<?>, Tuple<BiConsumer<DataView, ?>, Function<DataView, Optional<?>>>> entry : this.queriesByKey.entrySet()) {
        final BiConsumer serializer = entry.getValue().first();
        dataManipulator.get((Key) entry.getKey()).ifPresent(value -> serializer.accept(view, value));
    }
    return view;
}
Also used : DataView(org.spongepowered.api.data.persistence.DataView) Optional(java.util.Optional) Map(java.util.Map) Key(org.spongepowered.api.data.Key) Tuple(org.spongepowered.api.util.Tuple) BiConsumer(java.util.function.BiConsumer)

Aggregations

Tuple (org.spongepowered.api.util.Tuple)23 List (java.util.List)9 Map (java.util.Map)8 ArrayList (java.util.ArrayList)7 Optional (java.util.Optional)7 Type (org.objectweb.asm.Type)7 IOException (java.io.IOException)6 Collectors (java.util.stream.Collectors)6 Text (org.spongepowered.api.text.Text)5 Vector3d (com.flowpowered.math.vector.Vector3d)3 Nucleus (io.github.nucleuspowered.nucleus.Nucleus)3 HashMap (java.util.HashMap)3 Set (java.util.Set)3 Label (org.objectweb.asm.Label)3 Lists (com.google.common.collect.Lists)2 Maps (com.google.common.collect.Maps)2 TypeToken (com.google.common.reflect.TypeToken)2 Util (io.github.nucleuspowered.nucleus.Util)2 Reloadable (io.github.nucleuspowered.nucleus.internal.interfaces.Reloadable)2 File (java.io.File)2