Imitial support for running in a separate process
(Again)
This commit is contained in:
parent
fd9803c6f1
commit
61f3192760
5 changed files with 48 additions and 23 deletions
|
@ -17,6 +17,7 @@ import sznp.virtualcomputer.util.Scancode;
|
|||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class Computer {
|
||||
|
@ -60,9 +61,11 @@ public final class Computer {
|
|||
}
|
||||
session.setName("minecraft");
|
||||
VBoxEventHandler.getInstance().setup(machine.getId(), sender); //TODO: Sometimes null
|
||||
// machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); - This creates a *process*, we don't want that anymore
|
||||
synchronized (session) {
|
||||
machine.lockMachine(session, LockType.VM); // We want the machine inside *our* process <-- Need the VM type to have console access
|
||||
if (plugin.runEmbedded.get())
|
||||
machine.lockMachine(session, LockType.VM); //Run in our process <-- Need the VM type to have console access
|
||||
else
|
||||
machine.launchVMProcess(session, "headless", Collections.emptyList()); //Run in a separate process
|
||||
}
|
||||
} catch (VBoxException e) {
|
||||
if (e.getResultCode() == 0x80070005) { //lockMachine: "The object functionality is limited"
|
||||
|
@ -70,9 +73,6 @@ public final class Computer {
|
|||
sendMessage(sender, "§6Make sure that the server is running as root (sudo)");
|
||||
//TODO: If we have VirtualBox open, it won't close the server's port
|
||||
//TODO: "The object in question already exists." on second start
|
||||
//machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); //No privileges, start the 'old' way
|
||||
//session.getConsole().getDisplay().attachFramebuffer(0L, new IFramebuffer(new COMFrameBuffer(session.getConsole().getDisplay(), false)));
|
||||
//sendMessage(sender, "§6Computer started with slower screen. Run as root to use a faster method.");
|
||||
} else {
|
||||
sendMessage(sender, "§cFailed to start computer: " + e.getMessage());
|
||||
}
|
||||
|
@ -108,6 +108,7 @@ public final class Computer {
|
|||
handler.setProgress(progress);
|
||||
handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way?
|
||||
val fb = new MCFrameBuffer(console.getDisplay());
|
||||
if (plugin.runEmbedded.get())
|
||||
fb.start();
|
||||
String fbid = console.getDisplay().attachFramebuffer(0L,
|
||||
COMUtils.gimmeAFramebuffer(fb));
|
||||
|
|
|
@ -224,6 +224,7 @@ public class ComputerCommand extends ICommand2MC {
|
|||
switch (enableDisable) {
|
||||
case "enable":
|
||||
sender.sendMessage("§bEnabling plugin...");
|
||||
PluginMain.Instance.reloadConfig();
|
||||
PluginMain.Instance.pluginEnableInternal();
|
||||
sender.sendMessage("§bPlugin enabled! More info on console.");
|
||||
break;
|
||||
|
|
|
@ -48,9 +48,14 @@ public class PluginMain extends ButtonPlugin {
|
|||
*/
|
||||
public final ConfigData<Short> startID = getIConfig().getData("startID", (short) 0);
|
||||
/**
|
||||
* If true, uses the GPU to accelerate screen rendering. Requires root on Linux.
|
||||
* If true, uses the GPU to accelerate screen rendering. May require root on Linux.
|
||||
*/
|
||||
private final ConfigData<Boolean> useGPU = getIConfig().getData("useGPU", true);
|
||||
/**
|
||||
* The virtual machine will be hosted inside the server process if this option is enabled.
|
||||
* This can improve performance but may cause stability and other issues.
|
||||
*/
|
||||
public final ConfigData<Boolean> runEmbedded = getIConfig().getData("runEmbedded", true);
|
||||
/**
|
||||
* Determines the keyboard layout to use for /c show keyboard. Layouts can be defined in VirtualComputer/layouts/.
|
||||
*/
|
||||
|
|
|
@ -40,14 +40,15 @@ public class MachineEventHandler extends EventHandlerBase {
|
|||
sender.sendMessage("§cFailed to start computer! See the console for more details.");
|
||||
starting = false;
|
||||
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
|
||||
if (progress == null) return;
|
||||
progress.waitForCompletion(-1);
|
||||
if (progress != null && progress.getCompleted() && progress.getResultCode() != 0) {
|
||||
if (progress.getCompleted() && progress.getResultCode() != 0) {
|
||||
Logger l = PluginMain.Instance.getLogger();
|
||||
l.warning("Result code: " + Integer.toHexString(progress.getResultCode()));
|
||||
for (var info = progress.getErrorInfo(); info != null; info = info.getNext()) {
|
||||
l.warning("----------------");
|
||||
if (info.getResultCode() == 0x80004005 && info.getResultDetail() == 0xFFFFF88B)
|
||||
l.warning("The server cannot access the VirtualBox driver, run it with sudo. Make sure to only run plugins you trust.");
|
||||
l.warning("The server cannot access the VirtualBox driver. Either run it as root or disable the 'runEmbedded' config option. Make sure to only run plugins you trust as root.");
|
||||
else {
|
||||
l.warning("VBox: " + info.getText());
|
||||
l.warning("Component: " + info.getComponent());
|
||||
|
|
|
@ -22,7 +22,14 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
private final IDisplay display;
|
||||
private final Holder<IDisplaySourceBitmap> holder = new Holder<>();
|
||||
private BukkitTask tt;
|
||||
/**
|
||||
* Used when running embedded
|
||||
*/
|
||||
private Pointer pointer;
|
||||
/**
|
||||
* Used when not running embedded
|
||||
*/
|
||||
private byte[] screenImage; //TODO: Remove PluginMain.allpixels (and other PluginMain references)
|
||||
private int width;
|
||||
private int height;
|
||||
@Getter
|
||||
|
@ -38,7 +45,14 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
|
||||
synchronized (this) { //If a change occurs twice, then wait for it
|
||||
try {
|
||||
//System.out.println("Change: " + xOrigin + " " + yOrigin + " - " + width + " " + height);
|
||||
if (!PluginMain.Instance.runEmbedded.get()) { //Running separately
|
||||
this.width = (int) width;
|
||||
this.height = (int) height;
|
||||
if (screenImage == null || screenImage.length != width * height * 4)
|
||||
screenImage = new byte[(int) (width * height * 4)];
|
||||
updateScreen(screenImage);
|
||||
return;
|
||||
}
|
||||
display.querySourceBitmap(0L, holder);
|
||||
long[] ptr = new long[1], w = new long[1], h = new long[1], bpp = new long[1], bpl = new long[1], pf = new long[1];
|
||||
COMUtils.queryBitmapInfo(holder.value, ptr, w, h, bpp, bpl, pf);
|
||||
|
@ -46,9 +60,6 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
pointer = new Pointer(ptr[0]);
|
||||
this.width = (int) w[0];
|
||||
this.height = (int) h[0];
|
||||
//System.out.println("Actual sizes: " + this.width + " " + this.height);
|
||||
/*if (this.width > 1024 || this.height > 768)
|
||||
return;*/
|
||||
GPURenderer.update(pointer.getByteArray(0L, (int) (w[0] * h[0] * 4)), (int) w[0], (int) h[0], 0, 0, this.width, this.height);
|
||||
} else {
|
||||
PluginMain.allpixels = new Pointer(ptr[0]).getByteBuffer(0L, width * height * 4);
|
||||
|
@ -65,9 +76,7 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
e.printStackTrace();
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
} /*finally {
|
||||
System.out.println("Change finished");
|
||||
}*/
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -87,6 +96,13 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
@Override
|
||||
public void notifyUpdateImage(long x, long y, long width, long height, byte[] image) {
|
||||
System.out.println("Update image!");
|
||||
if (this.width == 0 || this.height == 0) {
|
||||
PluginMain.Instance.getLogger().warning("Received screen image before resolution change!");
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < height; i++) //Copy lines of the screen in a fast way
|
||||
System.arraycopy(image, (int) (i * width * 4), screenImage, (int) (x + y * this.width * 4), (int) width * 4);
|
||||
updateScreen(image);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
|
@ -105,14 +121,8 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
continue;
|
||||
}
|
||||
if (!running) return;
|
||||
//System.out.println("Update: " + x + " " + y + " - " + width + " " + height);
|
||||
Timing t = new Timing(); //TODO: Add support for only sending changed fragments
|
||||
GPURenderer.update(pointer.getByteArray(0L, this.width * this.height * 4), this.width, this.height, (int) 0, (int) 0, (int) width, (int) height);
|
||||
if (t.elapsedMS() > 60) //Typically 1ms max
|
||||
System.out.println("Update took " + t.elapsedMS() + "ms");
|
||||
updateScreen(pointer.getByteArray(0L, this.width * this.height * 4));
|
||||
shouldUpdate.set(false);
|
||||
/*else
|
||||
System.out.println("Update finished");*/
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException ignored) {
|
||||
|
@ -120,6 +130,13 @@ public class MCFrameBuffer implements IMCFrameBuffer {
|
|||
});
|
||||
}
|
||||
|
||||
private void updateScreen(byte[] pixels) {
|
||||
Timing t = new Timing(); //TODO: Add support for only sending changed fragments
|
||||
GPURenderer.update(pixels, this.width, this.height, (int) 0, (int) 0, (int) width, (int) height);
|
||||
if (t.elapsedMS() > 60) //Typically 1ms max
|
||||
PluginMain.Instance.getLogger().warning("Update took " + t.elapsedMS() + "ms");
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
synchronized (this) {
|
||||
running = false;
|
||||
|
|
Loading…
Reference in a new issue