Package openperipheral.adapter

Source Code of openperipheral.adapter.PeripheralHandlers

package openperipheral.adapter;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Map;
import java.util.Set;

import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import openmods.Log;
import openmods.utils.ReflectionHelper;
import openperipheral.Config;
import openperipheral.adapter.composed.ClassMethodsList;
import openperipheral.adapter.peripheral.AdapterPeripheral;
import openperipheral.adapter.peripheral.IPeripheralMethodExecutor;
import openperipheral.adapter.peripheral.ProxyAdapterPeripheral;
import openperipheral.api.*;

import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.IPeripheralProvider;

public class PeripheralHandlers implements IPeripheralProvider {
  private static final IPeripheralFactory<TileEntity> NULL_HANDLER = new IPeripheralFactory<TileEntity>() {

    @Override
    public IPeripheral getPeripheral(TileEntity obj, int side) {
      return null;
    }
  };

  private static final IPeripheralFactory<TileEntity> ADAPTER_HANDLER = new SafePeripheralFactory() {
    @Override
    protected IPeripheral createPeripheral(TileEntity tile, int side) {
      return createAdaptedPeripheral(tile);
    }

  };

  private static final IPeripheralFactory<TileEntity> ADAPTER_CACHING_HANDLER = new CachingPeripheralFactory() {
    @Override
    protected IPeripheral createPeripheral(TileEntity tile, int side) {
      return createAdaptedPeripheral(tile);
    }
  };

  private static final IPeripheralFactory<TileEntity> PROVIDER_HANDLER = new SafePeripheralFactory() {
    @Override
    protected IPeripheral createPeripheral(TileEntity tile, int side) {
      return (tile instanceof ICustomPeripheralProvider)? ((ICustomPeripheralProvider)tile).createPeripheral(side) : null;
    }
  };

  private static final IPeripheralFactory<TileEntity> PROVIDER_CACHING_HANDLER = new CachingPeripheralFactory() {
    @Override
    protected IPeripheral createPeripheral(TileEntity tile, int side) {
      return (tile instanceof ICustomPeripheralProvider)? ((ICustomPeripheralProvider)tile).createPeripheral(side) : null;
    }
  };

  private static final Map<Class<? extends TileEntity>, IPeripheralFactory<TileEntity>> adaptedClasses = Maps.newHashMap();

  private static final Set<String> blacklist = ImmutableSet.copyOf(Config.teBlacklist);

  private static IPeripheralFactory<TileEntity> findFactoryForClass(Class<? extends TileEntity> teClass) {
    if (IPeripheral.class.isAssignableFrom(teClass)) return NULL_HANDLER;

    if (ICustomPeripheralProvider.class.isAssignableFrom(teClass)) {
      if (teClass.isAnnotationPresent(Volatile.class)) {
        Log.trace("Adding non-caching provider handler for %s", teClass);
        return PROVIDER_HANDLER;
      } else {
        Log.trace("Adding caching provider handler for %s", teClass);
        return PROVIDER_CACHING_HANDLER;
      }
    }

    if (isIgnored(teClass)) return NULL_HANDLER;

    for (Class<?> adaptableClass : AdapterManager.peripherals.getAllAdaptableClasses()) {
      if (adaptableClass.isAssignableFrom(teClass)) {
        if (teClass.isAnnotationPresent(Volatile.class)) {
          Log.trace("Adding non-caching adapter handler for %s", teClass);
          return ADAPTER_HANDLER;
        } else {
          Log.trace("Adding caching adapter handler for %s", teClass);
          return ADAPTER_CACHING_HANDLER;
        }
      }
    }

    return NULL_HANDLER;
  }

  private static IPeripheralFactory<TileEntity> getFactoryForClass(Class<? extends TileEntity> teClass) {
    IPeripheralFactory<TileEntity> factory = adaptedClasses.get(teClass);

    if (factory == null) {
      factory = findFactoryForClass(teClass);
      adaptedClasses.put(teClass, factory);
    }

    return factory;
  }

  protected static boolean isIgnored(Class<? extends TileEntity> teClass) {
    final String teClassName = teClass.getName();
    if (blacklist.contains(teClassName) || blacklist.contains(teClassName.toLowerCase())) return true;

    if (teClass.isAnnotationPresent(Ignore.class)) return true;

    try {
      teClass.getField("OPENPERIPHERAL_IGNORE");
      return true;
    } catch (NoSuchFieldException e) {
      // uff, we are not ignored
    } catch (Throwable t) {
      Log.warn(t, "Class %s doesn't cooperate", teClass);
    }

    return false;
  }

  public static IPeripheral createAdaptedPeripheralSafe(Object target) {
    try {
      return createAdaptedPeripheral(target);
    } catch (Throwable t) {
      Log.warn(t, "Failed to create peripheral for turtle");
      return SafePeripheralFactory.PLACEHOLDER;
    }
  }

  public static IPeripheral createAdaptedPeripheral(Object target) {
    Class<?> targetClass = target.getClass();
    ClassMethodsList<IPeripheralMethodExecutor> methods = AdapterManager.peripherals.getAdapterClass(targetClass);

    ProxyInterfaces proxyAnn = targetClass.getAnnotation(ProxyInterfaces.class);
    if (proxyAnn == null) return new AdapterPeripheral(methods, target);

    Set<Class<?>> implemented = ReflectionHelper.getAllInterfaces(targetClass);
    Set<Class<?>> blacklist = ImmutableSet.copyOf(proxyAnn.exclude());
    Set<Class<?>> proxied = Sets.difference(implemented, blacklist);

    if (proxied.isEmpty()) return new AdapterPeripheral(methods, target);

    Set<Class<?>> allImplemented = Sets.newHashSet(proxied);
    allImplemented.add(IPeripheral.class);

    InvocationHandler handler = new ProxyAdapterPeripheral(methods, target);

    Class<?>[] interfaces = allImplemented.toArray(new Class<?>[allImplemented.size()]);

    return (IPeripheral)Proxy.newProxyInstance(targetClass.getClassLoader(), interfaces, handler);
  }

  @Override
  public IPeripheral getPeripheral(World world, int x, int y, int z, int side) {
    TileEntity te = world.getTileEntity(x, y, z);
    if (te == null) return null;

    IPeripheralFactory<TileEntity> factory = getFactoryForClass(te.getClass());

    return factory.getPeripheral(te, side);
  }
}
TOP

Related Classes of openperipheral.adapter.PeripheralHandlers

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.