diff --git a/lib/groovy-2.4.11.jar b/lib/groovy-2.4.11.jar
new file mode 100644
index 000000000..ccf798021
Binary files /dev/null and b/lib/groovy-2.4.11.jar differ
diff --git a/pom.xml b/pom.xml
index 96a0d35cc..23c607e91 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,6 +53,11 @@
lz4
1.3.0
+
+ org.codehaus.groovy
+ groovy
+ 2.4.11
+
diff --git a/scripts/commands/generic/addFriend.groovy b/scripts/commands/generic/addFriend.groovy
new file mode 100644
index 000000000..59c5b3cda
--- /dev/null
+++ b/scripts/commands/generic/addFriend.groovy
@@ -0,0 +1,15 @@
+import intents.chat.ChatAvatarRequestIntent
+import resources.objects.SWGObject
+import resources.player.Player
+import services.galaxy.GalacticManager
+
+static def execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
+ if (args == null)
+ return
+
+ def name = args.split(" ")[0].toLowerCase(Locale.ENGLISH)
+ if (name == null)
+ return
+
+ new ChatAvatarRequestIntent(player, name, ChatAvatarRequestIntent.RequestType.FRIEND_ADD_TARGET).broadcast()
+}
\ No newline at end of file
diff --git a/scripts/commands/generic/cmdTip.groovy b/scripts/commands/generic/cmdTip.groovy
new file mode 100644
index 000000000..f88902da5
--- /dev/null
+++ b/scripts/commands/generic/cmdTip.groovy
@@ -0,0 +1,32 @@
+import resources.commands.ICmdCallback
+import resources.objects.SWGObject
+import resources.player.AccessLevel
+import resources.player.Player
+import services.galaxy.GalacticManager
+import utilities.IntentFactory
+
+class CmdTip implements ICmdCallback {
+ void execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
+ if (player.getAccessLevel() == AccessLevel.PLAYER) {
+ IntentFactory.sendSystemMessage(player, "Unable to access /tip command - currently reserved for admins")
+ return
+ }
+ def argSplit = args.split(" ")
+ if (argSplit.length < 2) {
+ IntentFactory.sendSystemMessage(player, "Invalid Arguments: " + args)
+ return
+ }
+ def creature = player.getCreatureObject()
+ if (argSplit[0] == "bank")
+ creature.setBankBalance(creature.getBankBalance() + Long.valueOf(argSplit[1]))
+ else if (argSplit[0] == "cash")
+ creature.setCashBalance(creature.getCashBalance() + Long.valueOf(argSplit[1]))
+ else
+ IntentFactory.sendSystemMessage(player, "Unknown Destination: " + argSplit[0])
+ }
+}
+
+def execute(GalacticManager galacticManager, Player player, SWGObject target, String args) {
+ println("Hello World!")
+ new CmdTip().execute(galacticManager, player, target, args)
+}
\ No newline at end of file
diff --git a/src/main/ProjectSWG.java b/src/main/ProjectSWG.java
index ee44f64ec..9daa264f1 100644
--- a/src/main/ProjectSWG.java
+++ b/src/main/ProjectSWG.java
@@ -27,6 +27,18 @@
***********************************************************************************/
package main;
+import com.projectswg.common.concurrency.Delay;
+import com.projectswg.common.control.IntentManager;
+import com.projectswg.common.debug.Log;
+import com.projectswg.common.debug.Log.LogLevel;
+import com.projectswg.common.debug.log_wrapper.ConsoleLogWrapper;
+import com.projectswg.common.debug.log_wrapper.FileLogWrapper;
+import intents.server.ServerStatusIntent;
+import resources.Galaxy.GalaxyStatus;
+import resources.control.ServerStatus;
+import resources.server_info.DataManager;
+import services.CoreManager;
+
import java.io.File;
import java.io.IOException;
import java.lang.Thread.State;
@@ -36,19 +48,6 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
-import com.projectswg.common.concurrency.Delay;
-import com.projectswg.common.control.IntentManager;
-import com.projectswg.common.debug.Log;
-import com.projectswg.common.debug.Log.LogLevel;
-import com.projectswg.common.debug.log_wrapper.ConsoleLogWrapper;
-import com.projectswg.common.debug.log_wrapper.FileLogWrapper;
-
-import intents.server.ServerStatusIntent;
-import resources.Galaxy.GalaxyStatus;
-import resources.control.ServerStatus;
-import resources.server_info.DataManager;
-import services.CoreManager;
-
public class ProjectSWG {
private static ProjectSWG server;
diff --git a/src/resources/commands/ICmdCallback.java b/src/resources/commands/ICmdCallback.java
index 79deddb63..20d627521 100644
--- a/src/resources/commands/ICmdCallback.java
+++ b/src/resources/commands/ICmdCallback.java
@@ -32,5 +32,5 @@ import resources.player.Player;
import services.galaxy.GalacticManager;
public interface ICmdCallback {
- public void execute(GalacticManager galacticManager, Player player, SWGObject target, String args);
+ void execute(GalacticManager galacticManager, Player player, SWGObject target, String args);
}
diff --git a/src/resources/commands/callbacks/QaToolCmdCallback.java b/src/resources/commands/callbacks/QaToolCmdCallback.java
index 7d66e3dee..72fcedf08 100644
--- a/src/resources/commands/callbacks/QaToolCmdCallback.java
+++ b/src/resources/commands/callbacks/QaToolCmdCallback.java
@@ -27,13 +27,11 @@
package resources.commands.callbacks;
-import java.io.FileNotFoundException;
-import java.util.Map;
-
import com.projectswg.common.data.location.Location;
import com.projectswg.common.data.location.Terrain;
import com.projectswg.common.debug.Log;
-
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
import intents.chat.ChatBroadcastIntent;
import intents.experience.ExperienceIntent;
import intents.network.CloseConnectionIntent;
@@ -58,6 +56,8 @@ import services.objects.StaticItemService.ObjectCreationHandler;
import services.player.PlayerManager;
import utilities.Scripts;
+import java.util.Map;
+
/**
* Created by Waverunner on 8/19/2015
*/
@@ -94,7 +94,7 @@ public class QaToolCmdCallback implements ICmdCallback {
case "details":
try {
Scripts.invoke("commands/helper/qatool/details", "sendDetails", player, target, args.split(" "));
- } catch (FileNotFoundException ex) {
+ } catch (ResourceException | ScriptException e) {
Log.e("sendDetails qatool script not found!");
}
break;
diff --git a/src/resources/radial/Radials.java b/src/resources/radial/Radials.java
index 4ae182acd..2e812e2a4 100644
--- a/src/resources/radial/Radials.java
+++ b/src/resources/radial/Radials.java
@@ -27,16 +27,16 @@
***********************************************************************************/
package resources.radial;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.List;
-
import com.projectswg.common.debug.Log;
-
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
import resources.objects.SWGObject;
import resources.player.Player;
import utilities.Scripts;
+import java.util.ArrayList;
+import java.util.List;
+
public class Radials {
private static final String SCRIPT_PREFIX = "radial/";
@@ -45,7 +45,7 @@ public class Radials {
List options = new ArrayList<>();
try {
Scripts.invoke(SCRIPT_PREFIX + script, "getOptions", options, player, target, args);
- } catch (FileNotFoundException ex) {
+ } catch (ResourceException | ScriptException e) {
Log.w("Couldn't retrieve radial options from %s for object %s because the script couldn't be found", SCRIPT_PREFIX + script, target);
}
return options;
@@ -54,7 +54,7 @@ public class Radials {
public static void handleSelection(String script, Player player, SWGObject target, RadialItem selection, Object ... args) {
try {
Scripts.invoke(SCRIPT_PREFIX + script, "handleSelection", player, target, selection, args);
- } catch (FileNotFoundException ex) {
+ } catch (ResourceException | ScriptException e) {
Log.w("Can't handle selection %s on object %s because the script couldn't be found");
}
}
diff --git a/src/services/commands/BuffService.java b/src/services/commands/BuffService.java
index 1389b2b43..26cb8defe 100644
--- a/src/services/commands/BuffService.java
+++ b/src/services/commands/BuffService.java
@@ -27,20 +27,13 @@
***********************************************************************************/
package services.commands;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Stream;
-
import com.projectswg.common.concurrency.PswgBasicScheduledThread;
import com.projectswg.common.control.Service;
import com.projectswg.common.data.CRC;
import com.projectswg.common.debug.Assert;
import com.projectswg.common.debug.Log;
-
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
import intents.BuffIntent;
import intents.PlayerEventIntent;
import intents.SkillModIntent;
@@ -54,6 +47,13 @@ import services.commands.buff.BuffData;
import services.commands.buff.BuffMap;
import utilities.Scripts;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Stream;
+
public class BuffService extends Service {
/*
@@ -326,7 +326,7 @@ public class BuffService extends Service {
} else {
try {
Scripts.invoke("buffs/callback" + callback, callback, creature);
- } catch (FileNotFoundException ex) {
+ } catch (ResourceException | ScriptException e) {
Log.w("Callback script %s doesn't exist - buff %s won't behave as expected", callback, buffData.getName());
}
}
diff --git a/src/services/commands/CommandLauncher.java b/src/services/commands/CommandLauncher.java
index c3d813f31..822f1d36b 100644
--- a/src/services/commands/CommandLauncher.java
+++ b/src/services/commands/CommandLauncher.java
@@ -27,15 +27,10 @@
***********************************************************************************/
package services.commands;
-import java.io.FileNotFoundException;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.PriorityQueue;
-import java.util.Queue;
-
import com.projectswg.common.concurrency.PswgScheduledThreadPool;
import com.projectswg.common.debug.Log;
-
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
import intents.chat.ChatBroadcastIntent;
import intents.chat.ChatCommandIntent;
import network.packets.swg.zone.object_controller.CommandQueueDequeue;
@@ -52,6 +47,11 @@ import resources.server_info.DataManager;
import services.galaxy.GalacticManager;
import utilities.Scripts;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.PriorityQueue;
+import java.util.Queue;
+
public class CommandLauncher {
private final Map> combatQueueMap;
@@ -180,8 +180,11 @@ public class CommandLauncher {
}
} else {
try {
- Scripts.invoke("commands/generic/" + command.getDefaultScriptCallback(), "executeCommand", enqueued.getGalacticManager(), player, enqueued.getTarget(), enqueued.getRequest().getArguments());
- } catch (FileNotFoundException ex) {
+ Scripts.invoke("commands/generic/" + command.getDefaultScriptCallback(), "execute", enqueued.getGalacticManager(), player, enqueued.getTarget(), enqueued.getRequest().getArguments());
+ } catch (ResourceException e) {
+ // Script doesn't exist
+ } catch (ScriptException e) {
+ Log.a(e);
}
}
}
diff --git a/src/services/sui/SuiService.java b/src/services/sui/SuiService.java
index 181bc2272..2a5cd1d92 100644
--- a/src/services/sui/SuiService.java
+++ b/src/services/sui/SuiService.java
@@ -27,16 +27,10 @@
***********************************************************************************/
package services.sui;
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
import com.projectswg.common.control.Service;
import com.projectswg.common.debug.Log;
-
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
import intents.network.GalacticPacketIntent;
import intents.sui.SuiWindowIntent;
import network.packets.Packet;
@@ -51,6 +45,12 @@ import resources.sui.SuiComponent;
import resources.sui.SuiEvent;
import utilities.Scripts;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
public class SuiService extends Service {
private final Map> windows;
@@ -135,7 +135,7 @@ public class SuiService extends Service {
String script = window.getCallbackScript(callback);
try {
Scripts.invoke(script, callback, player, player.getCreatureObject(), event, parameters);
- } catch (FileNotFoundException ex) {
+ } catch (ResourceException | ScriptException e) {
Log.e("Callback script %s not found", script);
}
} else if (window.hasJavaCallback(callback)) {
diff --git a/src/utilities/Scripts.java b/src/utilities/Scripts.java
index e8ebb0cb7..6fce85e2d 100644
--- a/src/utilities/Scripts.java
+++ b/src/utilities/Scripts.java
@@ -27,71 +27,83 @@
***********************************************************************************/
package utilities;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
+import groovy.lang.Binding;
+import groovy.lang.Script;
+import groovy.util.GroovyScriptEngine;
+import groovy.util.ResourceException;
+import groovy.util.ScriptException;
+import main.ProjectSWG;
-import javax.script.Invocable;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-
-import com.projectswg.common.debug.Log;
+import java.io.IOException;
public class Scripts {
-
- private static final String SCRIPTS;
- private static final String EXTENSION;
- private static final ScriptEngine ENGINE;
- private static final Invocable INVOCABLE;
-
- static {
- ScriptEngineManager engineManager = new ScriptEngineManager();
- SCRIPTS = "scripts/";
- EXTENSION = ".js";
- ENGINE = engineManager.getEngineByName("nashorn");
- INVOCABLE = (Invocable) ENGINE;
- if (ENGINE == null) {
- Log.e("ScriptEngine is null!");
- } else {
- try {
- ENGINE.put("intentFactory", new IntentFactory());
- ENGINE.eval("var RadialOption = Java.type('resources.radial.RadialOption')");
- ENGINE.eval("var RadialItem = Java.type('resources.radial.RadialItem')");
- ENGINE.eval("var Log = Java.type('com.projectswg.common.debug.Log')");
- ENGINE.eval("var SuiWindow = Java.type('resources.sui.SuiWindow')");
- ENGINE.eval("var SuiButtons = Java.type('resources.sui.SuiButtons')");
- ENGINE.eval("var SuiEvent = Java.type('resources.sui.SuiEvent')");
- } catch (Throwable t) {
- Log.e(t);
- }
- }
- }
-
- // Prevents instantiation.
- private Scripts() {}
-
- /**
- * @param script name of the script, relative to the scripts folder.
- * @param function name of the specific function within the script.
- * @param args to pass to the function.
- * @return whatever the function returns. If the function doesn't have a return statement, this method returns {@code null}.
- * If an exception occurs, {@code null} is returned.
- * @throws java.io.FileNotFoundException if the script file wasn't found
- */
- @SuppressWarnings("unchecked")
- public static T invoke(String script, String function, Object... args) throws FileNotFoundException {
- try {
- ENGINE.eval(new InputStreamReader(new FileInputStream(SCRIPTS + script + EXTENSION), StandardCharsets.UTF_8));
- return (T) INVOCABLE.invokeFunction(function, args);
- } catch (ScriptException | NoSuchMethodException t) {
- Log.e("Error invoking script: " + script + " with function: " + function);
- Log.e(" Args: " + Arrays.toString(args));
- Log.e(t);
- return null;
- }
- }
-
+ private static GroovyScriptEngine groovyEngine;
+
+ static {
+ try {
+ groovyEngine = new GroovyScriptEngine("scripts/");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ if (groovyEngine == null)
+ throw new ProjectSWG.CoreException("Could not load the Groovy Script Engine!");
+ }
+
+ /**
+ * Invokes a method from the provided Groovy Script.
+ * @param scriptName name of the script, relative to the scripts folder.
+ * @param method name of the specific method within the script.
+ * @param args to pass to the method.
+ * @return expected return type of the script. If the method doesn't have a return statement, this method returns {@code null}.
+ * If an exception occurs, {@code null} is returned.
+ * @throws java.io.FileNotFoundException if the script file wasn't found
+ */
+ @SuppressWarnings("unchecked")
+ public static T invoke(String scriptName, String method, Object... args) throws ResourceException, ScriptException {
+ Script script = getScript(formatScriptName(scriptName));
+ return (script != null) ? (T) script.invokeMethod(method, args) : null;
+ }
+
+ /**
+ * Creates a binding from an array of variables. The name of the variable should lead the instance. An example would be:
+ *
  {@code setupScriptVariables("variableNameOne", variableOne, "variableNameTwo", variableTwo);}
+ * @param variables an array of variables. Variable names should lead the instance of the variable.
+ */
+ public static Binding createBindings(Object... variables) {
+ Binding binding = new Binding();
+
+ for (int i = 0; i < variables.length; i++) {
+ if (!(variables[i] instanceof String))
+ continue;
+
+ binding.setVariable((String) variables[i], variables[i++]);
+ }
+
+ return binding;
+ }
+
+ /**
+ * Creates the Groovy Script and returns it. The method uses the {@link GroovyScriptEngine}'s createScript method.
+ * A new {@link Binding} is passed to the created {@link Script} to ensure thread safety, providing a new instance of the generated {@link Script} for the accessing thread.
+ * @param scriptName Name of the script to load
+ * @return a unique instance of {@link Script}
+ */
+ public static Script getScript(String scriptName) throws ResourceException, ScriptException {
+ return getScript(scriptName, new Binding());
+ }
+
+ /**
+ * Creates the Groovy Script and returns it. The method uses the {@link GroovyScriptEngine}'s createScript method.
+ * @param scriptName name of the script to load
+ * @param binding the binding instance to use
+ * @return an instance of the obtained Groovy Script
+ */
+ public static Script getScript(String scriptName, Binding binding) throws ResourceException, ScriptException {
+ return groovyEngine.createScript(formatScriptName(scriptName), binding);
+ }
+
+ private static String formatScriptName(String name) {
+ return name.endsWith(".groovy") ? name : name + ".groovy";
+ }
}