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 52 additions and 51 deletions
Showing only changes of commit d35c2bf4b3 - Show all commits

View file

@ -113,13 +113,7 @@ public class Commands implements CommandExecutor {
+ " [\"\",{\"text\":\" [Ctrl]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key ControlLeft\"}},{\"text\":\" [Alt]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key AltLeft\"}},{\"text\":\" [Space]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Space\"}},{\"text\":\" [AltGr]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key AltRight\"}},{\"text\":\" [Ctrl]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key ControlRight\"}}]"); + " [\"\",{\"text\":\" [Ctrl]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key ControlLeft\"}},{\"text\":\" [Alt]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key AltLeft\"}},{\"text\":\" [Space]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Space\"}},{\"text\":\" [AltGr]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key AltRight\"}},{\"text\":\" [Ctrl]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key ControlRight\"}}]");
break; break;
case "mouse": case "mouse":
if (!MouseLockerPlayerListener.LockedPlayers.containsKey(sender)) { MouseLockerPlayerListener.toggleLock((Player) sender);
MouseLockerPlayerListener.LockedPlayers.put((Player) sender, ((Player) sender).getLocation());
sender.sendMessage("§aMouse locked.");
} else {
MouseLockerPlayerListener.LockedPlayers.remove(sender);
sender.sendMessage("§bMouse unlocked.");
}
break; break;
case "mspeed": case "mspeed":
case "mousespeed": case "mousespeed":

View file

@ -76,13 +76,12 @@ public final class Computer {
public void onLock(CommandSender sender) { public void onLock(CommandSender sender) {
machine = session.getMachine(); // This is the Machine object we can work with machine = session.getMachine(); // This is the Machine object we can work with
final IConsole console = session.getConsole(); final IConsole console = session.getConsole();
handler = new MachineEventHandler(Computer.this); handler = new MachineEventHandler(Computer.this, sender);
listener = handler.registerTo(console.getEventSource()); listener = handler.registerTo(console.getEventSource());
IProgress progress = console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2 IProgress progress = console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2
handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way? handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way?
console.getDisplay().attachFramebuffer(0L, console.getDisplay().attachFramebuffer(0L,
new IFramebuffer(new MCFrameBuffer(console.getDisplay(), true))); new IFramebuffer(new MCFrameBuffer(console.getDisplay(), true)));
sendMessage(sender, "§eComputer started.");
} }
private void sendMessage(@Nullable CommandSender sender, String message) { private void sendMessage(@Nullable CommandSender sender, String message) {
@ -192,20 +191,20 @@ public final class Computer {
UpdateMouse(sender, x, y, z, w, mbs, false); UpdateMouse(sender, x, y, z, w, mbs, false);
} }
public void onMachineStop() { public void onMachineStart(CommandSender sender) {
System.out.println("Unlocking machine..."); sendMessage(sender, "§eComputer started.");
}
public void onMachineStop(CommandSender sender) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (session.getState() == SessionState.Locked) { if (session.getState() == SessionState.Locked) {
System.out.println("Unlocking...");
session.unlockMachine(); //Needs to be outside of the event handler session.unlockMachine(); //Needs to be outside of the event handler
System.out.println("Machine unlocked.");
} }
}); });
System.out.println("Setting pixels...");
GPURendererInternal.setPixels(new byte[1], 0, 0); //Black screen GPURendererInternal.setPixels(new byte[1], 0, 0); //Black screen
System.out.println("Stopping events...");
stopEvents(); stopEvents();
plugin.getLogger().info("Computer powered off."); MouseLockerPlayerListener.computerStop();
sendMessage(sender, "§eComputer powered off.");
} }
public void stopEvents() { public void stopEvents() {

View file

@ -2,14 +2,17 @@ package sznp.virtualcomputer;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
public class MouseLockerPlayerListener implements Runnable { public class MouseLockerPlayerListener implements Runnable, Listener {
public static Map<Player, Location> LockedPlayers = new HashMap<>(); private static final Map<Player, Location> LockedPlayers = new HashMap<>();
public static float LockedSpeed = 5; public static float LockedSpeed = 5;
@Override @Override
@ -28,4 +31,23 @@ public class MouseLockerPlayerListener implements Runnable {
entry.getKey().teleport(entry.getValue(), TeleportCause.PLUGIN); entry.getKey().teleport(entry.getValue(), TeleportCause.PLUGIN);
} }
} }
@EventHandler
public void onPlayerLeave(PlayerQuitEvent event) {
LockedPlayers.remove(event.getPlayer());
}
public static void toggleLock(Player player) {
if (!MouseLockerPlayerListener.LockedPlayers.containsKey(player)) {
MouseLockerPlayerListener.LockedPlayers.put(player, player.getLocation());
player.sendMessage("§aMouse locked.");
} else {
MouseLockerPlayerListener.LockedPlayers.remove(player);
player.sendMessage("§bMouse unlocked.");
}
}
public static void computerStop() {
LockedPlayers.clear();
}
} }

View file

@ -1,6 +1,7 @@
package sznp.virtualcomputer; package sznp.virtualcomputer;
import jnr.ffi.LibraryLoader; import jnr.ffi.LibraryLoader;
import lombok.val;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
@ -92,7 +93,9 @@ public class PluginMain extends JavaPlugin {
ccs.sendMessage("§6Compatibility error, using slower renderer"); ccs.sendMessage("§6Compatibility error, using slower renderer");
} }
ccs.sendMessage("§bLoaded!"); ccs.sendMessage("§bLoaded!");
mousetask = getServer().getScheduler().runTaskTimer(this, new MouseLockerPlayerListener(), 0, 0); val mlpl = new MouseLockerPlayerListener();
mousetask = getServer().getScheduler().runTaskTimer(this, mlpl, 0, 0);
getServer().getPluginManager().registerEvents(mlpl, this);
} catch (final Exception e) { } catch (final Exception e) {
e.printStackTrace(); e.printStackTrace();

View file

@ -1,6 +1,7 @@
package sznp.virtualcomputer.events; package sznp.virtualcomputer.events;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.virtualbox_6_0.IProgressTaskCompletedEvent; import org.virtualbox_6_0.IProgressTaskCompletedEvent;
import org.virtualbox_6_0.IStateChangedEvent; import org.virtualbox_6_0.IStateChangedEvent;
@ -9,17 +10,18 @@ import sznp.virtualcomputer.Computer;
public class MachineEventHandler extends EventHandlerBase { public class MachineEventHandler extends EventHandlerBase {
private final Computer computer; private final Computer computer;
private final CommandSender sender;
private boolean starting = false; private boolean starting = false;
public MachineEventHandler(Computer computer) { public MachineEventHandler(Computer computer, CommandSender sender) {
super(ImmutableMap.of(VBoxEventType.OnStateChanged, IStateChangedEvent.class, super(ImmutableMap.of(VBoxEventType.OnStateChanged, IStateChangedEvent.class,
VBoxEventType.OnProgressTaskCompleted, IProgressTaskCompletedEvent.class)); VBoxEventType.OnProgressTaskCompleted, IProgressTaskCompletedEvent.class));
this.computer = computer; this.computer = computer;
this.sender = sender;
} }
@EventHandler @EventHandler
public void handleStateChange(IStateChangedEvent event) { //https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#a80b08f71210afe16038e904a656ed9eb public void handleStateChange(IStateChangedEvent event) { //https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#a80b08f71210afe16038e904a656ed9eb
System.out.println("State event: " + event.getState());
switch (event.getState()) { switch (event.getState()) {
case Stuck: case Stuck:
computer.Stop(null); computer.Stop(null);
@ -27,17 +29,18 @@ public class MachineEventHandler extends EventHandlerBase {
case PoweredOff: case PoweredOff:
case Saved: case Saved:
if (starting) { if (starting) {
System.out.println("Failed to start computer! See the VM's log for more details."); sender.sendMessage("§cFailed to start computer! See the VM's log for more details.");
starting = false; //TODO: Sender sender.sendMessage("§cMake sure that 2D and 3D acceleration is disabled.");
starting = false;
} }
computer.onMachineStop(); computer.onMachineStop(sender);
break; break;
case Starting: case Starting:
starting = true; starting = true;
break; break;
case Running: case Running:
System.out.println("Computer is running.");
starting = false; starting = false;
computer.onMachineStart(sender);
break; break;
} }
} }

View file

@ -39,6 +39,7 @@ public class MCFrameBuffer implements IFramebuffer {
@Override @Override
public long[] getCapabilities(long[] arg0) { public long[] getCapabilities(long[] arg0) {
try { try {
System.out.println("Capabilities queried");
System.out.println("Capabilities: " + Arrays.toString(arg0)); System.out.println("Capabilities: " + Arrays.toString(arg0));
return new long[]{FramebufferCapabilities.UpdateImage.value()}; return new long[]{FramebufferCapabilities.UpdateImage.value()};
} }
@ -94,24 +95,14 @@ public class MCFrameBuffer implements IFramebuffer {
@Override @Override
public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) { public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) {
//Timing ti=new Timing();
//System.out.println("Change - " + width + "x" + height);
if (tt != null) if (tt != null)
tt.cancel(); tt.cancel();
/*
* if (width > 640 || height > 480) { tt = Bukkit.getScheduler().runTaskTimerAsynchronously(PluginMain.Instance, () -> display.setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L), 5, 5);
* return; // Don't even try to render too large resolutions }
*/
tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> { tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
try { try {
display.querySourceBitmap(0L, holder); display.querySourceBitmap(0L, holder);
//byte[] arr = PluginMain.allpixels.array();
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]; 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];
holder.value.getTypedWrapped().queryBitmapInfo(ptr, w, h, bpp, bpl, pf); holder.value.getTypedWrapped().queryBitmapInfo(ptr, w, h, bpp, bpl, pf);
//System.out.println("Arr0:" + ptr[0]);
//System.out.println("whbppbplpf: " + w[0] + " " + h[0] + " " + bpp[0] + " " + bpl[0] + " " + pf[0]);
if (PluginMain.direct) { if (PluginMain.direct) {
//PluginMain.pxc.setSource(ptr[0], (int)w[0], (int)h[0], PluginMain.MCX, PluginMain.MCY);
pointer = new Pointer(ptr[0]); pointer = new Pointer(ptr[0]);
this.width = (int) w[0]; this.width = (int) w[0];
this.height = (int) h[0]; this.height = (int) h[0];
@ -123,8 +114,6 @@ public class MCFrameBuffer implements IFramebuffer {
else else
PluginMain.allpixels.limit((int) (width * height * 4)); PluginMain.allpixels.limit((int) (width * height * 4));
} }
//System.out.println("Change!");
//System.out.println("Change task took "+ti.elapsedMS()+"ms");
} catch (VBoxException e) { } catch (VBoxException e) {
if (e.getResultCode() == 0x80070005) if (e.getResultCode() == 0x80070005)
return; // Machine is being powered down return; // Machine is being powered down
@ -134,20 +123,11 @@ public class MCFrameBuffer implements IFramebuffer {
} catch (Throwable t) { } catch (Throwable t) {
t.printStackTrace(); t.printStackTrace();
} }
}); // Wait 1/4th of a second - Don't });
//System.out.println("Change took "+ti.elapsedMS()+"ms");
} }
@Override @Override
public void notifyUpdate(long x, long y, long width, long height) { public void notifyUpdate(long x, long y, long width, long height) {
/*if(tttt != null)
tttt.cancel();*/ //We are getting updates, but the pixel array isn't updated - VB reacts slowly
/*tttt = Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.Instance, () -> {
for (IRenderer r : PluginMain.renderers)
if (r instanceof DirectRenderer)
((DirectRenderer) r).render(PluginMain.allpixels, x, y, width, height);
System.out.println("Update!"); - The render is done each tick
}, 5);*/
Timing t = new Timing(); Timing t = new Timing();
GPURendererInternal.setPixels(pointer.getByteArray(0L, (this.width * this.height * 4)), this.width, this.height); //TODO: Only copy changed part GPURendererInternal.setPixels(pointer.getByteArray(0L, (this.width * this.height * 4)), this.width, this.height); //TODO: Only copy changed part
if (t.elapsedMS() > 60) //Typically 1ms max if (t.elapsedMS() > 60) //Typically 1ms max