Package l2p.extensions.scripts

Source Code of l2p.extensions.scripts.ScriptManager$ScriptClassAndMethod

package l2p.extensions.scripts;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javolution.util.FastList;
import l2p.Config;
import l2p.Server;
import l2p.extensions.scripts.Compiler.MemoryClassLoader;
import l2p.extensions.scripts.jarloader.JarClassLoader;
import l2p.gameserver.GameServer;
import l2p.gameserver.handler.AdminCommandHandler;
import l2p.gameserver.instancemanager.QuestManager;
import l2p.gameserver.model.quest.Quest;
import l2p.util.GArray;

public class ScriptManager
{
  private static final Logger _log = Logger.getLogger(ScriptManager.class.getName());
  public static boolean JAR;
  private static ScriptManager _instance;
  public static boolean loading;
  private final HashMap<String, Script> _classes = new HashMap<String, Script>();
  public static final HashMap<Integer, GArray<ScriptClassAndMethod>> itemHandlers = new HashMap<Integer, GArray<ScriptClassAndMethod>>();
  public static final HashMap<Integer, GArray<ScriptClassAndMethod>> dialogAppends = new HashMap<Integer, GArray<ScriptClassAndMethod>>();
  public static final HashMap<String, ScriptClassAndMethod> onAction = new HashMap<String, ScriptClassAndMethod>();
  public static final HashMap<String, ScriptClassAndMethod> onActionShift = new HashMap<String, ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onPlayerExit = new GArray<ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onPlayerEnter = new GArray<ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onReloadMultiSell = new GArray<ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onDie = new GArray<ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onEscape = new GArray<ScriptClassAndMethod>();
  public static final GArray<ScriptClassAndMethod> onDisconnect = new GArray<ScriptClassAndMethod>();

  public static ScriptManager getInstance()
  {
    if(_instance == null)
    {
      new ScriptManager();
    }
    return _instance;
  }

  public ScriptManager()
  {
    _instance = this;
    load(false);
  }

  public boolean reload()
  {
    loading = true;
    for(ScriptObject go : GameServer.scriptsObjects.values())
    {
      try
      {
        go.invokeMethod("onReload");
      }
      catch(Exception f)
      {
        f.printStackTrace();
      }
    }
    GameServer.scriptsObjects.clear();
    boolean error = load(true);
    callOnLoad();
    loading = false;
    return error;
  }

  public void shutdown()
  {
    for(ScriptObject go : GameServer.scriptsObjects.values())
    {
      try
      {
        go.invokeMethod("onShutdown");
      }
      catch(Exception f)
      {
        f.printStackTrace();
      }
    }
    GameServer.scriptsObjects.clear();
  }
 
  private void registerCoreScripts()
  {
    try
    {
      for (Class<?> c : getClasses("l2p.gameserver.scripts"))
      {
        if (!Modifier.isAbstract(c.getModifiers()))
          _classes.put(c.getName(), new Script(c));
      }
    }
    catch (Exception e)
    {
      _log.log(Level.WARNING, "Error parsing core script", e);
    }
  }
 
  private static FastList<Class<?>> getClasses(String packageName) throws ClassNotFoundException, IOException
  {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    assert classLoader != null;
    String path = packageName.replace('.', '/');
    Enumeration<URL> resources = classLoader.getResources(path);
    FastList<File> dirs = new FastList<File>();
    while (resources.hasMoreElements())
    {
      URL resource = resources.nextElement();
      String fileName = resource.getFile();
      String fileNameDecoded = URLDecoder.decode(fileName, "UTF-8");
      dirs.add(new File(fileNameDecoded));
    }
    FastList<Class<?>> classes = new FastList<Class<?>>();
    for (File directory : dirs)
    {
      classes.addAll(findClasses(directory, packageName));
    }
    return classes;
  }
 
  private static FastList<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException
  {
    FastList<Class<?>> classes = new FastList<Class<?>>();
    if (!directory.exists())
    {
      return classes;
    }
    File[] files = directory.listFiles();
    for (File file : files)
    {
      String fileName = file.getName();
      if (file.isDirectory())
      {
        assert !fileName.contains(".");
        classes.addAll(findClasses(file, packageName + "." + fileName));
      }
      else if (fileName.endsWith(".class") && !fileName.contains("$"))
      {
        Class<?> c;
        try
        {
          c = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6));
        }
        catch (ExceptionInInitializerError e)
        {
          // happen, for example, in classes, which depend on
          // Spring to inject some beans, and which fail,
          // if dependency is not fulfilled
          c = Class.forName(packageName + '.' + fileName.substring(0, fileName.length() - 6), false, Thread.currentThread().getContextClassLoader());
        }
        classes.add(c);
      }
    }
    return classes;
  }

  private synchronized boolean load(boolean reload)
  {
    _log.info("Scripts loading...");
    boolean error = false;
   
    registerCoreScripts();
   
    Class<?> c;
    JAR = new File("./scripts.jar").exists();
    if(JAR)
    {
      JarClassLoader jcl;
      try
      {
        jcl = new JarClassLoader("./scripts.jar");
        for(String name : jcl.getClassNames())
        {
          if(!name.contains(".class"))
          {
            continue;
          }
          if(name.contains("$"))
          {
            continue;
          } // пропускаем вложенные классы
          name = name.replace(".class", "").replace("/", ".");
          c = jcl.loadClass(name);
          Script s = new Script(c);
          _classes.put(c.getName(), s);
        }
      }
      catch(Exception e)
      {
        error = true;
        e.printStackTrace();
      }
    }
    else
    {
      GArray<File> scriptFiles = new GArray<File>();
      parseClasses(new File(Config.DATAPACK_ROOT, "data/scripts"), scriptFiles);
      if(Compiler.getInstance().compile(scriptFiles, System.out))
      {
        MemoryClassLoader classLoader = Compiler.getInstance().classLoader; //TODO
        for(String name : classLoader.byteCodes.keySet())
        {
          if(name.contains("$"))
          {
            continue;
          } // пропускаем вложенные классы
          try
          {
            c = classLoader.loadClass(name);
            Script s = new Script(c);
            _classes.put(name, s);
          }
          catch(ClassNotFoundException e)
          {
            _log.warning("Can't load script class:" + e.getMessage());
            error = true;
          }
        }
        Compiler.getInstance().classLoader = null;
      }
      else
      {
        _log.warning("Can't compile scripts!");
        error = true;
      }
    }
    if(error)
    {
      _log.info("Scripts loaded with errors. Loaded " + _classes.size() + " classes.");
      if(!reload)
      {
        Server.halt(0, "Scripts loaded with errors. Loaded " + _classes.size() + " classes.");
      }
    }
    else
    {
      _log.info("Scripts successfully loaded. Loaded " + _classes.size() + " classes.");
    }
    return error;
  }

  public void callOnLoad()
  {
    loadAndInitHandlers();
    AdminCommandHandler.getInstance().registerAdminCommandHandler(new AdminScripts());
  }

  private void loadAndInitHandlers()
  {
    itemHandlers.clear();
    dialogAppends.clear();
    onAction.clear();
    onActionShift.clear();
    onPlayerExit.clear();
    onPlayerEnter.clear();
    onReloadMultiSell.clear();
    onDie.clear();
    onEscape.clear();
    onDisconnect.clear();
    for(Script _class : _classes.values())
    {
      loadAndInitHandlersForClass(_class);
    }
  }

  private void loadAndInitHandlersForClass(Script _class)
  {
    try
    {
      if(!GameServer.scriptsObjects.containsKey(_class.getName()))
      {
        ScriptObject go = _class.newInstance();
        GameServer.scriptsObjects.put(_class.getName(), go);
        go.invokeMethod("onLoad");
      }
      for(Method method : _class.getRawClass().getMethods())
      {
        if(method.getName().equals("onLoad"))
        {
          if(Modifier.isStatic(method.getModifiers()))
          {
            method.invoke(null);
          }
        }
        else if(method.getName().contains("ItemHandler_"))
        {
          Integer id = Integer.parseInt(method.getName().substring(12));
          GArray<ScriptClassAndMethod> handlers = itemHandlers.get(id);
          if(handlers == null)
          {
            handlers = new GArray<ScriptClassAndMethod>();
            itemHandlers.put(id, handlers);
          }
          handlers.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().contains("DialogAppend_"))
        {
          Integer id = Integer.parseInt(method.getName().substring(13));
          GArray<ScriptClassAndMethod> handlers = dialogAppends.get(id);
          if(handlers == null)
          {
            handlers = new GArray<ScriptClassAndMethod>();
            dialogAppends.put(id, handlers);
          }
          handlers.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().contains("OnAction_"))
        {
          String name = method.getName().substring(9);
          if(onAction.containsKey(name))
          {
            onAction.remove(name);
          }
          onAction.put(name, new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().contains("OnActionShift_"))
        {
          String name = method.getName().substring(14);
          if(onActionShift.containsKey(name))
          {
            onActionShift.remove(name);
          }
          onActionShift.put(name, new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("OnPlayerExit"))
        {
          onPlayerExit.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("OnPlayerEnter"))
        {
          onPlayerEnter.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("OnReloadMultiSell"))
        {
          onReloadMultiSell.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("OnDie"))
        {
          onDie.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("OnEscape"))
        {
          onEscape.add(new ScriptClassAndMethod(_class, method));
        }
        else if(method.getName().equals("onDisconnect"))
        {
          onDisconnect.add(new ScriptClassAndMethod(_class, method));
        }
      }
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  private void clearHandlersForClass(Script _class)
  {
    try
    {
      for(GArray<ScriptClassAndMethod> entry : itemHandlers.values())
      {
        GArray<ScriptClassAndMethod> toRemove = new GArray<ScriptClassAndMethod>();
        for(ScriptClassAndMethod sc : entry)
        {
          if(sc.scriptClass == _class)
          {
            toRemove.add(sc);
          }
        }
        for(ScriptClassAndMethod sc : toRemove)
        {
          entry.remove(sc);
        }
      }
      for(GArray<ScriptClassAndMethod> entry : dialogAppends.values())
      {
        GArray<ScriptClassAndMethod> toRemove = new GArray<ScriptClassAndMethod>();
        for(ScriptClassAndMethod sc : entry)
        {
          if(sc.scriptClass == _class)
          {
            toRemove.add(sc);
          }
        }
        for(ScriptClassAndMethod sc : toRemove)
        {
          entry.remove(sc);
        }
      }
      GArray<String> toRemove = new GArray<String>();
      for(Map.Entry<String, ScriptClassAndMethod> entry : onAction.entrySet())
      {
        if(entry.getValue().scriptClass == _class)
        {
          toRemove.add(entry.getKey());
        }
      }
      for(String key : toRemove)
      {
        onAction.remove(key);
      }
      toRemove = new GArray<String>();
      for(Map.Entry<String, ScriptClassAndMethod> entry : onActionShift.entrySet())
      {
        if(entry.getValue().scriptClass == _class)
        {
          toRemove.add(entry.getKey());
        }
      }
      for(String key : toRemove)
      {
        onActionShift.remove(key);
      }
      GArray<ScriptClassAndMethod> toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onPlayerExit)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onPlayerExit.remove(sc);
      }
      toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onPlayerEnter)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onPlayerEnter.remove(sc);
      }
      toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onReloadMultiSell)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onReloadMultiSell.remove(sc);
      }
      toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onDie)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onDie.remove(sc);
      }
      toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onEscape)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onEscape.remove(sc);
      }
      toRemove2 = new GArray<ScriptClassAndMethod>();
      for(ScriptClassAndMethod sc : onDisconnect)
      {
        if(sc.scriptClass == _class)
        {
          toRemove2.add(sc);
        }
      }
      for(ScriptClassAndMethod sc : toRemove2)
      {
        onDisconnect.remove(sc);
      }
    }
    catch(Exception e)
    {
      e.printStackTrace();
    }
  }

  public boolean reloadClass(String name)
  {
    File f = new File(Config.DATAPACK_ROOT, "data/scripts/" + name.replace(".", "/") + ".java");
    if(f.exists() && f.isFile())
    {
      return reloadClassByName(name.replace("/", "."));
    }
    f = new File(Config.DATAPACK_ROOT, "data/scripts/" + name.replace(".", "/"));
    if(f.exists() && f.isDirectory())
    {
      return reloadClassByPath(f);
    }
    _log.warning("Can't find class or package by path: " + name);
    return true;
  }

  private boolean reloadClassByPath(File f)
  {
    GArray<File> scriptFiles = new GArray<File>();
    parseClasses(f, scriptFiles);
    if(Compiler.getInstance().compile(scriptFiles, System.out))
    {
      MemoryClassLoader classLoader = Compiler.getInstance().classLoader;
      Class<?> c;
      for(String name : classLoader.byteCodes.keySet())
      {
        if(name.contains("$"))
        {
          continue;
        } // пропускаем вложенные классы
        try
        {
          c = classLoader.loadClass(name);
          Script s = new Script(c);
          ScriptObject oldSo = GameServer.scriptsObjects.remove(name);
          if(oldSo != null)
          {
            oldSo.invokeMethod("onReload");
          }
          Script oldS = _classes.remove(name);
          if(oldS != null)
          {
            clearHandlersForClass(oldS);
          }
          _classes.put(name, s);
          loadAndInitHandlersForClass(s);
        }
        catch(ClassNotFoundException e)
        {
          _log.warning("Can't load script class:" + e.getMessage());
          return true;
        }
      }
      Compiler.getInstance().classLoader = null;
    }
    else
    {
      _log.warning("Can't recompile scripts: " + f.getPath());
      return true;
    }
    return false;
  }

  private boolean reloadClassByName(String name)
  {
    if(Compiler.getInstance().compile(new File(Config.DATAPACK_ROOT, "data/scripts/" + name.replace(".", "/") + ".java"), System.out))
    {
      MemoryClassLoader classLoader = Compiler.getInstance().classLoader;
      try
      {
        Class<?> c = classLoader.loadClass(name);
        Script s = new Script(c);
        ScriptObject oldSo = GameServer.scriptsObjects.remove(name);
        if(oldSo != null)
        {
          oldSo.invokeMethod("onReload");
        }
        Script oldS = _classes.remove(name);
        if(oldS != null)
        {
          clearHandlersForClass(oldS);
        }
        _classes.put(name, s);
        loadAndInitHandlersForClass(s);
        return false;
      }
      catch(ClassNotFoundException e)
      {
        _log.warning("Can't load script class:" + e.getMessage());
      }
      Compiler.getInstance().classLoader = null;
    }
    else
    {
      _log.warning("Can't recompile script: " + name);
    }
    return true;
  }

  public boolean reloadQuest(String name)
  {
    if(Config.DONTLOADQUEST)
    {
      return true;
    }
    Quest q = QuestManager.getQuest(name);
    File f;
    if(q != null)
    {
      String path = q.getClass().getPackage().getName().replace(".", "/");
      f = new File(Config.DATAPACK_ROOT, "data/scripts/" + path + "/");
      if(f.isDirectory())
      {
        return reloadClassByPath(f);
      }
    }
    q = QuestManager.getQuest(Integer.parseInt(name));
    if(q != null)
    {
      String path = q.getClass().getPackage().getName().replace(".", "/");
      f = new File(Config.DATAPACK_ROOT, "data/scripts/" + path + "/");
      if(f.isDirectory())
      {
        return reloadClassByPath(f);
      }
    }
    return reloadClassByPath(new File(Config.DATAPACK_ROOT, "data/scripts/quests/" + name + "/"));
  }

  private void parseClasses(File f, GArray<File> list)
  {
    for(File z : f.listFiles())
    {
      if(z.isDirectory())
      {
        if(z.getName().equals(".svn"))
        {
          continue;
        }
        if(Config.DONTLOADQUEST && z.getName().equals("quests") && z.getParentFile().getName().equals("scripts"))
        {
          continue;
        }
        parseClasses(z, list);
      }
      else
      {
        if(!z.getName().contains(".java"))
        {
          continue;
        }
        list.add(z);
      }
    }
  }

  public HashMap<String, Script> getClasses()
  {
    return _classes;
  }

  public static class ScriptClassAndMethod
  {
    public final Script scriptClass;
    public final Method method;

    public ScriptClassAndMethod(Script _scriptClass, Method _method)
    {
      scriptClass = _scriptClass;
      method = _method;
    }
  }
}
TOP

Related Classes of l2p.extensions.scripts.ScriptManager$ScriptClassAndMethod

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.