Skip to content

Commit

Permalink
Rework EffectLib Integration (#384)
Browse files Browse the repository at this point in the history
  • Loading branch information
tal5 committed Aug 27, 2022
1 parent 7dac08d commit c5c5a1d
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 122 deletions.
4 changes: 2 additions & 2 deletions pom.xml
Expand Up @@ -118,9 +118,9 @@
<dependency>
<groupId>de.slikey</groupId>
<artifactId>EffectLib</artifactId>
<version>5.8</version>
<version>9.4</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/EffectLib-5.8.jar</systemPath>
<systemPath>${project.basedir}/lib/EffectLib.jar</systemPath>
</dependency>
<dependency>
<groupId>net.ess3</groupId>
Expand Down
@@ -1,16 +1,20 @@
package com.denizenscript.depenizen.bukkit.bridges;

import com.denizenscript.denizencore.DenizenCore;
import com.denizenscript.depenizen.bukkit.Depenizen;
import com.denizenscript.depenizen.bukkit.commands.effectlib.EffectLibCommand;
import com.denizenscript.depenizen.bukkit.Bridge;
import de.slikey.effectlib.EffectManager;

public class EffectLibBridge extends Bridge {

public static EffectLibBridge instance;
public EffectManager effectManager;

@Override
public void init() {
instance = this;
effectManager = new EffectManager(Depenizen.instance);
DenizenCore.commandRegistry.registerCommand(EffectLibCommand.class);
}
}
@@ -1,170 +1,167 @@
package com.denizenscript.depenizen.bukkit.commands.effectlib;

import com.denizenscript.denizencore.objects.Argument;
import com.denizenscript.depenizen.bukkit.bridges.EffectLibBridge;
import de.slikey.effectlib.EffectManager;
import de.slikey.effectlib.effect.ArcEffect;
import de.slikey.effectlib.effect.AtomEffect;
import de.slikey.effectlib.effect.BleedEffect;
import com.denizenscript.denizen.objects.EntityTag;
import com.denizenscript.denizen.objects.LocationTag;
import com.denizenscript.denizen.objects.PlayerTag;
import com.denizenscript.denizen.utilities.Utilities;
import com.denizenscript.denizencore.exceptions.InvalidArgumentsException;
import com.denizenscript.denizencore.objects.ObjectTag;
import com.denizenscript.denizencore.objects.core.DurationTag;
import com.denizenscript.denizencore.objects.core.MapTag;
import com.denizenscript.denizencore.scripts.ScriptEntry;
import com.denizenscript.denizencore.scripts.commands.AbstractCommand;
import com.denizenscript.denizencore.scripts.commands.Holdable;
import com.denizenscript.denizencore.scripts.commands.generator.ArgDefaultNull;
import com.denizenscript.denizencore.scripts.commands.generator.ArgName;
import com.denizenscript.denizencore.scripts.commands.generator.ArgPrefixed;
import com.denizenscript.denizencore.tags.TagContext;
import com.denizenscript.denizencore.utilities.CoreUtilities;
import com.denizenscript.denizencore.utilities.debugging.Debug;
import org.bukkit.Location;
import com.denizenscript.denizencore.utilities.debugging.SlowWarning;
import com.denizenscript.denizencore.utilities.debugging.Warning;
import com.denizenscript.denizencore.utilities.text.StringHolder;
import com.denizenscript.depenizen.bukkit.bridges.EffectLibBridge;
import de.slikey.effectlib.Effect;
import de.slikey.effectlib.util.DynamicLocation;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration;

public class EffectLibCommand extends AbstractCommand {
import java.util.Map;

public class EffectLibCommand extends AbstractCommand implements Holdable {

public EffectLibCommand() {
setName("effectlib");
setSyntax("effectlib (type:<effect name>) (duration:<duration>) (target:<entity>/location:<location>)");
setRequiredArguments(1, 3);
setSyntax("effectlib [type:<effect>] (origin:<entity>/<location>) (target:<entity>/<location>) (for:<player>) (effect_data:<map>)");
setRequiredArguments(1, 5);
autoCompile();
}

// <--[command]
// @Name effectlib
// @Syntax effectlib (type:<effect name>) (duration:<duration>) (target:<entity>/location:<location>)
// @Syntax effectlib [type:<effect>] (origin:<entity>/<location>) (target:<entity>/<location>) (for:<player>) (effect_data:<map>)
// @Group Depenizen
// @Plugin Depenizen, EffectLib
// @Required 1
// @Maximum 3
// @Maximum 5
// @Short Show custom effects using EffectLib
//
// @Description
// Use to show custom effects in a easier way using the config file in EffectLib.
// The effect names comes from the config file.
// Specify a location instead of a target to show the effect at a location instead.
// Displays EffectLib effects.
// Specify which effect to display using the 'type:' argument, note that effect names are CASE-SENSITIVE.
// The origin is the entity/location to play the effect at. If an entity is specified, the effect will follow it.
// Defaults to the linked player if unspecified.
// Some effects (such as the 'Line' effect) require an origin and a target, an effect's target can be a location or an entity.
// If an entity is specified, the effect will follow it.
//
// You can optionally use the 'for:' argument to show the effect to one player only.
//
// EffectLib effects can take additional data to change how the effect looks/works, you can specify that data in the form of a MapTag using the 'effect_data:' argument.
// See EffectLib's docs for further information on the available options for each effect: <@link url https://reference.elmakers.com/#effectlib>
//
// Note that this should only be used for displaying effects. for showing single particles, etc. use <@link command playeffect>.
//
// Note that most users should instead use <@link command playeffect>.
// The effectlib command is ~waitable. Refer to <@link language ~waitable>.
// When ~waited for, the command will wait until the effect is done playing.
//
// @Tags
// None
//
// @Usage
// Use to show a effect on the attached player in queue.
// - effectlib bleed duration:10s
// Use to show a helix of end rod sparks below the linked player for 5 seconds.
// - effectlib type:Helix effect_data:[duration=<duration[5s].in_milliseconds>;particle=end_rod;offset=0,-1.5,0]
//
// @Usage
// Use to show a effect on a target entity.
// - effectlib atom target:<player.target> duration:10s
// Use to show a line of electric sparks between 2 entities for 1 minute.
// - effectlib type:Line origin:<[originEntity]> target:<[targetEntity]> effect_data:[duration=<duration[1m].in_milliseconds>;particle=electric_spark]
//
// @Usage
// Use to show effect at a position of the player.
// - effectlib type:atom duration:10s location:<player.location>
// Use to show an atom effect at a location, and narrate a message after it's done playing.
// - ~effectlib type:Atom origin:<[location]>
// - narrate "It's done!"
//
// -->

private enum Action {
BLEED, ARC, ATOM
}
public static Warning durationArgument = new SlowWarning("effectlibCommandDuration", "The 'duration:<duration>' argument for the 'effectlib' command is deprecated in favour of the 'duration' key in the 'effect_data' map, refer to the meta docs for more information.");
public static Warning oldTargetArguments = new SlowWarning("effectlibCommandOldTarget", "The 'target:<entity>'/'location:<location>' arguments for the 'effectlib' command are deprecated in favour of the 'origin:<entity>/<location>' argument.");
public static Warning caseInsensitiveEffectName = new SlowWarning("effectlibCommandCaseInsensitiveType", "Case-Insensitive effect types in the 'effectlib' commands are deprecated. make sure you're using correct casing.");

@Override
public void parseArgs(ScriptEntry scriptEntry) throws InvalidArgumentsException {
for (Argument arg : scriptEntry) {
if (!scriptEntry.hasObject("target")
&& arg.matchesPrefix("target")) {
scriptEntry.addObject("target", arg.asType(EntityTag.class));
}
else if (!scriptEntry.hasObject("duration")
&& arg.matchesPrefix("duration")) {
scriptEntry.addObject("duration", arg.asType(DurationTag.class));
}
else if (!scriptEntry.hasObject("location")
&& arg.matchesPrefix("location")) {
scriptEntry.addObject("location", arg.asType(LocationTag.class));
}
else if (!scriptEntry.hasObject("action")
&& arg.matchesEnum(Action.class)) {
scriptEntry.addObject("action", Action.valueOf(arg.getValue().toUpperCase()));
}
else {
arg.reportUnhandled();
}
public static void autoExecute(ScriptEntry scriptEntry,
@ArgPrefixed @ArgName("type") String effectInput,
@ArgDefaultNull @ArgPrefixed @ArgName("origin") ObjectTag originInput,
@ArgDefaultNull @ArgPrefixed @ArgName("target") ObjectTag targetInput,
@ArgDefaultNull @ArgPrefixed @ArgName("for") PlayerTag forPlayer,
@ArgDefaultNull @ArgPrefixed @ArgName("effect_data") MapTag effectData,
@ArgDefaultNull @ArgPrefixed @ArgName("duration") DurationTag duration,
@ArgDefaultNull @ArgPrefixed @ArgName("location") LocationTag oldLocation) {
if (originInput == null && oldLocation != null) {
oldTargetArguments.warn(scriptEntry);
originInput = oldLocation;
targetInput = null;
}
if (originInput == null && targetInput != null && targetInput.shouldBeType(EntityTag.class)) {
oldTargetArguments.warn(scriptEntry);
originInput = targetInput;
targetInput = null;
}
if (!scriptEntry.hasObject("action")) {
throw new InvalidArgumentsException("Effect not specified!");
if (originInput == null && Utilities.entryHasPlayer(scriptEntry)) {
originInput = Utilities.getEntryPlayer(scriptEntry);
}
if (!scriptEntry.hasObject("duration")) {
throw new InvalidArgumentsException("Duration not specified!");
if (originInput == null) {
Debug.echoError(scriptEntry, "Must specify an origin location or entity!");
return;
}
// EffectLib is case-sensitive, and the way the command used to handle effect names let you input 'atom', where now 'Atom' is required
if (Character.isLowerCase(effectInput.charAt(0))) {
caseInsensitiveEffectName.warn(scriptEntry);
effectInput = Character.toUpperCase(effectInput.charAt(0)) + effectInput.substring(1);
}
if (!scriptEntry.hasObject("target")) {
if (Utilities.entryHasPlayer(scriptEntry)) {
scriptEntry.addObject("target", Utilities.getEntryPlayer(scriptEntry).getDenizenEntity());
Effect effect;
if (effectData == null) {
effect = EffectLibBridge.instance.effectManager.getEffectByClassName(effectInput);
if (effect != null) {
effect.setDynamicOrigin(getEffectLibLocationFrom(originInput, scriptEntry.context));
effect.setDynamicTarget(getEffectLibLocationFrom(targetInput, scriptEntry.context));
effect.setTargetPlayer(forPlayer != null ? forPlayer.getPlayerEntity() : null);
}
}

}

@Override
public void execute(final ScriptEntry scriptEntry) {
EntityTag target = scriptEntry.getObjectTag("target");
Action action = (Action) scriptEntry.getObject("action");
DurationTag duration = scriptEntry.getObjectTag("duration");
LocationTag location = scriptEntry.getObjectTag("location");
if (scriptEntry.dbCallShouldDebug()) {
Debug.report(scriptEntry, getName(), target, action, duration, location);
else {
ConfigurationSection effectLibData = new MemoryConfiguration();
for (Map.Entry<StringHolder, ObjectTag> entry : effectData.map.entrySet()) {
effectLibData.set(entry.getKey().str, CoreUtilities.objectTagToJavaForm(entry.getValue(), false, true));
}
effect = EffectLibBridge.instance.effectManager.getEffect(
effectInput,
effectLibData,
getEffectLibLocationFrom(originInput, scriptEntry.context),
getEffectLibLocationFrom(targetInput, scriptEntry.context),
null,
forPlayer != null ? forPlayer.getPlayerEntity() : null);
}
if (target == null && location == null) {
Debug.echoError(scriptEntry, "Target not found!");
if (effect == null) {
Debug.echoError(scriptEntry, "Invalid effect specified: " + effectInput);
return;
}
if (action == null) {
Debug.echoError(scriptEntry, "Effect type not specified!");
return;
effect.callback = () -> scriptEntry.setFinished(true);
if (duration != null) {
durationArgument.warn(scriptEntry);
effect.iterations = duration.getTicksAsInt();
}
if (duration == null) {
Debug.echoError(scriptEntry, "Duration not specified!");
return;
effect.start();
}

public static DynamicLocation getEffectLibLocationFrom(ObjectTag object, TagContext context) {
if (object == null) {
return null;
}
int ticks = duration.getTicksAsInt();
EffectManager effectManager = new EffectManager(EffectLibBridge.instance.plugin);
// TODO: Find a better way to handle all effects and add custom ones as well
switch (action) {
case BLEED: {
BleedEffect effect = new BleedEffect(effectManager);
if (location == null) {
effect.setEntity(target.getBukkitEntity());
}
else {
effect.setLocation(new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()));
}
effect.callback = () -> scriptEntry.setFinished(true);
effect.iterations = ticks;
effect.start();
return;
}
case ARC: {
ArcEffect effect = new ArcEffect(effectManager);
if (location == null) {
effect.setEntity(target.getBukkitEntity());
}
else {
effect.setLocation(new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()));
}
effect.callback = () -> scriptEntry.setFinished(true);
effect.iterations = ticks;
effect.start();
return;
}
case ATOM: {
AtomEffect effect = new AtomEffect(effectManager);
if (location == null) {
effect.setEntity(target.getBukkitEntity());
}
else {
effect.setLocation(new Location(location.getWorld(), location.getX(), location.getY(), location.getZ()));
}
effect.callback = () -> scriptEntry.setFinished(true);
effect.iterations = ticks;
effect.start();
return;
}
default: {
Debug.echoError(scriptEntry, "Effect type not found!");
if (object.shouldBeType(LocationTag.class)) {
return new DynamicLocation(object.asType(LocationTag.class, context));
}
else {
EntityTag entity = object.asType(EntityTag.class, context);
if (entity == null) {
Debug.echoError(context, "Invalid input specified '" + object + "': must be a valid location or entity.");
return null;
}
return new DynamicLocation(entity.getBukkitEntity());
}
}
}

0 comments on commit c5c5a1d

Please sign in to comment.