Package ch.njol.skript

Source Code of ch.njol.skript.ScriptLoader

/*
*   This file is part of Skript.
*
*  Skript is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  Skript is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with Skript.  If not, see <http://www.gnu.org/licenses/>.
*
*
* Copyright 2011-2014 Peter Güttinger
*
*/

package ch.njol.skript;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;

import org.bukkit.event.Event;
import org.eclipse.jdt.annotation.Nullable;

import ch.njol.skript.aliases.Aliases;
import ch.njol.skript.aliases.ItemType;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.command.CommandEvent;
import ch.njol.skript.command.Commands;
import ch.njol.skript.command.ScriptCommand;
import ch.njol.skript.config.Config;
import ch.njol.skript.config.EntryNode;
import ch.njol.skript.config.Node;
import ch.njol.skript.config.SectionNode;
import ch.njol.skript.config.SimpleNode;
import ch.njol.skript.effects.Delay;
import ch.njol.skript.lang.Condition;
import ch.njol.skript.lang.Conditional;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.Loop;
import ch.njol.skript.lang.ParseContext;
import ch.njol.skript.lang.SelfRegisteringSkriptEvent;
import ch.njol.skript.lang.SkriptEvent;
import ch.njol.skript.lang.SkriptEventInfo;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.Statement;
import ch.njol.skript.lang.Trigger;
import ch.njol.skript.lang.TriggerItem;
import ch.njol.skript.lang.TriggerSection;
import ch.njol.skript.lang.While;
import ch.njol.skript.lang.function.Function;
import ch.njol.skript.lang.function.FunctionEvent;
import ch.njol.skript.lang.function.Functions;
import ch.njol.skript.localization.Language;
import ch.njol.skript.localization.Message;
import ch.njol.skript.localization.PluralizingArgsMessage;
import ch.njol.skript.log.CountingLogHandler;
import ch.njol.skript.log.ErrorDescLogHandler;
import ch.njol.skript.log.ParseLogHandler;
import ch.njol.skript.log.RetainingLogHandler;
import ch.njol.skript.log.SkriptLogger;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.registrations.Converters;
import ch.njol.skript.util.Date;
import ch.njol.skript.util.ExceptionUtils;
import ch.njol.skript.variables.Variables;
import ch.njol.util.Callback;
import ch.njol.util.Kleenean;
import ch.njol.util.NonNullPair;
import ch.njol.util.StringUtils;
import ch.njol.util.coll.CollectionUtils;

/**
* @author Peter Güttinger
*/
final public class ScriptLoader {
  private ScriptLoader() {}
 
  private final static Message m_no_errors = new Message("skript.no errors"),
      m_no_scripts = new Message("skript.no scripts");
  private final static PluralizingArgsMessage m_scripts_loaded = new PluralizingArgsMessage("skript.scripts loaded");
 
  @Nullable
  public static Config currentScript = null;
 
  /**
   * use {@link #setCurrentEvent(String, Class...)}
   */
  @Nullable
  private static String currentEventName = null;
 
  @Nullable
  public static String getCurrentEventName() {
    return currentEventName;
  }
 
  /**
   * use {@link #setCurrentEvent(String, Class...)}
   */
  @Nullable
  private static Class<? extends Event>[] currentEvents = null;
 
  /**
   * Call {@link #deleteCurrentEvent()} after parsing
   *
   * @param name
   * @param events
   */
  public static void setCurrentEvent(final String name, final @Nullable Class<? extends Event>... events) {
    currentEventName = name;
    currentEvents = events;
    hasDelayBefore = Kleenean.FALSE;
  }
 
  public static void deleteCurrentEvent() {
    currentEventName = null;
    currentEvents = null;
    hasDelayBefore = Kleenean.FALSE;
  }
 
  public static List<TriggerSection> currentSections = new ArrayList<TriggerSection>();
  public static List<Loop> currentLoops = new ArrayList<Loop>();
  private final static Map<String, ItemType> currentAliases = new HashMap<String, ItemType>();
  final static HashMap<String, String> currentOptions = new HashMap<String, String>();
 
  public static Map<String, ItemType> getScriptAliases() {
    return currentAliases;
  }
 
  /**
   * must be synchronized
   */
  private final static ScriptInfo loadedScripts = new ScriptInfo();
 
  public static Kleenean hasDelayBefore = Kleenean.FALSE;
 
  public static class ScriptInfo {
    public int files, triggers, commands, functions;
   
    public ScriptInfo() {}
   
    public ScriptInfo(final int numFiles, final int numTriggers, final int numCommands, final int numFunctions) {
      files = numFiles;
      triggers = numTriggers;
      commands = numCommands;
      functions = numFunctions;
    }
   
    public void add(final ScriptInfo other) {
      files += other.files;
      triggers += other.triggers;
      commands += other.commands;
      functions += other.functions;
    }
   
    public void subtract(final ScriptInfo other) {
      files -= other.files;
      triggers -= other.triggers;
      commands -= other.commands;
      functions -= other.functions;
    }
  }
 
//  private final static class SerializedScript {
//    public SerializedScript() {}
//   
//    public final List<Trigger> triggers = new ArrayList<Trigger>();
//    public final List<ScriptCommand> commands = new ArrayList<ScriptCommand>();
//  }
 
  private static String indentation = "";
 
  static ScriptInfo loadScripts() {
    final File scriptsFolder = new File(Skript.getInstance().getDataFolder(), Skript.SCRIPTSFOLDER + File.separator);
    if (!scriptsFolder.isDirectory())
      scriptsFolder.mkdirs();
   
    final Date start = new Date();
   
    final ScriptInfo i;
   
    final ErrorDescLogHandler h = SkriptLogger.startLogHandler(new ErrorDescLogHandler(null, null, m_no_errors.toString()));
    try {
      Language.setUseLocal(false);
     
      i = loadScripts(scriptsFolder);
     
      synchronized (loadedScripts) {
        loadedScripts.add(i);
      }
    } finally {
      Language.setUseLocal(true);
      h.stop();
    }
   
    if (i.files == 0)
      Skript.warning(m_no_scripts.toString());
    if (Skript.logNormal() && i.files > 0)
      Skript.info(m_scripts_loaded.toString(i.files, i.triggers, i.commands, start.difference(new Date())));
   
    SkriptEventHandler.registerBukkitEvents();
   
    return i;
  }
 
  /**
   * Filter for enabled scripts & folders.
   */
  private final static FileFilter scriptFilter = new FileFilter() {
    @Override
    public boolean accept(final @Nullable File f) {
      return f != null && (f.isDirectory() || StringUtils.endsWithIgnoreCase("" + f.getName(), ".sk")) && !f.getName().startsWith("-");
    }
  };
 
  /**
   * Loads enabled scripts from the specified directory and it's subdirectories.
   *
   * @param directory
   * @return Info on the loaded scripts
   */
  public final static ScriptInfo loadScripts(final File directory) {
    final ScriptInfo i = new ScriptInfo();
    final boolean wasLocal = Language.setUseLocal(false);
    try {
      final File[] files = directory.listFiles(scriptFilter);
      Arrays.sort(files);
      for (final File f : files) {
        if (f.isDirectory()) {
          i.add(loadScripts(f));
        } else {
          i.add(loadScript(f));
        }
      }
    } finally {
      if (wasLocal)
        Language.setUseLocal(true);
    }
    return i;
  }
 
  /**
   * Loads the specified scripts.
   *
   * @param files
   * @return Info on the loaded scripts
   */
  public final static ScriptInfo loadScripts(final File[] files) {
    Arrays.sort(files);
    final ScriptInfo i = new ScriptInfo();
    final boolean wasLocal = Language.setUseLocal(false);
    try {
      for (final File f : files) {
        assert f != null : Arrays.toString(files);
        i.add(loadScript(f));
      }
    } finally {
      if (wasLocal)
        Language.setUseLocal(true);
    }
   
    synchronized (loadedScripts) {
      loadedScripts.add(i);
    }
   
    SkriptEventHandler.registerBukkitEvents();
   
    return i;
  }
 
  @SuppressWarnings("unchecked")
  private final static ScriptInfo loadScript(final File f) {
//    File cache = null;
//    if (SkriptConfig.enableScriptCaching.value()) {
//      cache = new File(f.getParentFile(), "cache" + File.separator + f.getName() + "c");
//      if (cache.exists()) {
//        final RetainingLogHandler log = SkriptLogger.startRetainingLog();
//        ObjectInputStream in = null;
//        try {
//          in = new ObjectInputStream(new FileInputStream(cache));
//          final long lastModified = in.readLong();
//          if (lastModified == f.lastModified()) {
//            final SerializedScript script = (SerializedScript) in.readObject();
//            triggersLoop: for (final Trigger t : script.triggers) {
//              if (t.getEvent() instanceof SelfRegisteringSkriptEvent) {
//                ((SelfRegisteringSkriptEvent) t.getEvent()).register(t);
//                SkriptEventHandler.addSelfRegisteringTrigger(t);
//              } else {
//                for (final SkriptEventInfo<?> e : Skript.getEvents()) {
//                  if (e.c == t.getEvent().getClass()) {
//                    SkriptEventHandler.addTrigger(e.events, t);
//                    continue triggersLoop;
//                  }
//                }
//                throw new EmptyStackException();
//              }
//            }
//            for (final ScriptCommand c : script.commands) {
//              Commands.registerCommand(c);
//            }
//            log.printLog();
//            return new ScriptInfo(1, script.triggers.size(), script.commands.size());
//          } else {
//            cache.delete();
//          }
//        } catch (final Exception e) {
//          if (Skript.testing()) {
//            System.err.println("[debug] Error loading cached script '" + f.getName() + "':");
//            e.printStackTrace();
//          }
//          unloadScript(f);
//          if (in != null) {
//            try {
//              in.close();
//            } catch (final IOException e1) {}
//          }
//          cache.delete();
//        } finally {
//          log.stop();
//          if (in != null) {
//            try {
//              in.close();
//            } catch (final IOException e) {}
//          }
//        }
//      }
//    }
    try {
      final Config config = new Config(f, true, false, ":");
      if (SkriptConfig.keepConfigsLoaded.value())
        SkriptConfig.configs.add(config);
      int numTriggers = 0;
      int numCommands = 0;
      int numFunctions = 0;
     
      currentAliases.clear();
      currentOptions.clear();
      currentScript = config;
     
//      final SerializedScript script = new SerializedScript();
     
      final CountingLogHandler numErrors = SkriptLogger.startLogHandler(new CountingLogHandler(SkriptLogger.SEVERE));
     
      try {
        for (final Node cnode : config.getMainNode()) {
          if (!(cnode instanceof SectionNode)) {
            Skript.error("invalid line - all code has to be put into triggers");
            continue;
          }
         
          final SectionNode node = ((SectionNode) cnode);
          String event = node.getKey();
          if (event == null)
            continue;
         
          if (event.equalsIgnoreCase("aliases")) {
            node.convertToEntries(0, "=");
            for (final Node n : node) {
              if (!(n instanceof EntryNode)) {
                Skript.error("invalid line in aliases section");
                continue;
              }
              final ItemType t = Aliases.parseAlias(((EntryNode) n).getValue());
              if (t == null)
                continue;
              currentAliases.put(((EntryNode) n).getKey().toLowerCase(), t);
            }
            continue;
          } else if (event.equalsIgnoreCase("options")) {
            node.convertToEntries(0);
            for (final Node n : node) {
              if (!(n instanceof EntryNode)) {
                Skript.error("invalid line in options");
                continue;
              }
              currentOptions.put(((EntryNode) n).getKey(), ((EntryNode) n).getValue());
            }
            continue;
          } else if (event.equalsIgnoreCase("variables")) {
            // TODO allow to make these override existing variables
            node.convertToEntries(0, "=");
            for (final Node n : node) {
              if (!(n instanceof EntryNode)) {
                Skript.error("Invalid line in variables section");
                continue;
              }
              String name = ((EntryNode) n).getKey().toLowerCase(Locale.ENGLISH);
              if (name.startsWith("{") && name.endsWith("}"))
                name = "" + name.substring(1, name.length() - 1);
              final String var = name;
              name = StringUtils.replaceAll(name, "%(.+)?%", new Callback<String, Matcher>() {
                @Override
                @Nullable
                public String run(final Matcher m) {
                  if (m.group(1).contains("{") || m.group(1).contains("}") || m.group(1).contains("%")) {
                    Skript.error("'" + var + "' is not a valid name for a default variable");
                    return null;
                  }
                  final ClassInfo<?> ci = Classes.getClassInfoFromUserInput("" + m.group(1));
                  if (ci == null) {
                    Skript.error("Can't understand the type '" + m.group(1) + "'");
                    return null;
                  }
                  return "<" + ci.getCodeName() + ">";
                }
              });
              if (name == null) {
                continue;
              } else if (name.contains("%")) {
                Skript.error("Invalid use of percent signs in variable name");
                continue;
              }
              if (Variables.getVariable(name, null, false) != null)
                continue;
              Object o;
              final ParseLogHandler log = SkriptLogger.startParseLogHandler();
              try {
                o = Classes.parseSimple(((EntryNode) n).getValue(), Object.class, ParseContext.SCRIPT);
                if (o == null) {
                  log.printError("Can't understand the value '" + ((EntryNode) n).getValue() + "'");
                  continue;
                }
                log.printLog();
              } finally {
                log.stop();
              }
              @SuppressWarnings("null")
              final ClassInfo<?> ci = Classes.getSuperClassInfo(o.getClass());
              if (ci.getSerializer() == null) {
                Skript.error("Can't save '" + ((EntryNode) n).getValue() + "' in a variable");
                continue;
              } else if (ci.getSerializeAs() != null) {
                final ClassInfo<?> as = Classes.getExactClassInfo(ci.getSerializeAs());
                if (as == null) {
                  assert false : ci;
                  continue;
                }
                o = Converters.convert(o, as.getC());
                if (o == null) {
                  Skript.error("Can't save '" + ((EntryNode) n).getValue() + "' in a variable");
                  continue;
                }
              }
              Variables.setVariable(name, o, null, false);
            }
            continue;
          }
         
          if (!SkriptParser.validateLine(event))
            continue;
         
          if (event.toLowerCase().startsWith("command ")) {
           
            setCurrentEvent("command", CommandEvent.class);
           
            final ScriptCommand c = Commands.loadCommand(node);
            if (c != null) {
              numCommands++;
//              script.commands.add(c);
            }
           
            deleteCurrentEvent();
           
            continue;
          } else if (event.toLowerCase().startsWith("function ")) {
           
            setCurrentEvent("function", FunctionEvent.class);
           
            final Function<?> func = Functions.loadFunction(node);
            if (func != null) {
              numFunctions++;
            }
           
            deleteCurrentEvent();
           
            continue;
          }
         
          if (Skript.logVeryHigh() && !Skript.debug())
            Skript.info("loading trigger '" + event + "'");
         
          if (StringUtils.startsWithIgnoreCase(event, "on "))
            event = "" + event.substring("on ".length());
         
          event = replaceOptions(event);
         
          final NonNullPair<SkriptEventInfo<?>, SkriptEvent> parsedEvent = SkriptParser.parseEvent(event, "can't understand this event: '" + node.getKey() + "'");
          if (parsedEvent == null)
            continue;
         
          if (Skript.debug() || node.debug())
            Skript.debug(event + " (" + parsedEvent.getSecond().toString(null, true) + "):");
         
          setCurrentEvent("" + parsedEvent.getFirst().getName().toLowerCase(Locale.ENGLISH), parsedEvent.getFirst().events);
          final Trigger trigger;
          try {
            trigger = new Trigger(config.getFile(), event, parsedEvent.getSecond(), loadItems(node));
          } finally {
            deleteCurrentEvent();
          }
         
          if (parsedEvent.getSecond() instanceof SelfRegisteringSkriptEvent) {
            ((SelfRegisteringSkriptEvent) parsedEvent.getSecond()).register(trigger);
            SkriptEventHandler.addSelfRegisteringTrigger(trigger);
          } else {
            SkriptEventHandler.addTrigger(parsedEvent.getFirst().events, trigger);
          }
         
//          script.triggers.add(trigger);
         
          numTriggers++;
        }
       
        if (Skript.logHigh())
          Skript.info("loaded " + numTriggers + " trigger" + (numTriggers == 1 ? "" : "s") + " and " + numCommands + " command" + (numCommands == 1 ? "" : "s") + " from '" + config.getFileName() + "'");
       
        currentScript = null;
      } finally {
        numErrors.stop();
      }
     
//      if (SkriptConfig.enableScriptCaching.value() && cache != null) {
//        if (numErrors.getCount() > 0) {
//          ObjectOutputStream out = null;
//          try {
//            cache.getParentFile().mkdirs();
//            out = new ObjectOutputStream(new FileOutputStream(cache));
//            out.writeLong(f.lastModified());
//            out.writeObject(script);
//          } catch (final NotSerializableException e) {
//            Skript.exception(e, "Cannot cache " + f.getName());
//            if (out != null)
//              out.close();
//            cache.delete();
//          } catch (final IOException e) {
//            Skript.warning("Cannot cache " + f.getName() + ": " + e.getLocalizedMessage());
//            if (out != null)
//              out.close();
//            cache.delete();
//          } finally {
//            if (out != null)
//              out.close();
//          }
//        }
//      }
     
      return new ScriptInfo(1, numTriggers, numCommands, numFunctions);
    } catch (final IOException e) {
      Skript.error("Could not load " + f.getName() + ": " + ExceptionUtils.toString(e));
    } catch (final Exception e) {
      Skript.exception(e, "Could not load " + f.getName());
    } finally {
      SkriptLogger.setNode(null);
    }
    return new ScriptInfo();
  }
 
  /**
   * Unloads enabled scripts from the specified directory and its subdirectories.
   *
   * @param folder
   * @return Info on the unloaded scripts
   */
  final static ScriptInfo unloadScripts(final File folder) {
    final ScriptInfo r = unloadScripts_(folder);
    Functions.validateFunctions();
    return r;
  }
 
  private final static ScriptInfo unloadScripts_(final File folder) {
    final ScriptInfo info = new ScriptInfo();
    final File[] files = folder.listFiles(scriptFilter);
    for (final File f : files) {
      if (f.isDirectory()) {
        info.add(unloadScripts_(f));
      } else if (f.getName().endsWith(".sk")) {
        info.add(unloadScript_(f));
      }
    }
    return info;
  }
 
  /**
   * Unloads the specified script.
   *
   * @param script
   * @return Info on the unloaded script
   */
  final static ScriptInfo unloadScript(final File script) {
    final ScriptInfo r = unloadScript_(script);
    Functions.validateFunctions();
    return r;
  }
 
  private final static ScriptInfo unloadScript_(final File script) {
    final ScriptInfo info = SkriptEventHandler.removeTriggers(script);
    synchronized (loadedScripts) {
      loadedScripts.subtract(info);
    }
    return info;
  }
 
  public final static String replaceOptions(final String s) {
    final String r = StringUtils.replaceAll(s, "\\{@(.+?)\\}", new Callback<String, Matcher>() {
      @Override
      @Nullable
      public String run(final Matcher m) {
        final String option = currentOptions.get(m.group(1));
        if (option == null) {
          Skript.error("undefined option " + m.group());
          return m.group();
        }
        return option;
      }
    });
    assert r != null;
    return r;
  }
 
  @SuppressWarnings("unchecked")
  public static ArrayList<TriggerItem> loadItems(final SectionNode node) {
   
    if (Skript.debug())
      indentation += "    ";
   
    final ArrayList<TriggerItem> items = new ArrayList<TriggerItem>();
   
    Kleenean hadDelayBeforeLastIf = Kleenean.FALSE;
   
    for (final Node n : node) {
      SkriptLogger.setNode(n);
      if (n instanceof SimpleNode) {
        final SimpleNode e = (SimpleNode) n;
        final String s = replaceOptions("" + e.getKey());
        if (!SkriptParser.validateLine(s))
          continue;
        final Statement stmt = Statement.parse(s, "Can't understand this condition/effect: " + s);
        if (stmt == null)
          continue;
        if (Skript.debug() || n.debug())
          Skript.debug(indentation + stmt.toString(null, true));
        items.add(stmt);
        if (stmt instanceof Delay)
          hasDelayBefore = Kleenean.TRUE;
      } else if (n instanceof SectionNode) {
        String name = replaceOptions("" + n.getKey());
        if (!SkriptParser.validateLine(name))
          continue;
       
        if (StringUtils.startsWithIgnoreCase(name, "loop ")) {
          final String l = "" + name.substring("loop ".length());
          final RetainingLogHandler h = SkriptLogger.startRetainingLog();
          Expression<?> loopedExpr;
          try {
            loopedExpr = new SkriptParser(l).parseExpression(Object.class);
            if (loopedExpr != null)
              loopedExpr = loopedExpr.getConvertedExpression(Object.class);
            if (loopedExpr == null) {
              h.printErrors("Can't understand this loop: '" + name + "'");
              continue;
            }
            h.printLog();
          } finally {
            h.stop();
          }
          if (loopedExpr.isSingle()) {
            Skript.error("Can't loop " + loopedExpr + " because it's only a single value");
            continue;
          }
          if (Skript.debug() || n.debug())
            Skript.debug(indentation + "loop " + loopedExpr.toString(null, true) + ":");
          final Kleenean hadDelayBefore = hasDelayBefore;
          items.add(new Loop(loopedExpr, (SectionNode) n));
          if (hadDelayBefore != Kleenean.TRUE && hasDelayBefore != Kleenean.FALSE)
            hasDelayBefore = Kleenean.UNKNOWN;
        } else if (StringUtils.startsWithIgnoreCase(name, "while ")) {
          final String l = "" + name.substring("while ".length());
          final Condition c = Condition.parse(l, "Can't understand this condition: " + l);
          if (c == null)
            continue;
          if (Skript.debug() || n.debug())
            Skript.debug(indentation + "while " + c.toString(null, true) + ":");
          final Kleenean hadDelayBefore = hasDelayBefore;
          items.add(new While(c, (SectionNode) n));
          if (hadDelayBefore != Kleenean.TRUE && hasDelayBefore != Kleenean.FALSE)
            hasDelayBefore = Kleenean.UNKNOWN;
        } else if (name.equalsIgnoreCase("else")) {
          if (items.size() == 0 || !(items.get(items.size() - 1) instanceof Conditional) || ((Conditional) items.get(items.size() - 1)).hasElseClause()) {
            Skript.error("'else' has to be placed just after an 'if' or 'else if' section");
            continue;
          }
          if (Skript.debug() || n.debug())
            Skript.debug(indentation + "else:");
          final Kleenean hadDelayAfterLastIf = hasDelayBefore;
          hasDelayBefore = hadDelayBeforeLastIf;
          ((Conditional) items.get(items.size() - 1)).loadElseClause((SectionNode) n);
          hasDelayBefore = hadDelayBeforeLastIf.or(hadDelayAfterLastIf.and(hasDelayBefore));
        } else if (StringUtils.startsWithIgnoreCase(name, "else if ")) {
          if (items.size() == 0 || !(items.get(items.size() - 1) instanceof Conditional) || ((Conditional) items.get(items.size() - 1)).hasElseClause()) {
            Skript.error("'else if' has to be placed just after another 'if' or 'else if' section");
            continue;
          }
          name = "" + name.substring("else if ".length());
          final Condition cond = Condition.parse(name, "can't understand this condition: '" + name + "'");
          if (cond == null)
            continue;
          if (Skript.debug() || n.debug())
            Skript.debug(indentation + "else if " + cond.toString(null, true));
          final Kleenean hadDelayAfterLastIf = hasDelayBefore;
          hasDelayBefore = hadDelayBeforeLastIf;
          ((Conditional) items.get(items.size() - 1)).loadElseIf(cond, (SectionNode) n);
          hasDelayBefore = hadDelayBeforeLastIf.or(hadDelayAfterLastIf.and(hasDelayBefore.and(Kleenean.UNKNOWN)));
        } else {
          if (StringUtils.startsWithIgnoreCase(name, "if "))
            name = "" + name.substring(3);
          final Condition cond = Condition.parse(name, "can't understand this condition: '" + name + "'");
          if (cond == null)
            continue;
          if (Skript.debug() || n.debug())
            Skript.debug(indentation + cond.toString(null, true) + ":");
          final Kleenean hadDelayBefore = hasDelayBefore;
          hadDelayBeforeLastIf = hadDelayBefore;
          items.add(new Conditional(cond, (SectionNode) n));
          hasDelayBefore = hadDelayBefore.or(hasDelayBefore.and(Kleenean.UNKNOWN));
        }
      }
    }
   
    for (int i = 0; i < items.size() - 1; i++)
      items.get(i).setNext(items.get(i + 1));
   
    SkriptLogger.setNode(node);
   
    if (Skript.debug())
      indentation = "" + indentation.substring(0, indentation.length() - 4);
   
    return items;
  }
 
  /**
   * For unit testing
   *
   * @param node
   * @return The loaded Trigger
   */
  @Nullable
  static Trigger loadTrigger(final SectionNode node) {
    String event = node.getKey();
    if (event == null) {
      assert false : node;
      return null;
    }
    if (event.toLowerCase().startsWith("on "))
      event = "" + event.substring("on ".length());
   
    final NonNullPair<SkriptEventInfo<?>, SkriptEvent> parsedEvent = SkriptParser.parseEvent(event, "can't understand this event: '" + node.getKey() + "'");
    if (parsedEvent == null) {
      assert false;
      return null;
    }
   
    setCurrentEvent("unit test", parsedEvent.getFirst().events);
    try {
      return new Trigger(null, event, parsedEvent.getSecond(), loadItems(node));
    } finally {
      deleteCurrentEvent();
    }
  }
 
  public final static int loadedScripts() {
    synchronized (loadedScripts) {
      return loadedScripts.files;
    }
  }
 
  public final static int loadedCommands() {
    synchronized (loadedScripts) {
      return loadedScripts.commands;
    }
  }
 
  public final static int loadedFunctions() {
    synchronized (loadedScripts) {
      return loadedScripts.functions;
    }
  }
 
  public final static int loadedTriggers() {
    synchronized (loadedScripts) {
      return loadedScripts.triggers;
    }
  }
 
  public final static boolean isCurrentEvent(final @Nullable Class<? extends Event> event) {
    return CollectionUtils.containsSuperclass(currentEvents, event);
  }
 
  public final static boolean isCurrentEvent(final Class<? extends Event>... events) {
    return CollectionUtils.containsAnySuperclass(currentEvents, events);
  }
 
  /**
   * @see #isCurrentEvent(Class)
   */
  @Nullable
  public static Class<? extends Event>[] getCurrentEvents() {
    return currentEvents;
  }
 
}
TOP

Related Classes of ch.njol.skript.ScriptLoader

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.