Directly using VirtualBox from Java #5
6 changed files with 271 additions and 192 deletions
|
@ -5,6 +5,7 @@ import org.bukkit.command.Command;
|
||||||
import org.bukkit.command.CommandExecutor;
|
import org.bukkit.command.CommandExecutor;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import sznp.virtualcomputer.events.Computer;
|
||||||
|
|
||||||
public class Commands implements CommandExecutor {
|
public class Commands implements CommandExecutor {
|
||||||
|
|
||||||
|
@ -22,14 +23,14 @@ public class Commands implements CommandExecutor {
|
||||||
sender.sendMessage("§cUsage: /" + label + " start [index]");
|
sender.sendMessage("§cUsage: /" + label + " start [index]");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PluginMain.Instance.Start(sender, c);
|
Computer.getInstance().Start(sender, c);
|
||||||
break;
|
break;
|
||||||
case "stop":
|
case "stop":
|
||||||
case "poweroff":
|
case "poweroff":
|
||||||
case "off":
|
case "off":
|
||||||
case "shutdown":
|
case "shutdown":
|
||||||
case "kill":
|
case "kill":
|
||||||
PluginMain.Instance.Stop(sender);
|
Computer.getInstance().Stop(sender);
|
||||||
break;
|
break;
|
||||||
case "powerbutton":
|
case "powerbutton":
|
||||||
case "pwrbtn":
|
case "pwrbtn":
|
||||||
|
@ -39,15 +40,15 @@ public class Commands implements CommandExecutor {
|
||||||
sender.sendMessage("§cUsage: /" + label + " powerbutton [index]");
|
sender.sendMessage("§cUsage: /" + label + " powerbutton [index]");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
PluginMain.Instance.PowerButton(sender, c);
|
Computer.getInstance().PowerButton(sender, c);
|
||||||
break;
|
break;
|
||||||
case "reset":
|
case "reset":
|
||||||
case "restart":
|
case "restart":
|
||||||
PluginMain.Instance.Reset(sender);
|
Computer.getInstance().Reset(sender);
|
||||||
break;
|
break;
|
||||||
case "fix":
|
case "fix":
|
||||||
case "fixscreen":
|
case "fixscreen":
|
||||||
PluginMain.Instance.FixScreen(sender);
|
Computer.getInstance().FixScreen(sender);
|
||||||
break;
|
break;
|
||||||
case "key":
|
case "key":
|
||||||
case "press":
|
case "press":
|
||||||
|
@ -58,9 +59,9 @@ public class Commands implements CommandExecutor {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (args.length < 3)
|
if (args.length < 3)
|
||||||
PluginMain.Instance.PressKey(sender, args[1], "");
|
Computer.getInstance().PressKey(sender, args[1], "");
|
||||||
else
|
else
|
||||||
PluginMain.Instance.PressKey(sender, args[1], args[2]);
|
Computer.getInstance().PressKey(sender, args[1], args[2]);
|
||||||
break;
|
break;
|
||||||
case "mouse":
|
case "mouse":
|
||||||
boolean showusage = true;
|
boolean showusage = true;
|
||||||
|
@ -68,15 +69,15 @@ public class Commands implements CommandExecutor {
|
||||||
// Command overloading, because I can :P
|
// Command overloading, because I can :P
|
||||||
if (args.length > 4) // 4<x<6
|
if (args.length > 4) // 4<x<6
|
||||||
{
|
{
|
||||||
PluginMain.Instance.UpdateMouse(sender, Integer.parseInt(args[1]), Integer.parseInt(args[2]),
|
Computer.getInstance().UpdateMouse(sender, Integer.parseInt(args[1]), Integer.parseInt(args[2]),
|
||||||
Integer.parseInt(args[3]), Integer.parseInt(args[4]), "", false);
|
Integer.parseInt(args[3]), Integer.parseInt(args[4]), "", false);
|
||||||
showusage = false;
|
showusage = false;
|
||||||
} else {
|
} else {
|
||||||
if (args.length == 3) {
|
if (args.length == 3) {
|
||||||
PluginMain.Instance.UpdateMouse(sender, 0, 0, 0, 0, args[1], args[2].equals("down"));
|
Computer.getInstance().UpdateMouse(sender, 0, 0, 0, 0, args[1], args[2].equals("down"));
|
||||||
showusage = false;
|
showusage = false;
|
||||||
} else if (args.length == 2) {
|
} else if (args.length == 2) {
|
||||||
PluginMain.Instance.UpdateMouse(sender, 0, 0, 0, 0, args[1]);
|
Computer.getInstance().UpdateMouse(sender, 0, 0, 0, 0, args[1]);
|
||||||
showusage = false;
|
showusage = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.bukkit.command.ConsoleCommandSender;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
import org.virtualbox_6_0.*;
|
import org.virtualbox_6_0.*;
|
||||||
|
import sznp.virtualcomputer.events.VBoxEventHandler;
|
||||||
import sznp.virtualcomputer.renderer.BukkitRenderer;
|
import sznp.virtualcomputer.renderer.BukkitRenderer;
|
||||||
import sznp.virtualcomputer.renderer.GPURenderer;
|
import sznp.virtualcomputer.renderer.GPURenderer;
|
||||||
import sznp.virtualcomputer.renderer.IRenderer;
|
import sznp.virtualcomputer.renderer.IRenderer;
|
||||||
|
@ -22,6 +23,8 @@ import java.lang.reflect.Field;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public class PluginMain extends JavaPlugin {
|
public class PluginMain extends JavaPlugin {
|
||||||
|
@ -75,12 +78,13 @@ public class PluginMain extends JavaPlugin {
|
||||||
VBoxLib vbl = LibraryLoader.create(VBoxLib.class).load("vboxjxpcom");
|
VBoxLib vbl = LibraryLoader.create(VBoxLib.class).load("vboxjxpcom");
|
||||||
vbl.RTR3InitExe(0, "", 0);
|
vbl.RTR3InitExe(0, "", 0);
|
||||||
vbox = manager.getVBox();
|
vbox = manager.getVBox();
|
||||||
|
vbox.getEventSource().registerListener(new IEventListener(new VBoxEventHandler()), Arrays.asList(VBoxEventType.OnMachineStateChanged), true);
|
||||||
session = manager.getSessionObject(); // TODO: Events
|
session = manager.getSessionObject(); // TODO: Events
|
||||||
ccs.sendMessage("§bLoading Screen...");
|
ccs.sendMessage("§bLoading Screen...");
|
||||||
try {
|
try {
|
||||||
//throw new NoClassDefFoundError("Test error pls ignore");
|
//throw new NoClassDefFoundError("Test error pls ignore");
|
||||||
for (short i = 0; i < 5; i++)
|
for (short i = 0; i < MCX; i++)
|
||||||
for (short j = 0; j < 4; j++)
|
for (short j = 0; j < MCY; j++)
|
||||||
renderers.add(new GPURenderer((short) (j * 5 + i), Bukkit.getWorlds().get(0), i, j));
|
renderers.add(new GPURenderer((short) (j * 5 + i), Bukkit.getWorlds().get(0), i, j));
|
||||||
//pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc");
|
//pxc = LibraryLoader.create(PXCLib.class).search(getDataFolder().getAbsolutePath()).load("pxc");
|
||||||
direct=true;
|
direct=true;
|
||||||
|
@ -123,186 +127,6 @@ public class PluginMain extends JavaPlugin {
|
||||||
saveConfig();
|
saveConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start(CommandSender sender, int index) {// TODO: Add touchscreen support (#2)
|
|
||||||
if (session.getState() == SessionState.Locked) {
|
|
||||||
sender.sendMessage("§cThe machine is already running!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Bukkit.getScheduler().runTaskAsynchronously(this, () -> {
|
|
||||||
if (vbox.getMachines().size() <= index) {
|
|
||||||
sendMessage(sender, "§cMachine not found!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
sendMessage(sender, "§eStarting computer...");
|
|
||||||
machine = vbox.getMachines().get(index);
|
|
||||||
session.setName("minecraft");
|
|
||||||
// machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); - This creates a *process*, we don't want that anymore
|
|
||||||
machine.lockMachine(session, LockType.VM); // We want the machine inside *our* process <-- Need the VM type to have console access
|
|
||||||
final Runnable tr = new Runnable() {
|
|
||||||
public void run() {
|
|
||||||
if (session.getState() != SessionState.Locked) { // https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#ac82c179a797c0d7c249d1b98a8e3aa8f
|
|
||||||
Bukkit.getScheduler().runTaskLaterAsynchronously(PluginMain.this, this, 5);
|
|
||||||
return; // "This state also occurs as a short transient state during an IMachine::lockMachine call."
|
|
||||||
}
|
|
||||||
machine = session.getMachine(); // This is the Machine object we can work with
|
|
||||||
final IConsole console = session.getConsole();
|
|
||||||
console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2
|
|
||||||
console.getDisplay().attachFramebuffer(0L,
|
|
||||||
new IFramebuffer(new MCFrameBuffer(console.getDisplay(), true)));
|
|
||||||
startScreenTask(console, sender);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this, tr, 5);
|
|
||||||
} catch (VBoxException e) {
|
|
||||||
if (e.getResultCode() == 0x80070005) { //lockMachine: "The object functionality is limited"
|
|
||||||
sendMessage(sender, "§6Cannot start computer, the machine may be inaccessible");
|
|
||||||
return; //TODO: If we have VirtualBox open, it won't close the server's port
|
|
||||||
//TODO: Can't detect if machine fails to start because of hardening issues
|
|
||||||
//TODO: This error also occurs if the machine has failed to start at least once (always reassign the machine?)
|
|
||||||
//machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); //No privileges, start the 'old' way
|
|
||||||
//session.getConsole().getDisplay().attachFramebuffer(0L, new IFramebuffer(new MCFrameBuffer(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());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendMessage(sender, "§eComputer started.");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Right now only checks if the computer has turned off.
|
|
||||||
*/
|
|
||||||
private void startScreenTask(IConsole console, CommandSender sender) {
|
|
||||||
if (screenupdatetask == null)
|
|
||||||
screenupdatetask = Bukkit.getScheduler().runTaskTimerAsynchronously(PluginMain.this, () -> {
|
|
||||||
/*if (session.getState().equals(SessionState.Locked) // Don't run until the machine is running
|
|
||||||
&& console.getState().equals(MachineState.Running))
|
|
||||||
console.getDisplay().invalidateAndUpdateScreen(0L);*/
|
|
||||||
if (session.getState().equals(SessionState.Unlocked) // Stop if the machine stopped fully
|
|
||||||
|| console.getState().equals(MachineState.PoweredOff)
|
|
||||||
|| console.getState().equals(MachineState.Saved)) {
|
|
||||||
if (session.getState().equals(SessionState.Locked)) {
|
|
||||||
session.unlockMachine();
|
|
||||||
sendMessage(sender, "Computer powered off, released it.");
|
|
||||||
}
|
|
||||||
screenupdatetask.cancel();
|
|
||||||
screenupdatetask = null;
|
|
||||||
}
|
|
||||||
}, 100, 100); // Do a full update every 5 seconds
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sendMessage(CommandSender sender, String message) {
|
|
||||||
sender.sendMessage(message);
|
|
||||||
getLogger().warning(sender.getName() + ": " + ChatColor.stripColor(message));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop(CommandSender sender) {
|
|
||||||
if (checkMachineNotRunning(sender)) {
|
|
||||||
if (session.getState().equals(SessionState.Locked)) {
|
|
||||||
session.unlockMachine();
|
|
||||||
sendMessage(sender, "§eComputer powered off, released it.");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
sendMessage(sender, "§eStopping computer...");
|
|
||||||
session.getConsole().powerDown().waitForCompletion(2000);
|
|
||||||
session.unlockMachine();
|
|
||||||
sendMessage(sender, "§eComputer stopped.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PowerButton(CommandSender sender, int index) {
|
|
||||||
sendMessage(sender, "§ePressing powerbutton...");
|
|
||||||
getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (session.getState() != SessionState.Locked || session.getMachine() == null) {
|
|
||||||
Start(sender, index);
|
|
||||||
} else {
|
|
||||||
session.getConsole().powerButton();
|
|
||||||
sendMessage(sender, "§ePowerbutton pressed.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Reset(CommandSender sender) {
|
|
||||||
if (checkMachineNotRunning(sender))
|
|
||||||
return;
|
|
||||||
sendMessage(sender, "§eResetting computer...");
|
|
||||||
session.getConsole().reset();
|
|
||||||
sendMessage(sender, "§eComputer reset.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void FixScreen(CommandSender sender) {
|
|
||||||
if (checkMachineNotRunning(sender))
|
|
||||||
return;
|
|
||||||
sendMessage(sender, "§eFixing screen...");
|
|
||||||
session.getConsole().getDisplay().setSeamlessMode(false);
|
|
||||||
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L);
|
|
||||||
sendMessage(sender, "§eScreen fixed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean checkMachineNotRunning(@Nullable CommandSender sender) {
|
|
||||||
if (session.getState() != SessionState.Locked || machine.getState() != MachineState.Running) {
|
|
||||||
if (sender != null)
|
|
||||||
sender.sendMessage("§cMachine isn't running.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void PressKey(CommandSender sender, String key, String stateorduration) {
|
|
||||||
if (checkMachineNotRunning(sender))
|
|
||||||
return;
|
|
||||||
int durationorstate;
|
|
||||||
if (stateorduration.length() == 0)
|
|
||||||
durationorstate = 0;
|
|
||||||
else if (stateorduration.equalsIgnoreCase("down"))
|
|
||||||
durationorstate = -1;
|
|
||||||
else if (stateorduration.equalsIgnoreCase("up"))
|
|
||||||
durationorstate = -2;
|
|
||||||
else
|
|
||||||
durationorstate = Short.parseShort(stateorduration);
|
|
||||||
int code;
|
|
||||||
try {
|
|
||||||
code = Scancode.valueOf("sc_" + key.toLowerCase()).Code;
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
sender.sendMessage("§cUnknown key: " + key);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Release key scan code concept taken from VirtualBox source code (KeyboardImpl.cpp:putCAD())
|
|
||||||
// +128
|
|
||||||
if (durationorstate != -2)
|
|
||||||
session.getConsole().getKeyboard().putScancode(code);
|
|
||||||
Runnable sendrelease = () -> session.getConsole().getKeyboard().putScancodes(Lists.newArrayList(code + 128,
|
|
||||||
Scancode.sc_controlLeft.Code + 128, Scancode.sc_shiftLeft.Code + 128, Scancode.sc_altLeft.Code + 128));
|
|
||||||
if (durationorstate == 0 || durationorstate == -2)
|
|
||||||
sendrelease.run();
|
|
||||||
if (durationorstate > 0) {
|
|
||||||
Bukkit.getScheduler().runTaskLaterAsynchronously(this, sendrelease, durationorstate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs, boolean down) {
|
|
||||||
if (checkMachineNotRunning(sender))
|
|
||||||
return;
|
|
||||||
int state = 0;
|
|
||||||
if (mbs.length() > 0 && down)
|
|
||||||
state = Arrays.stream(MouseButtonState.values()).filter(mousebs -> mousebs.name().equalsIgnoreCase(mbs))
|
|
||||||
.findAny().orElseThrow(() -> new RuntimeException("Unknown mouse button")).value();
|
|
||||||
session.getConsole().getMouse().putMouseEvent(x, y, z, w, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs) {
|
|
||||||
if (checkMachineNotRunning(sender))
|
|
||||||
return;
|
|
||||||
UpdateMouse(sender, x, y, z, w, mbs, true);
|
|
||||||
UpdateMouse(sender, x, y, z, w, mbs, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified path to the java library path
|
* Adds the specified path to the java library path
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,195 @@
|
||||||
|
package sznp.virtualcomputer.events;
|
||||||
|
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import lombok.Getter;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.virtualbox_6_0.*;
|
||||||
|
import sznp.virtualcomputer.PluginMain;
|
||||||
|
import sznp.virtualcomputer.renderer.MCFrameBuffer;
|
||||||
|
import sznp.virtualcomputer.util.Scancode;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
public final class Computer {
|
||||||
|
@Getter
|
||||||
|
private static Computer instance;
|
||||||
|
|
||||||
|
private final PluginMain plugin;
|
||||||
|
private ISession session;
|
||||||
|
private IVirtualBox vbox;
|
||||||
|
private IMachine machine;
|
||||||
|
|
||||||
|
@java.beans.ConstructorProperties({"plugin"})
|
||||||
|
public Computer(PluginMain plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
if(instance!=null) throw new IllegalStateException("A computer already exists!");
|
||||||
|
instance=this; //TODO: Move some init stuff here
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(CommandSender sender, int index) {// TODO: Add touchscreen support (#2)
|
||||||
|
if (session.getState() == SessionState.Locked) {
|
||||||
|
sender.sendMessage("§cThe machine is already running!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
|
||||||
|
if (vbox.getMachines().size() <= index) {
|
||||||
|
sendMessage(sender, "§cMachine not found!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
sendMessage(sender, "§eStarting computer...");
|
||||||
|
machine = vbox.getMachines().get(index);
|
||||||
|
session.setName("minecraft");
|
||||||
|
// machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); - This creates a *process*, we don't want that anymore
|
||||||
|
machine.lockMachine(session, LockType.VM); // We want the machine inside *our* process <-- Need the VM type to have console access
|
||||||
|
final Runnable tr = new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
if (session.getState() != SessionState.Locked) { // https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#ac82c179a797c0d7c249d1b98a8e3aa8f
|
||||||
|
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, this, 5);
|
||||||
|
return; // "This state also occurs as a short transient state during an IMachine::lockMachine call."
|
||||||
|
}
|
||||||
|
machine = session.getMachine(); // This is the Machine object we can work with
|
||||||
|
final IConsole console = session.getConsole();
|
||||||
|
console.getEventSource().registerListener(new IEventListener(new MachineEventHandler(Computer.this)), Collections.singletonList(VBoxEventType.MachineEvent), true);
|
||||||
|
console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2
|
||||||
|
console.getDisplay().attachFramebuffer(0L,
|
||||||
|
new IFramebuffer(new MCFrameBuffer(console.getDisplay(), true)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, tr, 5);
|
||||||
|
} catch (VBoxException e) {
|
||||||
|
if (e.getResultCode() == 0x80070005) { //lockMachine: "The object functionality is limited"
|
||||||
|
sendMessage(sender, "§6Cannot start computer, the machine may be inaccessible");
|
||||||
|
return; //TODO: If we have VirtualBox open, it won't close the server's port
|
||||||
|
//TODO: Can't detect if machine fails to start because of hardening issues
|
||||||
|
//TODO: This error also occurs if the machine has failed to start at least once (always reassign the machine?)
|
||||||
|
//machine.launchVMProcess(session, "headless", "").waitForCompletion(10000); //No privileges, start the 'old' way
|
||||||
|
//session.getConsole().getDisplay().attachFramebuffer(0L, new IFramebuffer(new MCFrameBuffer(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());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendMessage(sender, "§eComputer started.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendMessage(@Nullable CommandSender sender, String message) {
|
||||||
|
if(sender!=null)
|
||||||
|
sender.sendMessage(message);
|
||||||
|
plugin.getLogger().warning((sender==null?"":sender.getName() + ": ") + ChatColor.stripColor(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop(CommandSender sender) {
|
||||||
|
if (checkMachineNotRunning(sender)) {
|
||||||
|
if (session.getState().equals(SessionState.Locked)) {
|
||||||
|
session.unlockMachine();
|
||||||
|
sendMessage(sender, "§eComputer powered off, released it.");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendMessage(sender, "§eStopping computer...");
|
||||||
|
session.getConsole().powerDown().waitForCompletion(2000);
|
||||||
|
session.unlockMachine();
|
||||||
|
sendMessage(sender, "§eComputer stopped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PowerButton(CommandSender sender, int index) {
|
||||||
|
sendMessage(sender, "§ePressing powerbutton...");
|
||||||
|
Bukkit.getServer().getScheduler().runTaskAsynchronously(plugin, new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (session.getState() != SessionState.Locked || session.getMachine() == null) {
|
||||||
|
Start(sender, index);
|
||||||
|
} else {
|
||||||
|
session.getConsole().powerButton();
|
||||||
|
sendMessage(sender, "§ePowerbutton pressed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset(CommandSender sender) {
|
||||||
|
if (checkMachineNotRunning(sender))
|
||||||
|
return;
|
||||||
|
sendMessage(sender, "§eResetting computer...");
|
||||||
|
session.getConsole().reset();
|
||||||
|
sendMessage(sender, "§eComputer reset.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FixScreen(CommandSender sender) {
|
||||||
|
if (checkMachineNotRunning(sender))
|
||||||
|
return;
|
||||||
|
sendMessage(sender, "§eFixing screen...");
|
||||||
|
session.getConsole().getDisplay().setSeamlessMode(false);
|
||||||
|
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L);
|
||||||
|
sendMessage(sender, "§eScreen fixed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean checkMachineNotRunning(@Nullable CommandSender sender) {
|
||||||
|
if (session.getState() != SessionState.Locked || machine.getState() != MachineState.Running) {
|
||||||
|
if (sender != null)
|
||||||
|
sender.sendMessage("§cMachine isn't running.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PressKey(CommandSender sender, String key, String stateorduration) {
|
||||||
|
if (checkMachineNotRunning(sender))
|
||||||
|
return;
|
||||||
|
int durationorstate;
|
||||||
|
if (stateorduration.length() == 0)
|
||||||
|
durationorstate = 0;
|
||||||
|
else if (stateorduration.equalsIgnoreCase("down"))
|
||||||
|
durationorstate = -1;
|
||||||
|
else if (stateorduration.equalsIgnoreCase("up"))
|
||||||
|
durationorstate = -2;
|
||||||
|
else
|
||||||
|
durationorstate = Short.parseShort(stateorduration);
|
||||||
|
int code;
|
||||||
|
try {
|
||||||
|
code = Scancode.valueOf("sc_" + key.toLowerCase()).Code;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
sender.sendMessage("§cUnknown key: " + key);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Release key scan code concept taken from VirtualBox source code (KeyboardImpl.cpp:putCAD())
|
||||||
|
// +128
|
||||||
|
if (durationorstate != -2)
|
||||||
|
session.getConsole().getKeyboard().putScancode(code);
|
||||||
|
Runnable sendrelease = () -> session.getConsole().getKeyboard().putScancodes(Lists.newArrayList(code + 128,
|
||||||
|
Scancode.sc_controlLeft.Code + 128, Scancode.sc_shiftLeft.Code + 128, Scancode.sc_altLeft.Code + 128));
|
||||||
|
if (durationorstate == 0 || durationorstate == -2)
|
||||||
|
sendrelease.run();
|
||||||
|
if (durationorstate > 0) {
|
||||||
|
Bukkit.getScheduler().runTaskLaterAsynchronously(plugin, sendrelease, durationorstate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs, boolean down) {
|
||||||
|
if (checkMachineNotRunning(sender))
|
||||||
|
return;
|
||||||
|
int state = 0;
|
||||||
|
if (mbs.length() > 0 && down)
|
||||||
|
state = Arrays.stream(MouseButtonState.values()).filter(mousebs -> mousebs.name().equalsIgnoreCase(mbs))
|
||||||
|
.findAny().orElseThrow(() -> new RuntimeException("Unknown mouse button")).value();
|
||||||
|
session.getConsole().getMouse().putMouseEvent(x, y, z, w, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs) {
|
||||||
|
if (checkMachineNotRunning(sender))
|
||||||
|
return;
|
||||||
|
UpdateMouse(sender, x, y, z, w, mbs, true);
|
||||||
|
UpdateMouse(sender, x, y, z, w, mbs, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stopRendering() {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
package sznp.virtualcomputer.events;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.val;
|
||||||
|
import org.mozilla.interfaces.IEvent;
|
||||||
|
import org.mozilla.interfaces.IEventListener;
|
||||||
|
import org.virtualbox_6_0.IStateChangedEvent;
|
||||||
|
import org.virtualbox_6_0.MachineState;
|
||||||
|
import sznp.virtualcomputer.renderer.MCFrameBuffer;
|
||||||
|
import sznp.virtualcomputer.util.COMObjectBase;
|
||||||
|
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class MachineEventHandler extends COMObjectBase implements IEventListener {
|
||||||
|
private final Computer computer;
|
||||||
|
@Override
|
||||||
|
public void handleEvent(IEvent iEvent) {
|
||||||
|
if(iEvent instanceof IStateChangedEvent) {
|
||||||
|
val event=(IStateChangedEvent) iEvent; //https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#a80b08f71210afe16038e904a656ed9eb
|
||||||
|
switch (event.getState()) {
|
||||||
|
case Stuck:
|
||||||
|
computer.Stop(null);
|
||||||
|
break;
|
||||||
|
case PoweredOff:
|
||||||
|
case Saved:
|
||||||
|
computer.stopRendering();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package sznp.virtualcomputer.events;
|
||||||
|
|
||||||
|
import lombok.val;
|
||||||
|
import org.mozilla.interfaces.IEvent;
|
||||||
|
import org.mozilla.interfaces.IEventListener;
|
||||||
|
import org.mozilla.interfaces.nsISupports;
|
||||||
|
import org.mozilla.xpcom.Mozilla;
|
||||||
|
import org.virtualbox_6_0.IMachineStateChangedEvent;
|
||||||
|
import org.virtualbox_6_0.VBoxEventType;
|
||||||
|
import sznp.virtualcomputer.util.COMObjectBase;
|
||||||
|
|
||||||
|
public class VBoxEventHandler extends COMObjectBase implements IEventListener {
|
||||||
|
@Override
|
||||||
|
public void handleEvent(IEvent iEvent) {
|
||||||
|
if(iEvent.getType()== VBoxEventType.OnMachineStateChanged.value()) {
|
||||||
|
val event=(IMachineStateChangedEvent) iEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package sznp.virtualcomputer.util;
|
||||||
|
|
||||||
|
import org.mozilla.interfaces.nsISupports;
|
||||||
|
import org.mozilla.xpcom.Mozilla;
|
||||||
|
|
||||||
|
public abstract class COMObjectBase implements nsISupports {
|
||||||
|
public nsISupports queryInterface(String id) {
|
||||||
|
return Mozilla.queryInterface(this, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue