diff --git a/README.md b/README.md
index cb06d1c82..aacf53c97 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ Some dependencies are required:
permission system for Bukkit
- [Permissions](http://forums.bukkit.org/threads/1403/) provides an
permission system for Bukkit
+- worldeditsunrhino.jar is included
For links to downloads, check out
[http://wiki.sk89q.com/wiki/WorldEdit/Development](http://wiki.sk89q.com/wiki/WorldEdit/Development)
diff --git a/build.xml b/build.xml
index 82d814618..45cd0dde9 100644
--- a/build.xml
+++ b/build.xml
@@ -16,6 +16,7 @@
+
@@ -46,7 +47,9 @@
-
+
+
+
diff --git a/contrib/sunrhino/README.txt b/contrib/sunrhino/README.txt
new file mode 100644
index 000000000..29dd20bd6
--- /dev/null
+++ b/contrib/sunrhino/README.txt
@@ -0,0 +1,3 @@
+This contains sources for an implementation of the Sun Rhino engine for
+WorldEdit. However, this Rhino version is an internal component of
+the Sun JVM and thus it is implementation specific.
\ No newline at end of file
diff --git a/contrib/sunrhino/build.xml b/contrib/sunrhino/build.xml
new file mode 100644
index 000000000..f710301e6
--- /dev/null
+++ b/contrib/sunrhino/build.xml
@@ -0,0 +1,47 @@
+
+ Sun Rhino implementation.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoContextFactory.java b/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoContextFactory.java
new file mode 100644
index 000000000..aad0fa2ae
--- /dev/null
+++ b/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoContextFactory.java
@@ -0,0 +1,61 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see .
+ */
+
+package com.sk89q.worldedit.scripting;
+
+import sun.org.mozilla.javascript.internal.*;
+
+public class SunRhinoContextFactory extends ContextFactory {
+ protected int timeLimit;
+
+ public SunRhinoContextFactory(int timeLimit) {
+ this.timeLimit = timeLimit;
+ }
+
+ protected Context makeContext() {
+ RhinoContext cx = new RhinoContext(this);
+ cx.setInstructionObserverThreshold(10000);
+ return cx;
+ }
+
+ protected void observeInstructionCount(Context cx, int instructionCount) {
+ RhinoContext mcx = (RhinoContext)cx;
+ long currentTime = System.currentTimeMillis();
+
+ if (currentTime - mcx.startTime > timeLimit) {
+ throw new Error("Script timed out (" + timeLimit + "ms)");
+ }
+ }
+
+ protected Object doTopCall(Callable callable, Context cx, Scriptable scope,
+ Scriptable thisObj, Object[] args) {
+ RhinoContext mcx = (RhinoContext)cx;
+ mcx.startTime = System.currentTimeMillis();
+
+ return super.doTopCall(callable, cx, scope, thisObj, args);
+ }
+
+ private static class RhinoContext extends Context {
+ long startTime;
+
+ public RhinoContext(ContextFactory factory) {
+ super();
+ }
+ }
+}
\ No newline at end of file
diff --git a/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoCraftScriptEngine.java b/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoCraftScriptEngine.java
new file mode 100644
index 000000000..4706b69e4
--- /dev/null
+++ b/contrib/sunrhino/src/com/sk89q/worldedit/scripting/SunRhinoCraftScriptEngine.java
@@ -0,0 +1,90 @@
+// $Id$
+/*
+ * WorldEdit
+ * Copyright (C) 2010 sk89q
+ *
+ * This program 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.
+ *
+ * This program 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 this program. If not, see .
+*/
+
+package com.sk89q.worldedit.scripting;
+
+import java.util.Map;
+import javax.script.ScriptException;
+import com.sk89q.worldedit.WorldEdit;
+import com.sk89q.worldedit.WorldEditException;
+import sun.org.mozilla.javascript.internal.*;
+
+public class SunRhinoCraftScriptEngine implements CraftScriptEngine {
+ private int timeLimit;
+
+ @Override
+ public void setTimeLimit(int milliseconds) {
+ timeLimit = milliseconds;
+ }
+
+ @Override
+ public int getTimeLimit() {
+ return timeLimit;
+ }
+
+ @Override
+ public Object evaluate(final String script, final String filename,
+ final Map args)
+ throws ScriptException, Throwable {
+ SunRhinoContextFactory factory = new SunRhinoContextFactory(timeLimit);
+ factory.initApplicationClassLoader(WorldEdit.class.getClassLoader());
+
+ try {
+ return factory.call(new ContextAction() {
+ public Object run(Context cx) {
+ Scriptable topLevel = new ImporterTopLevel(cx);
+ Scriptable scope = cx.initStandardObjects();
+ topLevel.setParentScope(scope);
+
+ for (Map.Entry entry : args.entrySet()) {
+ ScriptableObject.putProperty(scope, entry.getKey(),
+ Context.javaToJS(entry.getValue(), scope));
+ }
+
+ return cx.evaluateString(topLevel, script, filename, 1, null);
+ }
+ });
+ } catch (Error e) {
+ throw new ScriptException(e.getMessage());
+ } catch (RhinoException e) {
+ if (e instanceof WrappedException) {
+ Throwable cause = ((WrappedException)e).getCause();
+ if (cause instanceof WorldEditException) {
+ throw ((WrappedException)e).getCause();
+ }
+ }
+
+ String msg;
+ int line = (line = e.lineNumber()) == 0 ? -1 : line;
+
+ if (e instanceof JavaScriptException) {
+ msg = String.valueOf(((JavaScriptException)e).getValue());
+ } else {
+ msg = e.getMessage();
+ }
+
+ ScriptException scriptException =
+ new ScriptException(msg, e.sourceName(), line);
+ scriptException.initCause(e);
+
+ throw scriptException;
+ }
+ }
+
+}
diff --git a/lib/worldeditsunrhino.jar b/lib/worldeditsunrhino.jar
new file mode 100644
index 000000000..f5d9f656b
Binary files /dev/null and b/lib/worldeditsunrhino.jar differ
diff --git a/src/com/sk89q/worldedit/WorldEdit.java b/src/com/sk89q/worldedit/WorldEdit.java
index fe7dc6879..54e83aa0f 100644
--- a/src/com/sk89q/worldedit/WorldEdit.java
+++ b/src/com/sk89q/worldedit/WorldEdit.java
@@ -856,12 +856,17 @@ public class WorldEdit {
new CraftScriptContext(this, server, config, session, player, args);
CraftScriptEngine engine = null;
-
+
try {
engine = new RhinoCraftScriptEngine();
} catch (NoClassDefFoundError e) {
- player.printError("Please install a scripting engine.");
- return;
+ try {
+ engine = new SunRhinoCraftScriptEngine();
+ } catch (NoClassDefFoundError e2) {
+ player.printError("Failed to find an installed script engine.");
+ player.printError("Please see http://wiki.sk89q.com/wiki/WorldEdit/Installation");
+ return;
+ }
}
engine.setTimeLimit(config.scriptTimeout);