/** * 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-2017 Peter Güttinger and contributors */ package ch.njol.skript.lang; import java.io.File; import org.bukkit.event.Event; import org.eclipse.jdt.annotation.Nullable; import ch.njol.skript.Skript; import ch.njol.util.StringUtils; /** * Represents a trigger item, i.e. a trigger section, a condition or an effect. * * @author Peter Güttinger * @see TriggerSection * @see Trigger * @see Statement */ public abstract class TriggerItem implements Debuggable { @Nullable protected TriggerSection parent = null; @Nullable private TriggerItem next = null; protected TriggerItem() {} protected TriggerItem(final TriggerSection parent) { this.parent = parent; } /** * Executes this item and returns the next item to run. * <p> * Overriding classes must call {@link #debug(Event, boolean)}. If this method is overridden, {@link #run(Event)} is not used anymore and can be ignored. * * @param e * @return The next item to run or null to stop execution */ @Nullable protected TriggerItem walk(final Event e) { if (run(e)) { debug(e, true); return next; } else { debug(e, false); final TriggerSection parent = this.parent; return parent == null ? null : parent.getNext(); } } /** * Executes this item. * * @param e * @return True if the next item should be run, or false for the item following this item's parent. */ protected abstract boolean run(Event e); /** * @param start * @param e * @return false iff an exception occurred */ public static boolean walk(final TriggerItem start, final Event e) { assert start != null && e != null; TriggerItem i = start; try { while (i != null) i = i.walk(e); return true; } catch (final StackOverflowError err) { final Trigger t = start.getTrigger(); final File sc = t == null ? null : t.getScript(); Skript.adminBroadcast("<red>The script '<gold>" + (sc == null ? "<unknown>" : sc.getName()) + "<red>' infinitely (or excessively) repeated itself!"); if (Skript.debug()) err.printStackTrace(); } catch (final Exception ex) { if (ex.getStackTrace().length != 0) // empty exceptions have already been printed Skript.exception(ex, i); } return false; } /** * how much to indent each level */ private final static String indent = " "; @Nullable private String indentation = null; public String getIndentation() { String ind = indentation; if (ind == null) { int level = 0; TriggerItem i = this; while ((i = i.parent) != null) level++; indentation = ind = StringUtils.multiply(indent, level); } return ind; } protected final void debug(final Event e, final boolean run) { if (!Skript.debug()) return; Skript.debug(getIndentation() + (run ? "" : "-") + toString(e, true)); } @Override public final String toString() { return toString(null, false); } public TriggerItem setParent(final @Nullable TriggerSection parent) { this.parent = parent; return this; } @Nullable public final TriggerSection getParent() { return parent; } /** * @return The trigger this item belongs to, or null if this is a stand-alone item (e.g. the effect of an effect command) */ @Nullable public final Trigger getTrigger() { TriggerItem i = this; while (i != null && !(i instanceof Trigger)) i = i.getParent(); // if (i == null) // throw new IllegalStateException("TriggerItem without a Trigger detected!"); return (Trigger) i; } public TriggerItem setNext(final @Nullable TriggerItem next) { this.next = next; return this; } @Nullable public TriggerItem getNext() { return next; } }