Directly using VirtualBox from Java #5
6 changed files with 132 additions and 41 deletions
|
@ -32,6 +32,58 @@
|
|||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>XPCOM</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.virtualbox:VirtualBox-MSCOM</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>MSCOM</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<excludes>
|
||||
<exclude>org.virtualbox:VirtualBox</exclude>
|
||||
</excludes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
|
@ -74,6 +126,12 @@
|
|||
<groupId>net.md-5</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.virtualbox</groupId>
|
||||
<artifactId>VirtualBox-MSCOM</artifactId>
|
||||
<version>6.0</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
|
|
|
@ -9,7 +9,6 @@ import org.virtualbox_6_0.*;
|
|||
import sznp.virtualcomputer.events.MachineEventHandler;
|
||||
import sznp.virtualcomputer.events.VBoxEventHandler;
|
||||
import sznp.virtualcomputer.renderer.GPURenderer;
|
||||
import sznp.virtualcomputer.renderer.GPURendererInternal;
|
||||
import sznp.virtualcomputer.renderer.MCFrameBuffer;
|
||||
import sznp.virtualcomputer.util.Scancode;
|
||||
|
||||
|
@ -79,6 +78,8 @@ public final class Computer {
|
|||
public void onLock(CommandSender sender) {
|
||||
machine = session.getMachine(); // This is the Machine object we can work with
|
||||
final IConsole console = session.getConsole();
|
||||
if (handler != null)
|
||||
handler.disable();
|
||||
handler = new MachineEventHandler(Computer.this, sender);
|
||||
listener = handler.registerTo(console.getEventSource());
|
||||
IProgress progress = console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2
|
||||
|
@ -222,6 +223,7 @@ public final class Computer {
|
|||
}
|
||||
|
||||
public void pluginDisable(CommandSender ccs) {
|
||||
stopEvents();
|
||||
if (session.getState() == SessionState.Locked) {
|
||||
if (session.getMachine().getState().equals(MachineState.Running)) {
|
||||
ccs.sendMessage("§aSaving machine state...");
|
||||
|
|
|
@ -40,6 +40,7 @@ public class PluginMain extends JavaPlugin {
|
|||
*/
|
||||
//public static PXCLib pxc;
|
||||
public static boolean direct;
|
||||
public static boolean sendAll;
|
||||
|
||||
// Fired when plugin is first enabled
|
||||
@Override
|
||||
|
@ -48,6 +49,7 @@ public class PluginMain extends JavaPlugin {
|
|||
try {
|
||||
ConsoleCommandSender ccs = getServer().getConsoleSender();
|
||||
this.getCommand("computer").setExecutor(new Commands());
|
||||
sendAll = getConfig().getBoolean("sendAll", true);
|
||||
ccs.sendMessage("§bInitializing VirtualBox...");
|
||||
String vbpath = System.getProperty("os.name").toLowerCase().contains("mac")
|
||||
? "/Applications/VirtualBox.app/Contents/MacOS"
|
||||
|
@ -109,12 +111,14 @@ public class PluginMain extends JavaPlugin {
|
|||
@Override
|
||||
public void onDisable() {
|
||||
ConsoleCommandSender ccs = getServer().getConsoleSender();
|
||||
if (mousetask != null)
|
||||
mousetask.cancel();
|
||||
/*try {
|
||||
source.unregisterListener(listener);
|
||||
} catch (VBoxException e) { //"Listener was never registered"
|
||||
e.printStackTrace(); - VBox claims the listener was never registered (can double register as well)
|
||||
}*/
|
||||
if (listener != null)
|
||||
((VBoxEventHandler) listener.getTypedWrapped()).disable(); //The save progress wait locks with the event
|
||||
if (Computer.getInstance() != null)
|
||||
Computer.getInstance().pluginDisable(ccs);
|
||||
|
|
|
@ -37,7 +37,7 @@ public class MachineEventHandler extends EventHandlerBase {
|
|||
case PoweredOff:
|
||||
case Saved:
|
||||
if (starting) {
|
||||
sender.sendMessage("§cFailed to start computer! See the VM's log for more details.");
|
||||
sender.sendMessage("§cFailed to start computer! See the console for more details.");
|
||||
sender.sendMessage("§cMake sure that 2D and 3D acceleration is disabled.");
|
||||
starting = false;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
|
||||
|
|
|
@ -7,23 +7,29 @@ import org.bukkit.map.MapCanvas;
|
|||
import org.bukkit.map.MapPalette;
|
||||
import org.bukkit.map.MapRenderer;
|
||||
import org.bukkit.map.MapView;
|
||||
import sznp.virtualcomputer.PluginMain;
|
||||
import sznp.virtualcomputer.util.Timing;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class GPURenderer extends MapRenderer implements IRenderer {
|
||||
private byte[] buffer;
|
||||
private GPURendererInternal kernel;
|
||||
private final GPURendererInternal kernel;
|
||||
private WorldMap wmap;
|
||||
private int mapx, mapy;
|
||||
//Store at central location after conversion
|
||||
private static int[] colors_;
|
||||
private static int changedX, changedY, changedWidth, changedHeight;
|
||||
private int changedX = 0, changedY = 0, changedWidth = 640, changedHeight = 480;
|
||||
private static ArrayList<GPURenderer> renderers = new ArrayList<>();
|
||||
|
||||
public GPURenderer(short id, World world, int mapx, int mapy) throws Exception {
|
||||
MapView map = IRenderer.prepare(id, world);
|
||||
if (map == null) return; //Testing
|
||||
if (map == null) {
|
||||
kernel = null;
|
||||
return; //Testing
|
||||
}
|
||||
|
||||
if (colors_ == null) {
|
||||
Field field = MapPalette.class.getDeclaredField("colors");
|
||||
|
@ -40,8 +46,7 @@ public class GPURenderer extends MapRenderer implements IRenderer {
|
|||
field.setAccessible(true);
|
||||
wmap = (WorldMap) field.get(map);
|
||||
kernel = new GPURendererInternal(mapx, mapy, colors_);
|
||||
|
||||
//System.setProperty("com.codegen.config.enable.NEW", "true");
|
||||
renderers.add(this);
|
||||
|
||||
map.addRenderer(this);
|
||||
}
|
||||
|
@ -56,16 +61,35 @@ public class GPURenderer extends MapRenderer implements IRenderer {
|
|||
field.setAccessible(true);
|
||||
buffer = (byte[]) field.get(canvas);
|
||||
}
|
||||
if (!PluginMain.sendAll) {
|
||||
synchronized (kernel) {
|
||||
if (changedX >= (mapx + 1) * 128 || changedY >= (mapy + 1) * 128
|
||||
|| changedX + changedWidth < mapx * 128 || changedY + changedHeight < mapy * 128)
|
||||
return; //No change for this map - TODO: Test
|
||||
int x = changedX % 128;
|
||||
int y = changedY % 128;
|
||||
int w = x + changedWidth >= 128 ? 128 - x - 1 : changedWidth;
|
||||
int h = y + changedHeight >= 128 ? 128 - y - 1 : changedHeight;
|
||||
|| changedX + changedWidth < mapx * 128 || changedY + changedHeight < mapy * 128) {
|
||||
kernel.ignoreChange();
|
||||
return; //No change for this map
|
||||
}
|
||||
}
|
||||
//System.out.println("changed: (" + changedX + ", " + changedY + ") " + changedWidth + "x" + changedHeight);
|
||||
//System.out.println("map: (" + mapx + ", " + mapy + ")");
|
||||
int x = changedX - mapx * 128;
|
||||
int y = changedY - mapy * 128;
|
||||
if (x < 0) x = 0;
|
||||
if (y < 0) y = 0;
|
||||
int xx = x + changedWidth >= 128 ? 127 : x + changedWidth;
|
||||
int yy = y + changedHeight >= 128 ? 127 : y + changedHeight;
|
||||
//System.out.println("local: ("+x+", "+y+") "+w+"x"+h);
|
||||
kernel.render(buffer);
|
||||
wmap.flagDirty(x, y);
|
||||
wmap.flagDirty(x + w, y + h); // Send the changes only
|
||||
wmap.flagDirty(xx, yy); // Send the changes only
|
||||
changedX = Integer.MAX_VALUE; //Finished rendering
|
||||
changedY = Integer.MAX_VALUE; //TODO: Render as soon as we receive new image
|
||||
changedWidth = -1; //Finished rendering
|
||||
changedHeight = -1;
|
||||
} else {
|
||||
kernel.render(buffer);
|
||||
wmap.flagDirty(0, 0);
|
||||
wmap.flagDirty(127, 127); // Send everything
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -74,10 +98,20 @@ public class GPURenderer extends MapRenderer implements IRenderer {
|
|||
}
|
||||
|
||||
public static void update(byte[] pixels, int width, int height, int changedX, int changedY, int changedWidth, int changedHeight) {
|
||||
GPURenderer.changedX = changedX;
|
||||
GPURenderer.changedY = changedY;
|
||||
GPURenderer.changedWidth = changedWidth;
|
||||
GPURenderer.changedHeight = changedHeight;
|
||||
GPURendererInternal.setPixels(pixels, width, height);
|
||||
for (GPURenderer r : renderers) {
|
||||
synchronized (r.kernel) {
|
||||
if (!PluginMain.sendAll) {
|
||||
if (changedX < r.changedX)
|
||||
r.changedX = changedX;
|
||||
if (changedY < r.changedY)
|
||||
r.changedY = changedY;
|
||||
if (changedWidth > r.changedWidth)
|
||||
r.changedWidth = changedWidth;
|
||||
if (changedHeight > r.changedHeight)
|
||||
r.changedHeight = changedHeight;
|
||||
}
|
||||
r.kernel.setPixels(pixels, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,9 +4,6 @@ import com.aparapi.Kernel;
|
|||
import com.aparapi.Range;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
//Accessing the GPURenderer results in ArrayIndexOutOfBoundsExceptions - IT'S THE LAMBDAS
|
||||
public class GPURendererInternal extends Kernel {
|
||||
private int mapx;
|
||||
|
@ -21,7 +18,6 @@ public class GPURendererInternal extends Kernel {
|
|||
private Range range;
|
||||
@Getter
|
||||
private boolean rendered;
|
||||
private static ArrayList<GPURendererInternal> renderers = new ArrayList<>();
|
||||
|
||||
//public static byte[] test=new byte[1]; - LAMBDAS
|
||||
public GPURendererInternal(int mapx, int mapy, int[] colors) {
|
||||
|
@ -34,8 +30,6 @@ public class GPURendererInternal extends Kernel {
|
|||
pixels = new byte[1];
|
||||
width = height = 0;
|
||||
rendered = false;
|
||||
|
||||
renderers.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -94,17 +88,12 @@ public class GPURendererInternal extends Kernel {
|
|||
private static final int GREEN = 1;
|
||||
private static final int BLUE = 0;
|
||||
|
||||
@SuppressWarnings("Convert2Lambda") //Aparapi fails with lambdas
|
||||
static void setPixels(byte[] pixels, int width, int height) {
|
||||
renderers.forEach(new Consumer<GPURendererInternal>() {
|
||||
@Override //IT'S THE LAMBDAS (exception)
|
||||
public void accept(GPURendererInternal r) {
|
||||
r.pixels = pixels;
|
||||
r.width = width;
|
||||
r.height = height;
|
||||
r.rendered = false;
|
||||
}
|
||||
});
|
||||
//Aparapi fails with lambdas
|
||||
void setPixels(byte[] pixels, int width, int height) {
|
||||
this.pixels = pixels;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
rendered = false;
|
||||
}
|
||||
|
||||
void render(byte[] buffer) {
|
||||
|
@ -113,4 +102,8 @@ public class GPURendererInternal extends Kernel {
|
|||
put(buffer).put(pixels).execute(range).get(buffer);
|
||||
rendered = true;
|
||||
}
|
||||
|
||||
void ignoreChange() {
|
||||
rendered = true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue