Directly using VirtualBox from Java #5

Merged
NorbiPeti merged 60 commits from directvb into master 2019-04-18 23:29:21 +00:00
6 changed files with 132 additions and 41 deletions
Showing only changes of commit 99e02f8e7b - Show all commits

View file

@ -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>
@ -75,6 +127,12 @@
</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>
<artifactId>craftbukkit</artifactId>

View file

@ -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...");

View file

@ -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,13 +111,15 @@ public class PluginMain extends JavaPlugin {
@Override
public void onDisable() {
ConsoleCommandSender ccs = getServer().getConsoleSender();
mousetask.cancel();
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)
}*/
((VBoxEventHandler) listener.getTypedWrapped()).disable(); //The save progress wait locks with the event
if (listener != null)
((VBoxEventHandler) listener.getTypedWrapped()).disable(); //The save progress wait locks with the event
if (Computer.getInstance() != null)
Computer.getInstance().pluginDisable(ccs);
ccs.sendMessage("§aHuh.");

View file

@ -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, () -> {

View file

@ -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 (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;
kernel.render(buffer);
wmap.flagDirty(x, y);
wmap.flagDirty(x + w, y + h); // Send the changes only
if (!PluginMain.sendAll) {
synchronized (kernel) {
if (changedX >= (mapx + 1) * 128 || changedY >= (mapy + 1) * 128
|| 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(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);
}
}
}
}

View file

@ -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;
}
}