@Override
  protected void cleanHook() {
    if (serverHandlerRef != null && serverHandlerRef.isCurrentSet()) {
      writer.copyTo(
          serverHandlerRef.getValue(), serverHandlerRef.getOldValue(), serverHandler.getClass());
      serverHandlerRef.revertValue();

      try {
        if (getNetHandler() != null) {
          // Restore packet listener
          try {
            FieldUtils.writeField(
                netHandlerField, networkManager, serverHandlerRef.getOldValue(), true);
          } catch (IllegalAccessException e) {
            // Oh well
            e.printStackTrace();
          }
        }
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }

      // Prevent the PlayerQuitEvent from being sent twice
      if (hasDisconnected) {
        setDisconnect(serverHandlerRef.getValue(), true);
      }
    }

    serverInjection.revertServerHandler(serverHandler);
  }
  private boolean tryInjectManager() {
    Class<?> serverClass = serverHandler.getClass();

    Enhancer ex = new Enhancer();
    Callback sendPacketCallback =
        new MethodInterceptor() {
          @Override
          public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
              throws Throwable {
            Object packet = args[0];

            if (packet != null) {
              packet = handlePacketSending(packet);

              // A NULL packet indicate cancelling
              if (packet != null) args[0] = packet;
              else return null;
            }

            // Call the method directly
            return proxy.invokeSuper(obj, args);
          };
        };
    Callback noOpCallback = NoOp.INSTANCE;

    // Share callback filter - that way, we avoid generating a new class for
    // every logged in player.
    if (callbackFilter == null) {
      callbackFilter =
          new CallbackFilter() {
            @Override
            public int accept(Method method) {
              if (method.equals(sendPacketMethod)) return 0;
              else return 1;
            }
          };
    }

    ex.setClassLoader(classLoader);
    ex.setSuperclass(serverClass);
    ex.setCallbacks(new Callback[] {sendPacketCallback, noOpCallback});
    ex.setCallbackFilter(callbackFilter);

    // Find the Minecraft NetServerHandler superclass
    Class<?> minecraftSuperClass = getFirstMinecraftSuperClass(serverHandler.getClass());
    ExistingGenerator generator =
        ExistingGenerator.fromObjectFields(serverHandler, minecraftSuperClass);
    DefaultInstances serverInstances = null;

    // Maybe the proxy instance can help?
    Object proxyInstance = getProxyServerHandler();

    // Use the existing server proxy when we create one
    if (proxyInstance != null && proxyInstance != serverHandler) {
      serverInstances =
          DefaultInstances.fromArray(
              generator, ExistingGenerator.fromObjectArray(new Object[] {proxyInstance}));
    } else {
      serverInstances = DefaultInstances.fromArray(generator);
    }

    serverInstances.setNonNull(true);
    serverInstances.setMaximumRecursion(1);

    Object proxyObject = serverInstances.forEnhancer(ex).getDefault(serverClass);

    // Inject it now
    if (proxyObject != null) {
      // This will be done by InjectedServerConnection instead
      // copyTo(serverHandler, proxyObject);

      serverInjection.replaceServerHandler(serverHandler, proxyObject);
      serverHandlerRef.setValue(proxyObject);
      return true;
    } else {
      return false;
    }
  }