Attempts to fix screen on Ubuntu after /c fix

It stops sending updates after running the fix command
This commit is contained in:
Norbi Peti 2020-08-03 02:43:31 +02:00
parent 3ce2da7f7f
commit 32cea5c384
No known key found for this signature in database
GPG key ID: DBA4C4549A927E56
2 changed files with 115 additions and 46 deletions

View file

@ -3,6 +3,7 @@ package sznp.virtualcomputer;
import com.google.common.collect.Lists;
import lombok.Getter;
import lombok.val;
import lombok.var;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -28,6 +29,7 @@ public final class Computer {
private MachineEventHandler handler;
private IEventListener listener;
private VirtualBoxManager manager;
private MCFrameBuffer framebuffer;
@java.beans.ConstructorProperties({"plugin"})
public Computer(PluginMain plugin, VirtualBoxManager manager, IVirtualBox vbox) {
@ -45,7 +47,7 @@ public final class Computer {
return;
}
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (vbox.getMachines().size() <= index) {
if (index < 0 || vbox.getMachines().size() <= index) {
sendMessage(sender, "§cMachine not found!");
return;
}
@ -54,7 +56,9 @@ public final class 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
synchronized (session) {
machine.lockMachine(session, LockType.VM); // We want the machine inside *our* process <-- Need the VM type to have console access
}
VBoxEventHandler.getInstance().setup(machine.getId(), sender); //TODO: Sometimes null
} catch (VBoxException e) {
if (e.getResultCode() == 0x80070005) { //lockMachine: "The object functionality is limited"
@ -95,8 +99,11 @@ public final class Computer {
IProgress progress = console.powerUp(); // https://marc.info/?l=vbox-dev&m=142780789819967&w=2
handler.setProgress(progress);
handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way?
console.getDisplay().attachFramebuffer(0L,
COMUtils.gimmeAFramebuffer(new MCFrameBuffer(console.getDisplay())));
val fb = new MCFrameBuffer(console.getDisplay());
String fbid = console.getDisplay().attachFramebuffer(0L,
COMUtils.gimmeAFramebuffer(fb));
fb.setId(fbid);
framebuffer = fb;
}
private void sendMessage(@Nullable CommandSender sender, String message) {
@ -114,7 +121,9 @@ public final class Computer {
return;
}
sendMessage(sender, "§eStopping computer...");
session.getConsole().powerDown();
synchronized (session) {
session.getConsole().powerDown();
}
}
public void PowerButton(CommandSender sender, int index) {
@ -125,7 +134,9 @@ public final class Computer {
if (session.getState() != SessionState.Locked || session.getMachine() == null) {
Start(sender, index);
} else {
session.getConsole().powerButton();
synchronized (session) {
session.getConsole().powerButton();
}
sendMessage(sender, "§ePowerbutton pressed.");
}
}
@ -136,17 +147,36 @@ public final class Computer {
if (checkMachineNotRunning(sender))
return;
sendMessage(sender, "§eResetting computer...");
session.getConsole().reset();
synchronized (session) {
session.getConsole().reset();
}
sendMessage(sender, "§eComputer reset.");
}
public void FixScreen(CommandSender sender) {
if (checkMachineNotRunning(sender))
return;
if (framebuffer == null) {
sender.sendMessage("§cFramebuffer is null...");
return;
}
val lastUpdated = new Holder<Long>();
var status = session.getConsole().getGuest().getFacilityStatus(AdditionsFacilityType.Seamless, lastUpdated);
sendMessage(sender, "Seamless status: " + status);
sendMessage(sender, "§eFixing screen...");
session.getConsole().getDisplay().setSeamlessMode(false);
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L, true);
try {
synchronized (session) {
session.getConsole().getDisplay().setSeamlessMode(false);
session.getConsole().getDisplay().detachFramebuffer(0L, framebuffer.getId());
session.getConsole().getDisplay().setVideoModeHint(0L, true, false, 0, 0, 640L, 480L, 32L, true);
framebuffer.setId(session.getConsole().getDisplay().attachFramebuffer(0L, COMUtils.gimmeAFramebuffer(framebuffer)));
}
} catch (Exception e) {
e.printStackTrace();
}
sendMessage(sender, "§eScreen fixed.");
status = session.getConsole().getGuest().getFacilityStatus(AdditionsFacilityType.Seamless, lastUpdated);
sendMessage(sender, "Seamless status: " + status);
}
public boolean checkMachineNotRunning(@Nullable CommandSender sender) {
@ -177,14 +207,16 @@ public final class Computer {
}
// 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);
synchronized (session) {
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 * 20);
}
}
}
@ -195,7 +227,9 @@ public final class Computer {
if (mbs.length() > 0 && down)
state = Arrays.stream(MouseButtonState.values()).filter(mousebs -> mousebs.name().equalsIgnoreCase(mbs))
.findAny().orElseThrow(() -> new Exception("Unknown mouse button")).value();
session.getConsole().getMouse().putMouseEvent(x, y, z, w, state);
synchronized (session) {
session.getConsole().getMouse().putMouseEvent(x, y, z, w, state);
}
}
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs) throws Exception {
@ -212,7 +246,9 @@ public final class Computer {
public void onMachineStop(CommandSender sender) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (session.getState() == SessionState.Locked) {
session.unlockMachine(); //Needs to be outside of the event handler
synchronized (session) {
session.unlockMachine(); //Needs to be outside of the event handler
}
handler = null;
machine = null;
session = manager.getSessionObject();

View file

@ -1,7 +1,9 @@
package sznp.virtualcomputer.renderer;
import com.sun.jna.Pointer;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import org.virtualbox_6_1.Holder;
@ -21,46 +23,77 @@ public class MCFrameBuffer implements IMCFrameBuffer {
private Pointer pointer;
private int width;
private int height;
private boolean updating = false;
@Getter
@Setter
private String id;
@Override
public void notifyChange(long screenId, long xOrigin, long yOrigin, long width, long height) {
if (tt != null)
tt.cancel();
tt = Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
try {
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);
if (PluginMain.direct) {
pointer = new Pointer(ptr[0]);
this.width = (int) w[0];
this.height = (int) h[0];
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);
if (width * height > 640 * 480)
PluginMain.allpixels.limit(640 * 480 * 4);
else
PluginMain.allpixels.limit((int) (width * height * 4));
synchronized (this) { //If a change occurs twice, then wait for it
try {
System.out.println("Change: " + xOrigin + " " + yOrigin + " - " + width + " " + height);
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);
if (PluginMain.direct) {
pointer = new Pointer(ptr[0]);
this.width = (int) w[0];
this.height = (int) h[0];
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);
if (width * height > 640 * 480)
PluginMain.allpixels.limit(640 * 480 * 4);
else
PluginMain.allpixels.limit((int) (width * height * 4));
}
} catch (VBoxException e) {
if (e.getResultCode() == 0x80070005)
return; // Machine is being powered down
if (e.getResultCode() == 0x80004005) //The function "querySourceBitmap" returned an error condition: "Operation failed (NS_ERROR_FAILURE)"
System.out.println("I don't know why this happens, but stopping the computer helps.");
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("Change finished");
}
} catch (VBoxException e) {
if (e.getResultCode() == 0x80070005)
return; // Machine is being powered down
if (e.getResultCode() == 0x80004005) //The function "querySourceBitmap" returned an error condition: "Operation failed (NS_ERROR_FAILURE)"
System.out.println("I don't know why this happens, but stopping the computer helps.");
e.printStackTrace();
} catch (Throwable t) {
t.printStackTrace();
}
});
}
@Override
public void notifyUpdate(long x, long y, long width, long height) {
Timing t = new Timing();
GPURenderer.update(pointer.getByteArray(0L, this.width * this.height * 4), this.width, this.height, (int) x, (int) y, (int) width, (int) height);
if (t.elapsedMS() > 60) //Typically 1ms max
System.out.println("Update took " + t.elapsedMS() + "ms");
if (this.width > 1024 || this.height > 768)
return;
Bukkit.getScheduler().runTaskAsynchronously(PluginMain.Instance, () -> {
synchronized (this) {
if (updating) {
System.out.println("Ignoring update");
return;
}
updating = true;
if (pointer == null) {
System.out.println("Screen pointer is null");
updating = false;
return;
}
System.out.println("Update: " + x + " " + y + " - " + width + " " + height);
Timing t = new Timing();
GPURenderer.update(pointer.getByteArray(0L, this.width * this.height * 4), this.width, this.height, (int) x, (int) y, (int) width, (int) height);
if (t.elapsedMS() > 60) //Typically 1ms max
System.out.println("Update took " + t.elapsedMS() + "ms");
else
System.out.println("Update finished");
updating = false;
}
});
}
@Override