Search in sources :

Example 11 with ComputerMethod

use of mekanism.common.integration.computer.annotation.ComputerMethod in project Mekanism by mekanism.

the class ComputerMethodMapper method collectScanData.

@Override
protected void collectScanData(Map<String, Class<?>> classNameCache, Map<Class<?>, List<AnnotationData>> knownClasses) {
    Type wrappingType = Type.getType(WrappingComputerMethod.class);
    Map<Class<?>, List<WrappingMethodHelper>> cachedWrappers = new Object2ObjectOpenHashMap<>();
    Map<Class<?>, List<MethodDetails>> rawMethodDetails = new Object2ObjectOpenHashMap<>();
    for (Entry<Class<?>, List<AnnotationData>> entry : knownClasses.entrySet()) {
        Class<?> annotatedClass = entry.getKey();
        List<MethodDetails> methodDetails = new ArrayList<>();
        rawMethodDetails.put(annotatedClass, methodDetails);
        for (AnnotationData data : entry.getValue()) {
            if (getAnnotationValue(data, "requiredMods", Collections.<String>emptyList()).stream().anyMatch(s -> !ModList.get().isLoaded(s))) {
                // If the required mods are not loaded, skip this annotation as the restrictions are not met
                continue;
            }
            if (data.getTargetType() == ElementType.FIELD) {
                // Synthetic Computer Method(s) need to be generated for the field
                String fieldName = data.getMemberName();
                Field field = getField(annotatedClass, fieldName);
                if (field == null) {
                    continue;
                }
                if (data.getAnnotationType().equals(wrappingType)) {
                    // Wrapping computer method
                    try {
                        MethodHandle methodHandle = LOOKUP.unreflectGetter(field);
                        wrapMethodHandle(classNameCache, methodHandle, data, methodDetails, cachedWrappers, annotatedClass, fieldName);
                    } catch (IllegalAccessException e) {
                        Mekanism.logger.error("Failed to create getter for field '{}' in class '{}'.", fieldName, annotatedClass.getSimpleName());
                    }
                } else {
                    String getterName = getAnnotationValue(data, "getter", "");
                    String setterName = getAnnotationValue(data, "setter", "");
                    if (getterName.isEmpty() && setterName.isEmpty()) {
                        Mekanism.logger.error("Field: '{}' in class '{}' is annotated to generate a computer method but does not specify a getter or setter.", fieldName, annotatedClass.getSimpleName());
                    } else {
                        MethodRestriction restriction = getAnnotationValue(data, "restriction", MethodRestriction.NONE);
                        createSyntheticMethod(methodDetails, annotatedClass, field, fieldName, getterName, true, restriction, getAnnotationValue(data, "threadSafeGetter", false));
                        createSyntheticMethod(methodDetails, annotatedClass, field, fieldName, setterName, false, restriction, getAnnotationValue(data, "threadSafeSetter", false));
                    }
                }
            } else {
                // data.getTargetType() == ElementType.METHOD
                // Note: Signature is methodName followed by the method descriptor
                // For example this method is: collectScanDataUnsafe(Ljava/util/Map;Ljava/util/Map;)V
                String methodSignature = data.getMemberName();
                int descriptorStart = methodSignature.indexOf('(');
                if (descriptorStart == -1) {
                    Mekanism.logger.error("Method '{}' in class '{}' does not have a method descriptor.", methodSignature, annotatedClass.getSimpleName());
                } else {
                    String methodDescriptor = methodSignature.substring(descriptorStart);
                    String methodName = methodSignature.substring(0, descriptorStart);
                    Method method = getMethod(annotatedClass, methodName, methodDescriptor);
                    if (method != null) {
                        // Note: We need to grab the method handle via the method so that we can access private and protected methods properly
                        MethodHandle methodHandle;
                        try {
                            methodHandle = LOOKUP.unreflect(method);
                        } catch (IllegalAccessException e) {
                            Mekanism.logger.error("Failed to retrieve method handle for method '{}' in class '{}'.", methodName, annotatedClass.getSimpleName());
                            continue;
                        }
                        if (data.getAnnotationType().equals(wrappingType)) {
                            // Wrapping computer method
                            wrapMethodHandle(classNameCache, methodHandle, data, methodDetails, cachedWrappers, annotatedClass, methodName);
                        } else {
                            // ComputerMethod
                            // See if there is a name override defined for the method, or fallback
                            String methodNameOverride = getAnnotationValue(data, "nameOverride", methodName, name -> {
                                if (name.isEmpty()) {
                                    Mekanism.logger.warn("Specified name override for method '{}' in class '{}' is explicitly set to empty and " + "will not be used.", methodName, annotatedClass.getSimpleName());
                                } else if (validMethodName(name)) {
                                    return true;
                                } else {
                                    Mekanism.logger.error("Specified name override '{}' for method '{}' in class '{}' is not a valid method name and " + "will not be used.", name, methodName, annotatedClass.getSimpleName());
                                }
                                return false;
                            });
                            methodDetails.add(new MethodDetails(methodNameOverride, methodHandle, getAnnotationValue(data, "restriction", MethodRestriction.NONE), getAnnotationValue(data, "threadSafe", false)));
                        }
                    }
                }
            }
        }
    }
    List<ClassBasedInfo<MethodDetails>> methodDetails = combineWithParents(rawMethodDetails);
    for (ClassBasedInfo<MethodDetails> details : methodDetails) {
        // Linked map to preserve order
        Map<String, List<MethodHandleInfo>> cache = new LinkedHashMap<>();
        details.infoList.sort(Comparator.comparing(info -> info.methodName));
        for (MethodDetails handle : details.infoList) {
            // Add the method handle to the list of methods with that method name for our computer handler
            // Note: we construct the list with an initial capacity of one, as that is likely how many we
            // actually have per methodName, we just support using a list
            cache.computeIfAbsent(handle.methodName, methodName -> new ArrayList<>(1)).add(new MethodHandleInfo(handle.method, handle.restriction, handle.threadSafe));
        }
        namedMethodHandleCache.put(details.clazz, cache);
    }
}
Also used : MethodHandle(java.lang.invoke.MethodHandle) Arrays(java.util.Arrays) WrappingComputerMethodIndex(mekanism.common.integration.computer.annotation.WrappingComputerMethod.WrappingComputerMethodIndex) WrappingComputerMethod(mekanism.common.integration.computer.annotation.WrappingComputerMethod) Type(org.objectweb.asm.Type) ThreadAwareMethodHandle(mekanism.common.integration.computer.BoundComputerMethod.ThreadAwareMethodHandle) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) Map(java.util.Map) IMekanismStrictEnergyHandler(mekanism.api.energy.IMekanismStrictEnergyHandler) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod) TileEntityMultiblock(mekanism.common.tile.prefab.TileEntityMultiblock) Method(java.lang.reflect.Method) Nonnull(javax.annotation.Nonnull) Nullable(javax.annotation.Nullable) Mekanism(mekanism.common.Mekanism) ITileRedstone(mekanism.common.tile.interfaces.ITileRedstone) EnumMap(java.util.EnumMap) Predicate(java.util.function.Predicate) MethodHandles(java.lang.invoke.MethodHandles) SyntheticComputerMethod(mekanism.common.integration.computer.annotation.SyntheticComputerMethod) AnnotationData(net.minecraftforge.forgespi.language.ModFileScanData.AnnotationData) ModList(net.minecraftforge.fml.ModList) IComparatorSupport(mekanism.common.tile.interfaces.IComparatorSupport) ElementType(java.lang.annotation.ElementType) Field(java.lang.reflect.Field) ITileDirectional(mekanism.common.tile.interfaces.ITileDirectional) List(java.util.List) Entry(java.util.Map.Entry) Comparator(java.util.Comparator) Collections(java.util.Collections) BaseAnnotationScanner(mekanism.common.lib.MekAnnotationScanner.BaseAnnotationScanner) AnnotationData(net.minecraftforge.forgespi.language.ModFileScanData.AnnotationData) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Field(java.lang.reflect.Field) Object2ObjectOpenHashMap(it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap) ArrayList(java.util.ArrayList) ModList(net.minecraftforge.fml.ModList) List(java.util.List) WrappingComputerMethod(mekanism.common.integration.computer.annotation.WrappingComputerMethod) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod) Method(java.lang.reflect.Method) SyntheticComputerMethod(mekanism.common.integration.computer.annotation.SyntheticComputerMethod) Type(org.objectweb.asm.Type) ElementType(java.lang.annotation.ElementType) MethodHandle(java.lang.invoke.MethodHandle) ThreadAwareMethodHandle(mekanism.common.integration.computer.BoundComputerMethod.ThreadAwareMethodHandle)

Example 12 with ComputerMethod

use of mekanism.common.integration.computer.annotation.ComputerMethod in project Mekanism by mekanism.

the class TileEntityQIORedstoneAdapter method setTargetItem.

@ComputerMethod
private void setTargetItem(ResourceLocation itemName) throws ComputerException {
    validateSecurityIsPublic();
    Item item = ForgeRegistries.ITEMS.getValue(itemName);
    if (item == null || item == Items.AIR) {
        throw new ComputerException("Target item '%s' could not be found. If you are trying to clear it consider using clearTargetItem instead.", itemName);
    }
    handleStackChange(new ItemStack(item));
}
Also used : Item(net.minecraft.item.Item) HashedItem(mekanism.common.lib.inventory.HashedItem) ItemStack(net.minecraft.item.ItemStack) SyncableItemStack(mekanism.common.inventory.container.sync.SyncableItemStack) ComputerException(mekanism.common.integration.computer.ComputerException) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod)

Example 13 with ComputerMethod

use of mekanism.common.integration.computer.annotation.ComputerMethod in project Mekanism by mekanism.

the class TileEntityDiversionTransporter method decrementMode.

@ComputerMethod
private void decrementMode(Direction side) {
    DiversionTransporter transmitter = getTransmitter();
    transmitter.updateMode(side, transmitter.modes[side.ordinal()].getPrevious());
}
Also used : DiversionTransporter(mekanism.common.content.network.transmitter.DiversionTransporter) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod)

Example 14 with ComputerMethod

use of mekanism.common.integration.computer.annotation.ComputerMethod in project Mekanism by mekanism.

the class TileEntityQIOComponent method setFrequency.

@ComputerMethod
private void setFrequency(String name) throws ComputerException {
    validateSecurityIsPublic();
    QIOFrequency frequency = FrequencyType.QIO.getManagerWrapper().getPublicManager().getFrequency(name);
    if (frequency == null) {
        throw new ComputerException("No public QIO frequency with name '%s' found.", name);
    }
    setFrequency(FrequencyType.QIO, frequency.getIdentity(), getOwnerUUID());
}
Also used : QIOFrequency(mekanism.common.content.qio.QIOFrequency) ComputerException(mekanism.common.integration.computer.ComputerException) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod)

Example 15 with ComputerMethod

use of mekanism.common.integration.computer.annotation.ComputerMethod in project Mekanism by mekanism.

the class TileEntityQIOComponent method incrementFrequencyColor.

@ComputerMethod
private void incrementFrequencyColor() throws ComputerException {
    validateSecurityIsPublic();
    QIOFrequency frequency = computerGetFrequency();
    frequency.setColor(frequency.getColor().getNext());
}
Also used : QIOFrequency(mekanism.common.content.qio.QIOFrequency) ComputerMethod(mekanism.common.integration.computer.annotation.ComputerMethod)

Aggregations

ComputerMethod (mekanism.common.integration.computer.annotation.ComputerMethod)23 ComputerException (mekanism.common.integration.computer.ComputerException)10 WrappingComputerMethod (mekanism.common.integration.computer.annotation.WrappingComputerMethod)9 QIOFrequency (mekanism.common.content.qio.QIOFrequency)4 TeleporterFrequency (mekanism.common.content.teleporter.TeleporterFrequency)4 ConfigInfo (mekanism.common.tile.component.config.ConfigInfo)4 SyntheticComputerMethod (mekanism.common.integration.computer.annotation.SyntheticComputerMethod)3 FrequencyIdentity (mekanism.common.lib.frequency.Frequency.FrequencyIdentity)3 Nonnull (javax.annotation.Nonnull)2 FloatingLong (mekanism.api.math.FloatingLong)2 InventoryFrequency (mekanism.common.content.entangloporter.InventoryFrequency)2 DiversionTransporter (mekanism.common.content.network.transmitter.DiversionTransporter)2 BoundComputerMethod (mekanism.common.integration.computer.BoundComputerMethod)2 SyncableItemStack (mekanism.common.inventory.container.sync.SyncableItemStack)2 ItemStack (net.minecraft.item.ItemStack)2 Object2ObjectOpenHashMap (it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap)1 ElementType (java.lang.annotation.ElementType)1 MethodHandle (java.lang.invoke.MethodHandle)1 MethodHandles (java.lang.invoke.MethodHandles)1 Field (java.lang.reflect.Field)1