Package ch.njol.skript.effects

Source Code of ch.njol.skript.effects.EffChange

/*
*   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.effects;

import java.util.Arrays;
import java.util.logging.Level;

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

import ch.njol.skript.Skript;
import ch.njol.skript.classes.Changer;
import ch.njol.skript.classes.Changer.ChangeMode;
import ch.njol.skript.classes.ClassInfo;
import ch.njol.skript.doc.Description;
import ch.njol.skript.doc.Examples;
import ch.njol.skript.doc.Name;
import ch.njol.skript.doc.Since;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.skript.lang.Variable;
import ch.njol.skript.log.CountingLogHandler;
import ch.njol.skript.log.ErrorQuality;
import ch.njol.skript.log.ParseLogHandler;
import ch.njol.skript.log.SkriptLogger;
import ch.njol.skript.registrations.Classes;
import ch.njol.skript.util.Patterns;
import ch.njol.skript.util.Utils;
import ch.njol.util.Kleenean;

/**
* @author Peter Güttinger
*/
@Name("Change: Set/Add/Remove/Delete/Reset")
@Description("A very general effect that can change many <a href='../expressions'>expressions</a>. Many expressions can only be set and/or deleted, while some can have things added to or removed from them.")
@Examples({"# set:",
    "Set the player's display name to \"<red>%name of player%\"",
    "set the block above the victim to lava",
    "# add:",
    "add 2 to the player's health # preferably use '<a href='#heal'>heal</a>' for this",
    "add argument to {blacklist::*}",
    "give a diamond pickaxe of efficiency 5 to the player",
    "increase the data value of the clicked block by 1",
    "# remove:",
    "remove 2 pickaxes from the victim",
    "subtract 2.5 from {points.%player%}",
    "# remove all:",
    "remove every iron tool from the player",
    "remove all minecarts from {entitylist::*}",
    "# delete:",
    "delete the block below the player",
    "clear drops",
    "delete {variable}",
    "# reset:",
    "reset walk speed of player",
    "reset chunk at the targeted block"})
@Since("1.0 (set, add, remove, delete), 2.0 (remove all)")
public class EffChange extends Effect {
  private static Patterns<ChangeMode> patterns = new Patterns<ChangeMode>(new Object[][] {
      {"(add|give) %objects% to %~objects%", ChangeMode.ADD},
      {"increase %~objects% by %objects%", ChangeMode.ADD},
      {"give %~objects% %objects%", ChangeMode.ADD},
     
      {"set %~objects% to %objects%", ChangeMode.SET},
     
      {"remove (all|every) %objects% from %~objects%", ChangeMode.REMOVE_ALL},
     
      {"(remove|subtract) %objects% from %~objects%", ChangeMode.REMOVE},
      {"reduce %~objects% by %objects%", ChangeMode.REMOVE},
     
      {"(delete|clear) %~objects%", ChangeMode.DELETE},
     
      {"reset %~objects%", ChangeMode.RESET}
  });
 
  static {
    Skript.registerEffect(EffChange.class, patterns.getPatterns());
  }
 
  @SuppressWarnings("null")
  private Expression<?> changed;
  @Nullable
  private Expression<?> changer = null;
 
  @SuppressWarnings("null")
  private ChangeMode mode;
 
  private boolean single;
 
//  private Changer<?, ?> c = null;
 
  @SuppressWarnings({"unchecked", "null"})
  @Override
  public boolean init(final Expression<?>[] exprs, final int matchedPattern, final Kleenean isDelayed, final ParseResult parser) {
   
    mode = patterns.getInfo(matchedPattern);
   
    switch (mode) {
      case ADD:
        if (matchedPattern == 0) {
          changer = exprs[0];
          changed = exprs[1];
        } else {
          changer = exprs[1];
          changed = exprs[0];
        }
        break;
      case SET:
        changer = exprs[1];
        changed = exprs[0];
        break;
      case REMOVE_ALL:
        changer = exprs[0];
        changed = exprs[1];
        break;
      case REMOVE:
        if (matchedPattern == 5) {
          changer = exprs[0];
          changed = exprs[1];
        } else {
          changer = exprs[1];
          changed = exprs[0];
        }
        break;
      case DELETE:
        changed = exprs[0];
        break;
      case RESET:
        changed = exprs[0];
    }
   
    final CountingLogHandler h = SkriptLogger.startLogHandler(new CountingLogHandler(Level.SEVERE));
    final Class<?>[] rs;
    final String what;
    try {
      rs = changed.acceptChange(mode);
      final ClassInfo<?> c = Classes.getSuperClassInfo(changed.getReturnType());
      final Changer<?> changer = c.getChanger();
      what = changer == null || !Arrays.equals(changer.acceptChange(mode), rs) ? changed.toString(null, false) : c.getName().withIndefiniteArticle();
    } finally {
      h.stop();
    }
    if (rs == null) {
      if (h.getCount() > 0)
        return false;
      switch (mode) {
        case SET:
          Skript.error(what + " can't be set to anything", ErrorQuality.SEMANTIC_ERROR);
          break;
        case DELETE:
          if (changed.acceptChange(ChangeMode.RESET) != null)
            Skript.error(what + " can't be deleted/cleared. It can however be reset which might result in the desired effect.", ErrorQuality.SEMANTIC_ERROR);
          else
            Skript.error(what + " can't be deleted/cleared", ErrorQuality.SEMANTIC_ERROR);
          break;
        case REMOVE_ALL:
          if (changed.acceptChange(ChangeMode.REMOVE) != null) {
            Skript.error(what + " can't have 'all of something' removed from it. Use 'remove' instead of 'remove all' to fix this.", ErrorQuality.SEMANTIC_ERROR);
            break;
          }
          //$FALL-THROUGH$
        case ADD:
        case REMOVE:
          Skript.error(what + " can't have anything " + (mode == ChangeMode.ADD ? "added to" : "removed from") + " it", ErrorQuality.SEMANTIC_ERROR);
          break;
        case RESET:
          if (changed.acceptChange(ChangeMode.DELETE) != null)
            Skript.error(what + " can't be reset. It can however be deleted which might result in the desired effect.", ErrorQuality.SEMANTIC_ERROR);
          else
            Skript.error(what + " can't be reset", ErrorQuality.SEMANTIC_ERROR);
      }
      return false;
    }
   
    final Class<?>[] rs2 = new Class<?>[rs.length];
    for (int i = 0; i < rs.length; i++)
      rs2[i] = rs[i].isArray() ? rs[i].getComponentType() : rs[i];
    final boolean allSingle = Arrays.equals(rs, rs2);
   
    Expression<?> ch = changer;
    if (ch != null) {
      Expression<?> v = null;
      final ParseLogHandler log = SkriptLogger.startParseLogHandler();
      try {
        for (final Class<?> r : rs) {
          log.clear();
          if ((r.isArray() ? r.getComponentType() : r).isAssignableFrom(ch.getReturnType())) {
            v = ch.getConvertedExpression(Object.class);
            break; // break even if v == null as it won't convert to Object apparently
          }
        }
        if (v == null)
          v = ch.getConvertedExpression((Class<Object>[]) rs2);
        if (v == null) {
          if (log.hasError()) {
            log.printError();
            return false;
          }
          log.clear();
          log.printLog();
          final Class<?>[] r = new Class[rs.length];
          for (int i = 0; i < rs.length; i++)
            r[i] = rs[i].isArray() ? rs[i].getComponentType() : rs[i];
          if (rs.length == 1 && rs[0] == Object.class)
            Skript.error("Can't understand this expression: " + changer, ErrorQuality.NOT_AN_EXPRESSION);
          else if (mode == ChangeMode.SET)
            Skript.error(what + " can't be set to " + changer + " because the latter is " + SkriptParser.notOfType(r), ErrorQuality.SEMANTIC_ERROR);
          else
            Skript.error(changer + " can't be " + (mode == ChangeMode.ADD ? "added to" : "removed from") + " " + what + " because the former is " + SkriptParser.notOfType(r), ErrorQuality.SEMANTIC_ERROR);
          return false;
        }
        log.printLog();
      } finally {
        log.stop();
      }
     
      Class<?> x = Utils.getSuperType(rs2);
      single = allSingle;
      for (int i = 0; i < rs.length; i++) {
        if (rs2[i].isAssignableFrom(v.getReturnType())) {
          single = !rs[i].isArray();
          x = rs2[i];
          break;
        }
      }
      assert x != null;
      changer = ch = v;
     
      if (!ch.isSingle() && single) {
        if (mode == ChangeMode.SET)
          Skript.error(changed + " can only be set to one " + Classes.getSuperClassInfo(x).getName() + ", not more", ErrorQuality.SEMANTIC_ERROR);
        else
          Skript.error("only one " + Classes.getSuperClassInfo(x).getName() + " can be " + (mode == ChangeMode.ADD ? "added to" : "removed from") + " " + changed + ", not more", ErrorQuality.SEMANTIC_ERROR);
        return false;
      }
     
      if (changed instanceof Variable && !((Variable<?>) changed).isLocal() && (mode == ChangeMode.SET || ((Variable<?>) changed).isList() && mode == ChangeMode.ADD)) {
        final ClassInfo<?> ci = Classes.getSuperClassInfo(ch.getReturnType());
        if (ci.getC() != Object.class && ci.getSerializer() == null && ci.getSerializeAs() == null)
          Skript.warning(ci.getName().withIndefiniteArticle() + " cannot be saved, i.e. the contents of the variable " + changed + " will be lost when the server stops.");
      }
    }
    return true;
  }
 
  @Override
  protected void execute(final Event e) {
    final Expression<?> changer = this.changer;
    final Object[] delta = changer == null ? null : changer.getArray(e);
    if (delta != null && delta.length == 0)
      return;
    changed.change(e, delta, mode); // REMIND use a random element out of delta if changed only supports changing a single instance
//    changed.change(e, new Changer2<Object>() {
//      @Override
//      public Object change(Object o) {
//        return delta;
//      }
//    }, mode);
  }
 
  @Override
  public String toString(final @Nullable Event e, final boolean debug) {
    final Expression<?> changer = this.changer;
    switch (mode) {
      case ADD:
        assert changer != null;
        return "add " + changer.toString(e, debug) + " to " + changed.toString(e, debug);
      case SET:
        assert changer != null;
        return "set " + changed.toString(e, debug) + " to " + changer.toString(e, debug);
      case REMOVE:
        assert changer != null;
        return "remove " + changer.toString(e, debug) + " from " + changed.toString(e, debug);
      case REMOVE_ALL:
        assert changer != null;
        return "remove all " + changer.toString(e, debug) + " from " + changed.toString(e, debug);
      case DELETE:
        return "delete/clear " + changed.toString(e, debug);
      case RESET:
        return "reset " + changed.toString(e, debug);
    }
    assert false;
    return "";
  }
 
}
TOP

Related Classes of ch.njol.skript.effects.EffChange

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.