Creating an Effect

Creating an Effect

Lets get into it shall we. Effects are basically methods that are void. It's like taking the setting part from the expression of the last expression tutorial. In my opinion they're the easiest syntax to make in the Skript API.

Some things that should be effect are like titles, actonbars, spawning entities and other objects that cant be returned.

Some things can be made into effects but should be made into expressions with changeable options, some would include setting player name, setting player location or setting player's sneak state. Why are using these as effects not recommended? The answer is because they should be expressions rather than effects, because they can have returnable states which may be useful.

So lets get into making the effect. In this tutorial of creating an effect, I will be making a kick effect.

Lets copy Skript's already existing syntax and make it.
kick %players% [(by reason of|because [of]|on account of|due to) %-string%]



First we need to extend the Effect class.
package me.limeglass.addon.elements.effects;

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

import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;

public class EffKickPlayer extends Effect {

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
//Explaining this still below in the tutorial
return false;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
//Explaining this still below in the tutorial
return null;
}

@Override
protected void execute(Event event) {
//Explaining this still below in the tutorial

}
}

So this is a basic Effect class. Lets get into explaining what the methods do:

@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
//Explaining this still below in the tutorial
return false;
}

This is a main method that almost all syntax classes uses, it basically gets all the expressions and data used in the users syntax.

This abstract method calls the expressions of the syntax, the matched patterns if there are any (These are explained in Tip ands Tricks area), if the syntax is delayed and the parser of the whole syntax

So because of our syntax we know that will can have two variables one being optional because it can be null. When an expression is in the optional parameters [these] it's best to keep the optional expression of it null. We can add - to it to make it null by default, like %-string%

So now we know that one of our expressions could be null.

For this method it needs to return true or false. true meaning it did succeed and false if it didn't.

So now our class should look similar to this:
package me.limeglass.addon.elements.effects;

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

import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;

public class EffKickPlayer extends Effect {

static {
Skript.registerEffect(EffKickPlayer.class, "kick %players% [(by reason of|because [of]|on account of|due to) %-string%]");
}

private Expression<Player> player;
private Expression<String> reason;

@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
this.player = (Expression<Player>) expressions[0];
this.reason = (Expression<String>) expressions[1];
return true;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
//Explaining this still below in the tutorial
return null;
}

@Override
protected void execute(Event event) {
//Explaining this still below in the tutorial
}
}

Now for example, let's say we want to make this effect only work in a sneak event. This is what we would have to add to the init method, in order to execute that.

@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
if (!ScriptLoader.isCurrentEvent(PlayerToggleSneakEvent.class)) {
Skript.error("You can only use the kick effect in the Sneak toggle event.", ErrorQuality.SEMANTIC_ERROR);
return false;
}
this.player = (Expression<Player>) expressions[0];
this.reason = (Expression<String>) expressions[1];
return true;
}


The toString is basically a way to make your effect become a string, it's not used to get the effect back into it's state so what you can return in it is some useful information like the expressions etc. These will appear in any errors that may come from your addon and it makes other developers or yourself understand what is going on. So I will just add a generic toString and move on.

The next is the execute method. This is where we can put the actual thing we want to do. So in our case we want to get the player and string if it's not null and then kick the player.

And our final product should look like this
package me.limeglass.addon.elements.effects;

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

import ch.njol.skript.Skript;
import ch.njol.skript.lang.Effect;
import ch.njol.skript.lang.Expression;
import ch.njol.skript.lang.SkriptParser.ParseResult;
import ch.njol.util.Kleenean;

public class EffKickPlayer extends Effect {

static {
Skript.registerEffect(EffKickPlayer.class, "kick %players% [(by reason of|because [of]|on account of|due to) %-string%]");
}

private Expression<Player> player;
private Expression<String> reason;

@SuppressWarnings("unchecked")
@Override
public boolean init(Expression<?>[] expressions, int matchedPattern, Kleenean isDelayed, ParseResult parser) {
this.player = (Expression<Player>) expressions[0];
this.reason = (Expression<String>) expressions[1];
return true;
}

@Override
public String toString(@Nullable Event event, boolean debug) {
return "Kick player effect with expression player: " + player.toString(event, debug) + " and string expression: " + reason.toString(event, debug);
}

@Override
protected void execute(Event event) {
if (player == null) return;
for (Player user : player.getAll(event)) {
if (reason != null || reason.getSingle(event) != null) {
user.kickPlayer(reason.getSingle(event));
} else {
user.kickPlayer("You have been kicked.");
}
}
}
}

To look at more examples you can check out Skript's effects from Bensku's fork here https://github.com/bensku/Skript/tree/master/src/main/java/ch/njol/skript/effects


Addon tutorial
Back | Next