Skip to content

Commit a00fbbf

Browse files
committed
Added spigot event listening! Woooo!
1 parent bfcf7ef commit a00fbbf

7 files changed

Lines changed: 181 additions & 27 deletions

File tree

ReadMe.md

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,39 @@
11
# RepCraft
22
Modern JavaScript for modern minecraft
33

4-
This project is meant to address some issues I have with scriptcraft:
4+
## Disclaimers
5+
This project is in pre-release state.<br/>
6+
Feature may work, but are not fully tested<br/>
7+
Be aware that ScriptCraft compatibility is not a priority<br/>
58

6-
- Modern js (classes, let/const, arrow-functions, typed arrays, networking)
9+
## Why is this a thing?
10+
This project is addresses issues I have with scriptcraft:
11+
12+
- No support for modern JS (const, let, class, arrow-functions, es modules ..)
713
- Unfinished auto-complete
814
- Not enough debugging capabilities
9-
- Not enough standardized documentation
10-
- Not enough documented caveats
15+
- Not enough documentation
1116
- Relies on deprecated java APIs
12-
- It evals every JS file within its plugin structure
17+
- Evals scripts that don't need to be loaded
1318

1419
This project is a SpigotMC API `JavaPlugin`<br/>
1520
It gets its capabilities from GraalVM, a modern polyglot virtual machine<br/>
1621
with support for a BUNCH of languages, including Java, and JavaScript.
1722

23+
## Current features
24+
- ES Module `package.json` based plugins
25+
- Java interop
26+
- /js live eval command
27+
28+
## Planned features
29+
- Sandboxed permissions per-plugin
30+
- Persistent storage per-plugin
31+
- Debug hot-reloading (file-watch) per-plugin
32+
- Persistent debug state (after reload, states can be recovered)
33+
- WebSocket / WebSocketServer
34+
- Non-blocking TCP/UDP sockets
35+
- WebWorker implementation
36+
1837
## Installing
1938
This plugin makes use of GraalVM<br/>
2039
You need to run spigot using Graal's JVM

pom.xml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,8 @@
8787
<version>0.8.1</version>
8888
</plugin>
8989
</plugins>
90-
<!-- <resources>
91-
<resource>
92-
<directory>src/main/java</directory>
93-
<includes>
94-
<include>**/*.properties</include>
95-
</includes>
96-
</resource>
97-
</resources> -->
90+
<resources>
91+
</resources>
9892
</build>
9993
<reporting>
10094
<plugins>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.roguecircuitry.repcraft;
2+
3+
import org.graalvm.polyglot.Value;
4+
5+
public class JSEventListener {
6+
public String type;
7+
public Value func;
8+
public JSEventListener (String eType, Value cb) {
9+
this.type = eType;
10+
this.func = cb;
11+
}
12+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.roguecircuitry.repcraft;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import org.bukkit.event.Event;
7+
import org.bukkit.event.EventPriority;
8+
import org.bukkit.event.HandlerList;
9+
import org.bukkit.event.Listener;
10+
import org.bukkit.event.entity.EntityAirChangeEvent;
11+
import org.bukkit.plugin.RegisteredListener;
12+
import org.graalvm.polyglot.Value;
13+
14+
public class JSEvents implements Listener {
15+
RepCraft master;
16+
public List<JSEventListener> listeners;
17+
18+
public JSEvents(RepCraft master) {
19+
this.master = master;
20+
21+
this.listeners = new ArrayList<JSEventListener>();
22+
23+
this.master.jsBinding.putMember("Events", this);
24+
RegisteredListener registeredListener = new RegisteredListener(
25+
this,
26+
(listener, event) -> onEvent(event),
27+
EventPriority.NORMAL,
28+
master,
29+
false
30+
);
31+
32+
for (HandlerList handler : HandlerList.getHandlerLists()) {
33+
handler.register(registeredListener);
34+
}
35+
}
36+
37+
public void onEvent (Event e) {
38+
if (e instanceof EntityAirChangeEvent) return;
39+
for (JSEventListener l : this.listeners) {
40+
if (l.type.equals(e.getClass().getSimpleName())) {
41+
l.func.execute(e);
42+
}
43+
}
44+
}
45+
46+
public void on (Class classType, Value f) {
47+
this.listeners.add(new JSEventListener(classType.getSimpleName(), f));
48+
}
49+
}

src/main/java/com/roguecircuitry/repcraft/RepCraft.java

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,24 @@
44
import java.io.FileFilter;
55
import java.io.FileReader;
66
import java.nio.file.Paths;
7+
import java.util.ArrayList;
8+
import java.util.List;
79

810
import com.google.gson.JsonObject;
911
import com.google.gson.JsonParser;
1012
import com.google.gson.stream.JsonReader;
13+
import com.roguecircuitry.repcraft.resources.DefaultResources;
1114

15+
import org.bukkit.event.EventPriority;
16+
import org.bukkit.plugin.RegisteredListener;
1217
import org.bukkit.plugin.java.JavaPlugin;
1318

1419
import org.graalvm.polyglot.Context;
1520
import org.graalvm.polyglot.Value;
1621
import org.graalvm.polyglot.Source;
1722

18-
/**RepCraft main Spigot plugin class
19-
* Most of the core logic is in here
23+
/**
24+
* RepCraft main Spigot plugin class Most of the core logic is in here
2025
*/
2126
public final class RepCraft extends JavaPlugin {
2227
Context ctx;
@@ -33,12 +38,38 @@ private void critial(String msg) {
3338

3439
@Override
3540
public void onEnable() {
41+
// Initialize the JavaScript engine/bindings
3642
System.out.println("[RepCraft] Initializing GraalVM js context!");
3743
this.ctx = Context.newBuilder("js").allowAllAccess(true).build();
3844
this.jsBinding = this.ctx.getBindings("js");
3945

46+
getServer().getPluginManager().registerEvents(new JSEvents(this), this);
47+
48+
// Create a JSON parser so we can load package.json's for all of the plugins
4049
this.jsonParser = new JsonParser();
4150

51+
File repcraftDir = Paths.get("repcraft").toAbsolutePath().toFile();
52+
List<File> sources = new ArrayList<File>();
53+
if (!repcraftDir.exists()) {
54+
if (!repcraftDir.mkdir()) {
55+
this.critial("Could not create <spigot>/repcomm ! This is required. Disabling.");
56+
return;
57+
}
58+
String resFromPath = "/com/roguecircuitry/repcraft/resources/";
59+
60+
// Unpack necessary js
61+
File unpacked = new File(repcraftDir, "repcraft.mjs");
62+
DefaultResources.unpackResTo(resFromPath + "repcraft.mjs", unpacked, true);
63+
sources.add(unpacked);
64+
} else {
65+
sources.add(new File(repcraftDir, "repcraft.mjs"));
66+
}
67+
for (File s : sources) {
68+
if (this.loadSource(s)) {
69+
System.err.println("Loaded " + s.getAbsolutePath());
70+
}
71+
}
72+
4273
File jsPluginsDir = Paths.get("repcraft/js-plugins").toAbsolutePath().toFile();
4374

4475
if (jsPluginsDir.exists()) {
@@ -55,7 +86,7 @@ public void onEnable() {
5586
this.getCommand("js").setExecutor(this.jsc);
5687
}
5788

58-
public void loadPluginsFrom (File jsPluginsDir) {
89+
public void loadPluginsFrom(File jsPluginsDir) {
5990
File[] subdirs = jsPluginsDir.listFiles(new FileFilter() {
6091
public boolean accept(File f) {
6192
return f.isDirectory();
@@ -83,32 +114,33 @@ public boolean loadPlugin(File packageJson, File pluginSubDir) {
83114
File jsPluginFile;
84115

85116
try {
86-
pkgJson = this.jsonParser.parse(
87-
new JsonReader(
88-
new FileReader(
89-
packageJson
90-
)
91-
)
92-
).getAsJsonObject();
117+
pkgJson = this.jsonParser.parse(new JsonReader(new FileReader(packageJson))).getAsJsonObject();
93118
} catch (Exception ex) {
94119
// Suppress, file doesn't exist , no biggy :)
95120
return false;
96121
}
97122
// Skip package.json that don't have "main" in them
98-
if (!pkgJson.has("main")) return false;
123+
if (!pkgJson.has("main"))
124+
return false;
99125

100126
pkgJsonMain = pkgJson.get("main").getAsString();
101127

102128
jsPluginFile = new File(pluginSubDir.getAbsoluteFile() + "/" + pkgJsonMain);
103-
if (!jsPluginFile.exists()) {
129+
130+
if (!this.loadSource(jsPluginFile)) {
104131
System.err.println("Couldn't import 'main' : " + jsPluginFile.toPath() + ", ignoring!");
105132
return false;
106133
}
134+
return true;
135+
}
136+
137+
public boolean loadSource(File source) {
138+
if (!source.exists())
139+
return false;
107140
try {
108-
Source src = Source.newBuilder("js", jsPluginFile).build();
141+
Source src = Source.newBuilder("js", source).build();
109142
this.ctx.eval(src);
110143
} catch (Exception e) {
111-
// Just skip this script
112144
e.printStackTrace();
113145
return false;
114146
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.roguecircuitry.repcraft.resources;
2+
3+
import java.io.File;
4+
import java.io.FileNotFoundException;
5+
import java.io.FileOutputStream;
6+
import java.io.IOException;
7+
import java.io.InputStream;
8+
9+
public class DefaultResources {
10+
public static void unpackResTo(String resourceName, File resourceDestination, boolean log) {
11+
InputStream is = DefaultResources.getRes(resourceName);
12+
if (is == null) {
13+
System.err.println("Couldn't find resource to unpack: " + resourceName);
14+
return;
15+
}
16+
int readBytes = 0;
17+
byte[] buffer = new byte[4096];
18+
FileOutputStream fos = null;
19+
20+
try {
21+
fos = new FileOutputStream(resourceDestination);
22+
while ((readBytes = is.read(buffer)) > 0) {
23+
fos.write(buffer, 0, readBytes);
24+
}
25+
if (log) {
26+
System.out.println("Unpacked " + resourceName);
27+
}
28+
} catch (FileNotFoundException fnfe) {
29+
System.err.println("Couldn't unpack " + resourceName + " to " + resourceDestination.getName() + " : " + fnfe);
30+
} catch (IOException e) {
31+
System.err.println("Error while unpacking " + resourceName + " to " + resourceDestination.getName() + " : " + e);
32+
} finally {
33+
try {
34+
fos.close();
35+
is.close();
36+
} catch (Exception e) {
37+
//Fuck off
38+
}
39+
}
40+
return;
41+
}
42+
43+
public static InputStream getRes(String key) {
44+
return DefaultResources.class.getResourceAsStream(key);
45+
}
46+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+

0 commit comments

Comments
 (0)