Merge pull request #5 from NorbiPeti/directvb

Directly using VirtualBox from Java
This commit is contained in:
Norbi Peti 2019-04-19 01:29:21 +02:00 committed by GitHub
commit 04053f9b13
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 3032 additions and 3148 deletions

63
.gitattributes vendored Normal file
View file

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

3
.gitignore vendored
View file

@ -1,3 +1,5 @@
libpxc.so
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@ -466,4 +468,3 @@ TheButtonAutoFlair/out/artifacts/Autoflair/Autoflair.jar
*.iml
*.name
.idea/compiler.xml
*.xml

View file

@ -1,49 +1,50 @@
# The Computer
A working modern computer in Minecraft made using VirtualBox, jni4net, C# and Java. No clientside mods required.
A working modern computer in Minecraft made using VirtualBox and Java. No clientside mods required.
I started working on this project on 2015. december 5. However I did not write much code in that time as I had to figure out how things work.
I plan on making a series where I show the whole process of creating this project.
## Video
##Video
[![Original video](https://img.youtube.com/vi/VxSyDfxPd3s/0.jpg)](https://www.youtube.com/watch?v=VxSyDfxPd3s)
[![Video](https://img.youtube.com/vi/K4t98YUIm4M/0.jpg)](https://www.youtube.com/watch?v=K4t98YUIm4M)
## Installation requirements
*Note: only the server host has to meet these requirements.*
### Currently compiled for (and tested on):
*If you don't meet these requirements, you will need to compile the files for yourself. Please help by sending the compiled version to me so more people can download it.*
* A non-Windows OS supported by VirtualBox
* Root (sudo) privileges
* Enough resources to run another OS
* Windows 7 64-bit
* VirtualBox 5
* Spgiot/Bukkit 1.8/1.9 (with Movecraft for the mouse craft type)
* Microsoft .NET Framework 4.5
### Tested versions:
*If you don't meet these requirements, you may need to compile the files for yourself. If you do please send the compiled version to me so more people can download it.*
* OS X; Ubuntu 16.04/18.04
* VirtualBox 6.0
* Spgiot/Bukkit 1.12
* Java 8
### Possibly works with (untested):
* Any version of Windows which supports .NET 4.5
* Other VirtualBox versions (code modifications are probably necessary)
* Other Spigot/Bukkit versions
* Microsoft .NET Framework 4 (code modifications *are* necessary)
* Other Java versions
*The fast rendering method currently only supports 1.12.2.*
*Due to jni4net support limitations the plugin does not support other operating systems.*
### Tested on:
*The requirements vary greatly depending on what OS you want to run ingame but here are my specs that can run Overwatch in Minecraft.*
* CPU: Intel® Pentium(R) CPU G3460 @ 3.50GHz × 2
* RAM: 8 GB
* GPU: NVidia GeForce GTX 650 1 GB
*Due to VirtualBox Java binding support limitations the plugin does not support Windows currently.*
## Installation
**Warning:** The first loaded world on the server (the one specified in server.properties) will **lose** the first 20 maps, though it might be only a temporary effect, it might restore after the server starts up without the plugin. *(Untested.)*
**Warning:** The first loaded world on the server (the one specified in server.properties) will temporarily **lose** the first 20 maps, although it will be back to normal if the server is loaded without the plugin.
* Install all the requirements
* Add a virtual PC if you don't have any (the first one will be started)
* Install VirtualBox
* *Using sudo,* add a virtual PC if you don't have any (the first one will be started by default)
* Install an OS and Guest Additions, if you haven't already
* Put the jar file into <server>/plugins directory
* Make sure your server is set to a world that you don't mind your maps deleted from
* Start your server
* *Using sudo,* start your server
## Usage
*Please give appropriate credit and link to this page if you use this machine in one of your videos/creations/etc. You can also send me your video so I can put it here.*
*Please give appropriate credit and link to this page if you use this machine in one of your videos/creations/etc.*
### Display
*Note:* You can create as many displays as you want, but all of them will show the same.
*Note: You can create as many displays as you want, but all of them will show the same currently.*
To create a display, make a 5 wide 4 high wall of item frames, then put the maps 0-19 on them starting from the top left and going downwards. You can give the maps with this command:
@ -54,22 +55,40 @@ Where you'll need to increment 0 for each map.
It is also recommended to start the virtual machine first so you can distinguish the different parts of the display while placing it.
#### Keyboard
You can either open the chat keyboard using /computer input key, or you can use /computer key \<keyname\>. You can find key names [here](https://github.com/NorbiPeti/VirtualComputer/blob/master/VirtualComputerSender/VirtualKeys.cs). Note that not all keys are currently supported.
You can either open the chat keyboard using /computer input key, or you can use /computer key \<keyname\>. You can find key names [here](https://github.com/NorbiPeti/VirtualComputer/blob/directvb/VirtualComputer/src/sznp/virtualcomputer/Scancode.java).
#### Mouse
You can "lock" the physical mouse to the virtual one with /computer input mouse, or you can move the mouse (including scrolling) with /computer mouse \<dx\> \<dy\> \<dz\> \<dw\>, where dx specifies the amount of pixels to move right, and dy specifies the amount of pixels to move down, while dz and dw specify the scrolling vertically (positive values scroll down) and horizontally.
To set the locked mouse speed, use /computer input mspeed \<integer\>. The difference in look position will be multiplied with this number. Recommended values are between 1 and 10 (inclusive). Default: 1.
You can also use the "mouse" Movecraft craft type to move the mouse, though it's a bit unreliable.
You can press a mouse button with /computer mouse <buttonname>. For example: /computer mouse leftbutton. You can find all the button names [here](https://github.com/NorbiPeti/VirtualComputer/blob/master/VirtualComputerSender/MouseBS.cs).
You can press a mouse button with /computer mouse <buttonname>. For example: /computer mouse leftbutton. Usable key names:
* LeftButton
* RightButton
* MiddleButton
* WheelUp
* WheelDown
* XButton1
* XButton2
#### Sounds
Due to the way it works, it automatically plays every sound from the virtual machine **on the host computer**. This is built into VBoxHeadless, it seems. In order to make the sounds play for every connected player, we'd need a clientside mod.
Due to the way it works, it automatically plays every sound from the virtual machine **on the host computer**. This is built into the VM, it seems. In order to make the sounds play for every connected player, we'd need a clientside mod.
### Special thanks:
* The creators of VirtualBox for making it open-source and easy to use (though I had minor issues but those was because .NET had a few marshaling errors with booleans and that I needed to learn how machines work - especially keyboards)
* The creators of jni4net, after I figured it out, it was quite easy to use
* Minecraft player iie for testing and suggesting the Movecraft mouse and other ideas not related to this project
* The creator(s) of SketchMap, a plugin which I edited to create the display
* The creators of VirtualBox for making it open-source and kind of easy to use (though I had minor issues as the documentation doesn't really tell me how to write a new frontend :P and that I needed to learn how machines work - especially keyboards)
* @iiegit for testing and more testing for the non-Windows version and helping a lot to get it on /r/sequence
# Known issues
## Port remains open (cannot bind to port)
**Fix:** Close all VirtualBox instances and wait 10 seconds.
**Cause:** Possibly it happens because the plugin creates the VBoxSVC process, which thus inherits file descriptors such as the open server port.
## OpenCL error
```
Check your environment. Failed to load codegen native library or possibly failed to locate opencl native library (opencl.dll/opencl.so). Ensure that OpenCL is in your PATH (windows) or in LD_LIBRARY_PATH (linux).
```
**Fix:** On Ubuntu you can install the needed library with `sudo apt install ocl-icd-opencl-dev`

View file

@ -16,6 +16,5 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="VirtualComputerSender.j4n.jar"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.NorbiPeti</groupId>
<artifactId>VirtualComputer</artifactId>
<version>2.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-g</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration />
</execution>
</executions>
</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>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>repo</id>
<url>file://${basedir}/repo</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<artifactId>commons-lang</artifactId>
<groupId>commons-lang</groupId>
</exclusion>
<exclusion>
<artifactId>json-simple</artifactId>
<groupId>com.googlecode.json-simple</groupId>
</exclusion>
<exclusion>
<artifactId>guava</artifactId>
<groupId>com.google.guava</groupId>
</exclusion>
<exclusion>
<artifactId>gson</artifactId>
<groupId>com.google.code.gson</groupId>
</exclusion>
<exclusion>
<artifactId>snakeyaml</artifactId>
<groupId>org.yaml</groupId>
</exclusion>
<exclusion>
<artifactId>bungeecord-chat</artifactId>
<groupId>net.md-5</groupId>
</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>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

Binary file not shown.

View file

@ -0,0 +1,3 @@
If a new version is released, copy this to the JAR into org/mozilla/interfaces
This fixes the source bitmap pointer return type in the Java API.

View file

@ -0,0 +1 @@
lombok.var.flagUsage = ALLOW

View file

@ -1,8 +0,0 @@
name: VirtualComputer
main: sznp.virtualcomputer.PluginMain
version: 1.1
commands:
computer:
usage: Use /computer start|stop
alias: c
softdepend: [Movecraft]

View file

@ -3,24 +3,8 @@
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.NorbiPeti</groupId>
<artifactId>VirtualComputer</artifactId>
<version>1.2-SNAPSHOT</version>
<version>2.0-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<resources>
<resource>
<directory>src</directory>
<excludes>
<exclude>**/*.java</exclude>
</excludes>
</resource>
<resource>
<directory>.</directory>
<includes>
<include>*.dll</include>
<include>*.yml</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
@ -28,6 +12,9 @@
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-g</arg> <!-- LocalVariableTable -->
</compilerArgs>
</configuration>
</plugin>
<plugin>
@ -41,16 +28,6 @@
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>org.virtualbox:VirtualBox</include>
</includes>
</artifactSet>
<pluginExecution>
<action>
<execute />
</action>
</pluginExecution>
</configuration>
</execution>
</executions>
@ -71,24 +48,103 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.9.2-R0.1-SNAPSHOT</version>
<version>1.12-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.countercraft</groupId>
<artifactId>Movecraft</artifactId>
<version>3.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.sf.jni4net</groupId>
<artifactId>jni4net.j</artifactId>
<version>0.8.8.0</version>
</dependency>
<dependency>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox</artifactId>
<version>5.1</version>
<version>6.0</version>
</dependency>
<dependency>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox-MSCOM</artifactId>
<version>6.0</version>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna -->
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>4.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.jnr/jnr-ffi -->
<dependency>
<groupId>com.github.jnr</groupId>
<artifactId>jnr-ffi</artifactId>
<version>2.1.7</version>
</dependency>
<dependency>
<groupId>com.aparapi</groupId>
<artifactId>aparapi</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>
<dependency> <!-- javax.annotations.Nullable -->
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<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>
</project>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox-MSCOM</artifactId>
<version>6.0</version>
<description>POM was created from install:install-file</description>
</project>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox-MSCOM</artifactId>
<versioning>
<release>6.0</release>
<versions>
<version>6.0</version>
</versions>
<lastUpdated>20190405225845</lastUpdated>
</versioning>
</metadata>

View file

@ -2,8 +2,8 @@
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>io.github.NorbiPeti</groupId>
<artifactId>SenderBridge</artifactId>
<version>1.0</version>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox</artifactId>
<version>5.1</version>
<description>POM was created from install:install-file</description>
</project>

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox</artifactId>
<version>5.2</version>
<description>POM was created from install:install-file</description>
</project>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox</artifactId>
<version>6.0</version>
<description>POM was created from install:install-file</description>
</project>

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<metadata>
<groupId>org.virtualbox</groupId>
<artifactId>VirtualBox</artifactId>
<versioning>
<release>6.0</release>
<versions>
<version>5.1</version>
<version>5.2</version>
<version>6.0</version>
</versions>
<lastUpdated>20181221211412</lastUpdated>
</versioning>
</metadata>

View file

@ -1,217 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap;
/*
* This file was originally taken from https://github.com/slipswhitley/SketchMap
*/
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import com.mcplugindev.slipswhitley.sketchmap.file.SketchMapFileException;
import com.mcplugindev.slipswhitley.sketchmap.map.RelativeLocation;
import com.mcplugindev.slipswhitley.sketchmap.map.SketchMap;
//import com.mcplugindev.slipswhitley.sketchmap.map.SketchMap.BaseFormat;
public class SketchMapAPI
{
public static SketchMap getMapByID(String id)
{
for (SketchMap map : SketchMap.getLoadedMaps())
{
if (map.getID().equalsIgnoreCase(id))
{
return map;
}
}
return null;
}
public static List<ItemStack> getOrderedItemSet(SketchMap map)
{
List<ItemStack> items = new ArrayList<ItemStack>();
for (int y = 0; y < map.getLengthY(); y++)
{
for (int x = 0; x < map.getLengthX(); x++)
{
for (RelativeLocation loc : map.getMapCollection().keySet())
{
if (loc.getX() != x || loc.getY() != y)
{
continue;
}
ItemStack iStack = new ItemStack(Material.MAP, 1);
iStack.setDurability(SketchMapUtils.getMapID(map
.getMapCollection().get(loc)));
ItemMeta iMeta = iStack.getItemMeta();
iMeta.setDisplayName(ChatColor.GREEN + "SketchMap ID: "
+ ChatColor.GOLD + map.getID() + ChatColor.GREEN
+ " Pos-X: " + ChatColor.GOLD + (x + 1)
+ ChatColor.GREEN + " Pos-Y: " + ChatColor.GOLD
+ (y + 1));
iMeta.setLore(Arrays.asList(new String[] { ChatColor.GRAY
+ "SketchMap ID: " + map.getID()
}));
iStack.setItemMeta(iMeta);
items.add(iStack);
}
}
}
return items;
}
public static SketchMap loadSketchMapFromFile(File file)
throws SketchMapFileException
{
YamlConfiguration config = null;
try
{
config = YamlConfiguration.loadConfiguration(file);
} catch (Exception ex)
{
throw new SketchMapFileException("Invalid SketchMap File \""
+ file.getName() + "\"");
}
String[] fieldSet = { "x-panes", "y-panes", "public-protected",
"map-collection", "base-format", "map-image", };
for (String field : fieldSet)
{
if (!config.isSet(field))
{
throw new SketchMapFileException(
"Unable to load SketchMap file \"" + file.getName()
+ "\" missing field \"" + field + "\"");
}
}
Integer xPanes = config.getInt("x-panes");
if (xPanes == null || xPanes < 1)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName() + "\" invalid field \"x-panes\"");
}
Integer yPanes = config.getInt("y-panes");
if (yPanes == null || yPanes < 1)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName() + "\" invalid field \"y-panes\"");
}
Boolean publicProtected = config.getBoolean("public-protected");
if (publicProtected == null)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName() + "\" invalid field \"public-protected\"");
}
List<String> mapList = config.getStringList("map-collection");
if (mapList == null)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName() + "\" invalid field \"map-collection\"");
}
Map<Short, RelativeLocation> mapCollection = new HashMap<Short, RelativeLocation>();
for (String map : mapList)
{
String[] split = map.split(" ");
if (split.length != 2)
{
throw new SketchMapFileException(
"Unable to load SketchMap file \"" + file.getName()
+ "\" cannot parse field in \"map-colection\"");
}
RelativeLocation loc = RelativeLocation.fromString(split[0]);
if (loc == null)
{
throw new SketchMapFileException(
"Unable to load SketchMap file \"" + file.getName()
+ "\" cannot parse field in \"map-colection\"");
}
Short id = null;
try
{
id = Short.parseShort(split[1]);
} catch (Exception ex)
{
throw new SketchMapFileException(
"Unable to load SketchMap file \"" + file.getName()
+ "\" cannot parse field in \"map-colection\"");
}
mapCollection.put(id, loc);
}
//BaseFormat format = null;
/*
* try {
* format = BaseFormat.valueOf(config.getString("base-format"));
* }
* catch (Exception ex) {
* throw new SketchMapFileException("Unable to load SketchMap file \"" +
* file.getName()
* + "\" cannot parse BaseFormat from field \"base-format\"");
* }
*/
String b64Img = config.getString("map-image");
if (b64Img == null)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName() + "\" invalid field \"map-image\"");
}
BufferedImage image = null;
try
{
image = SketchMapUtils.base64StringToImg(b64Img);
} catch (Exception ex)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName()
+ "\" parse image from field \"map-image\"");
}
String imageID = file.getName().substring(0,
file.getName().lastIndexOf("."));
if (getMapByID(imageID) != null)
{
throw new SketchMapFileException("Unable to load SketchMap file \""
+ file.getName()
+ "\" A SketchMap by that ID already exists.");
}
return new SketchMap(image, imageID, yPanes, yPanes, publicProtected);
}
}

View file

@ -1,54 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap;
/*
* This file was originally taken from https://github.com/slipswhitley/SketchMap
*/
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.plugin.java.JavaPlugin;
import com.mcplugindev.slipswhitley.sketchmap.listener.PlayerListener;
public class SketchMapPlugin extends JavaPlugin
{
private static SketchMapPlugin plugin;
public void onEnable()
{
plugin = this;
setupListeners();
sendEnabledMessage();
}
private void sendEnabledMessage()
{
SketchMapUtils.sendColoredConsoleMessage(ChatColor.GREEN
+ "| |");
SketchMapUtils.sendColoredConsoleMessage(ChatColor.GREEN + "| "
+ ChatColor.AQUA + "SketchMap "
+ this.getDescription().getVersion() + " has been Enabled!"
+ ChatColor.GREEN + " |");
SketchMapUtils.sendColoredConsoleMessage(ChatColor.GREEN + "| "
+ ChatColor.AQUA + " Authors: SlipsWhitley & Fyrinlight"
+ ChatColor.GREEN + " |");
SketchMapUtils.sendColoredConsoleMessage(ChatColor.GREEN
+ "| |");
}
private void setupListeners()
{
Bukkit.getPluginManager().registerEvents(new PlayerListener(), this);
}
public static SketchMapPlugin getPlugin()
{
return plugin;
}
}

View file

@ -1,109 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap;
/*
* This file was originally taken from https://github.com/slipswhitley/SketchMap
*/
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Base64;
import java.util.HashSet;
import javax.imageio.ImageIO;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.map.MapView;
public class SketchMapUtils
{
/**
*
* Image Utils
*
*/
public static BufferedImage resize(Image img, Integer width, Integer height)
{
img = img.getScaledInstance(width, height, Image.SCALE_SMOOTH);
if (img instanceof BufferedImage)
{
return (BufferedImage) img;
}
BufferedImage bimage = new BufferedImage(img.getWidth(null),
img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
Graphics2D bGr = bimage.createGraphics();
bGr.drawImage(img, 0, 0, null);
bGr.dispose();
return bimage;
}
public static BufferedImage base64StringToImg(final String base64String)
{
try
{
return ImageIO.read(new ByteArrayInputStream(Base64.getDecoder()
.decode(base64String)));
} catch (final IOException ioe)
{
throw new UncheckedIOException(ioe);
}
}
public static void sendColoredConsoleMessage(String msg)
{
ConsoleCommandSender sender = Bukkit.getConsoleSender();
sender.sendMessage(msg);
}
/**
* Deprecated Methods Here :'c
*/
@SuppressWarnings("deprecation")
public static short getMapID(MapView map)
{
return map.getId();
}
@SuppressWarnings("deprecation")
public static MapView getMapView(short id)
{
MapView map = Bukkit.getMap(id);
if (map != null)
{
return map;
}
return Bukkit.createMap(getDefaultWorld());
}
/**
*
*/
public static Block getTargetBlock(Player player, int i)
{
return player.getTargetBlock((HashSet<Material>) null, i);
}
public static World getDefaultWorld()
{
return Bukkit.getWorlds().get(0);
}
}

View file

@ -1,14 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap.file;
public class SketchMapFileException extends Exception {
/**
*
*/
private static final long serialVersionUID = 1L;
public SketchMapFileException(String message) {
super(message);
}
}

View file

@ -1,69 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap.listener;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractEntityEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class PlayerListener implements Listener {
@EventHandler
public void onPlayerInteract(PlayerInteractEntityEvent event) {
if(!(event.getRightClicked() instanceof ItemFrame)) {
return;
}
ItemFrame iFrame = (ItemFrame) event.getRightClicked();
ItemStack iHand = event.getPlayer().getItemInHand();
if(iHand.getType() != Material.MAP) {
return;
}
String lore = iHand.getItemMeta().getLore().get(0);
if(!ChatColor.stripColor(lore).startsWith("SketchMap ID:")) {
return;
}
if(iFrame.getItem().getType() != Material.AIR) {
return;
}
if(event.isCancelled()) {
return;
}
event.setCancelled(true);
ItemStack frameItem = iHand.clone();
frameItem.setAmount(1);
ItemMeta frameIMeta = frameItem.getItemMeta();
frameIMeta.setDisplayName("");
frameItem.setItemMeta(frameIMeta);
iFrame.setItem(frameItem);
Player player = event.getPlayer();
if(player.getGameMode() == GameMode.CREATIVE) {
return;
}
if(iHand.getAmount() == 1) {
player.getInventory().setItemInHand(new ItemStack(Material.AIR));
return;
}
iHand.setAmount(iHand.getAmount() - 1);
}
}

View file

@ -1,53 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap.map;
import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;
import org.bukkit.entity.Player;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
public class ImageRenderer extends MapRenderer
{
private BufferedImage image;
public ImageRenderer(BufferedImage image)
{
this.image = image;
}
private int progress = 0;
public static int updatepixels = 15;
@Override
public void render(MapView view, MapCanvas canvas, Player player)
{
long time = System.nanoTime();
try
{
canvas.drawImage(0, progress * updatepixels, image.getSubimage(0,
progress * updatepixels, 128, (progress * updatepixels
+ updatepixels >= 128 ? 128 - progress
* updatepixels : updatepixels)));
if (progress < 128 / updatepixels)
progress++;
else
progress = 0;
long diff = System.nanoTime() - time;
if (TimeUnit.NANOSECONDS.toMillis(diff) > 40)
{
System.out.println("Map rendering took "
+ TimeUnit.NANOSECONDS.toMillis(diff) + " ms");
}
} catch (Exception e)
{
e.printStackTrace();
System.out.println("Progess: " + progress);
System.out.println("UpdatePixels: " + updatepixels);
}
}
}

View file

@ -1,53 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap.map;
public class RelativeLocation {
private int x;
private int y;
public RelativeLocation (int x, int y) {
this.x = x;
this.y = y;
}
public String toString() {
return x + ":" + y;
}
public static RelativeLocation fromString(String str) {
String[] args = str.split(":");
if(args.length != 2) {
return null;
}
int x = 0;
int y = 0;
try {
x = Integer.parseInt(args[0]);
y = Integer.parseInt(args[1]);
}
catch (Exception ex) {
return null;
}
return new RelativeLocation (x, y);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}

View file

@ -1,220 +0,0 @@
package com.mcplugindev.slipswhitley.sketchmap.map;
/*
* This file was originally taken from https://github.com/slipswhitley/SketchMap
*/
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.bukkit.Bukkit;
import org.bukkit.map.MapView;
import com.mcplugindev.slipswhitley.sketchmap.SketchMapUtils;
public class SketchMap
{
public BufferedImage image;
private String mapID;
private Integer xPanes;
private Integer yPanes;
private Boolean publicProtected;
//private BaseFormat format;
private Map<RelativeLocation, MapView> mapCollection;
/**
*
* Create SketchMap using New Maps
*
*/
public SketchMap(BufferedImage image, String mapID, int xPanes, int yPanes,
boolean publicProtected)
{
this.image = SketchMapUtils.resize(image, xPanes * 128, yPanes * 128);
this.mapID = mapID;
this.xPanes = xPanes;
this.yPanes = yPanes;
this.publicProtected = publicProtected;
//this.format = format;
this.mapCollection = new HashMap<RelativeLocation, MapView>();
getLoadedMaps().add(this);
loadSketchMap();
}
private void loadSketchMap()
{
for (int x = 0; x < xPanes; x++)
{
for (int y = 0; y < yPanes; y++)
{
initMap(x, y,
Bukkit.createMap(SketchMapUtils.getDefaultWorld()));
}
}
}
/**
*
* Create SketchMap using Specified Maps
*
*/
public SketchMap(BufferedImage image, String mapID, int xPanes, int yPanes,
boolean publicProtected, Map<Short, RelativeLocation> mapCollection)
{
this.image = SketchMapUtils.resize(image, xPanes * 128, yPanes * 128);
this.mapID = mapID;
this.xPanes = xPanes;
this.yPanes = yPanes;
this.publicProtected = publicProtected;
//this.format = format;
this.mapCollection = new HashMap<RelativeLocation, MapView>();
getLoadedMaps().add(this);
loadSketchMap(mapCollection);
}
private void loadSketchMap(Map<Short, RelativeLocation> mapCollection)
{
for (Short mapID : mapCollection.keySet())
{
RelativeLocation loc = mapCollection.get(mapID);
initMap(loc.getX(), loc.getY(), SketchMapUtils.getMapView(mapID));
}
}
/**
*
*
*
*/
private void initMap(int x, int y, MapView mapView)
{
BufferedImage subImage = image.getSubimage(x * 128, y * 128, 128, 128);
mapView.getRenderers().clear();
mapView.addRenderer(new ImageRenderer(subImage));
mapCollection.put(new RelativeLocation(x, y), mapView);
}
/**
*
* Get Object information
*
*/
public String getID()
{
return mapID;
}
public BufferedImage getImage()
{
return image;
}
public int getLengthX()
{
return xPanes;
}
public int getLengthY()
{
return yPanes;
}
public boolean isPublicProtected()
{
return publicProtected;
}
public Map<RelativeLocation, MapView> getMapCollection()
{
return mapCollection;
}
/*
* public BaseFormat getBaseFormat() {
* return format;
* }
*/
/**
*
* Map Functions
*
*
*/
public void delete()
{
getLoadedMaps().remove(this);
try
{
this.finalize();
} catch (Throwable e)
{
}
}
/**
*
* Static Methods
*
*/
private static Set<SketchMap> sketchMaps;
public static Set<SketchMap> getLoadedMaps()
{
if (sketchMaps == null)
{
sketchMaps = new HashSet<SketchMap>();
}
return sketchMaps;
}
/*
* public enum BaseFormat {
* PNG,
* JPEG;
*
* public String getExtension() {
* if(this == BaseFormat.PNG) {
* return "png";
* }
* if(this == BaseFormat.JPEG) {
* return "jpg";
* }
* return null;
* }
*
* public static BaseFormat fromExtension(String ext) {
* if(ext.equalsIgnoreCase("png")) {
* return BaseFormat.PNG;
*
* }
* if(ext.equalsIgnoreCase("jpg")) {
* return BaseFormat.JPEG;
* }
* return null;
* }
* }
*/
}

View file

@ -0,0 +1,162 @@
package sznp.virtualcomputer;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.virtualbox_6_0.VBoxException;
public class Commands implements CommandExecutor {
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
if (args.length == 0)
return false;
switch (args[0].toLowerCase()) {
case "start":
case "poweron":
case "on":
case "startup":
int c = getMachineIndex(args);
if (c == -1) {
sender.sendMessage("§cUsage: /" + label + " start [index]");
return true;
}
Computer.getInstance().Start(sender, c);
break;
case "stop":
case "poweroff":
case "off":
case "shutdown":
case "kill":
Computer.getInstance().Stop(sender);
break;
case "powerbutton":
case "pwrbtn":
case "powerbtn":
c = getMachineIndex(args);
if (c == -1) {
sender.sendMessage("§cUsage: /" + label + " powerbutton [index]");
return true;
}
Computer.getInstance().PowerButton(sender, c);
break;
case "reset":
case "restart":
Computer.getInstance().Reset(sender);
break;
case "fix":
case "fixscreen":
Computer.getInstance().FixScreen(sender);
break;
case "key":
case "press":
case "presskey":
case "keypress":
if (args.length < 2) {
sender.sendMessage("§cUsage: /computer key <key> [down/up|duration(ticks)]");
return true;
}
if (args.length < 3)
Computer.getInstance().PressKey(sender, args[1], "");
else
Computer.getInstance().PressKey(sender, args[1], args[2]);
break;
case "mouse":
boolean showusage = true;
if (args.length < 6) {
try {
// Command overloading, because I can :P
if (args.length > 4) // 4<x<6
{
Computer.getInstance().UpdateMouse(sender, Integer.parseInt(args[1]), Integer.parseInt(args[2]),
Integer.parseInt(args[3]), Integer.parseInt(args[4]), "", false);
showusage = false;
} else {
if (args.length == 3) {
Computer.getInstance().UpdateMouse(sender, 0, 0, 0, 0, args[1], args[2].equals("down"));
showusage = false;
} else if (args.length == 2) {
Computer.getInstance().UpdateMouse(sender, 0, 0, 0, 0, args[1]);
showusage = false;
}
}
}
catch (VBoxException e) {
e.printStackTrace();
}
catch (Exception ignored) { //It will show the usage here
}
}
if (showusage) {
sender.sendMessage("§cUsage: /computer mouse <relx> <rely> <relz> <relw>");
sender.sendMessage("§cOr: /computer mouse <button> [up/down]");
}
break;
case "input":
case "show":
case "showinput":
case "shinput": {
if (!(sender instanceof Player)) {
sender.sendMessage("§cError: Only players can use this command.");
return true;
}
if (args.length < 2) {
sender.sendMessage("§cUsage: /computer input <key|mouse>");
return true;
}
switch (args[1].toLowerCase()) {
case "key":
case "keyboard":
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName()
+ " [\"\",{\"text\":\" [0]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D0\"}},{\"text\":\" [1]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D1\"}},{\"text\":\" [2]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D2\"}},{\"text\":\" [3]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D3\"}},{\"text\":\" [4]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D4\"}},{\"text\":\" [5]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D5\"}},{\"text\":\" [6]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D6\"}},{\"text\":\" [7]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D7\"}},{\"text\":\" [8]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D8\"}},{\"text\":\" [9]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D9\"}}]");
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName()
+ " [\"\",{\"text\":\" [Tab]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Tab\"}},{\"text\":\" [Q]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Q\"}},{\"text\":\" [W]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key W\"}},{\"text\":\" [E]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key E\"}},{\"text\":\" [R]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key R\"}},{\"text\":\" [T]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key T\"}},{\"text\":\" [Y]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Y\"}},{\"text\":\" [U]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key U\"}},{\"text\":\" [I]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key I\"}},{\"text\":\" [O]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key O\"}},{\"text\":\" [P]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key P\"}}]");
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName()
+ " [\"\",{\"text\":\" [CapsLock]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key CapsLock\"}},{\"text\":\" [A]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key A\"}},{\"text\":\" [S]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key S\"}},{\"text\":\" [D]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D\"}},{\"text\":\" [F]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key F\"}},{\"text\":\" [G]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key G\"}},{\"text\":\" [H]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key H\"}},{\"text\":\" [J]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key J\"}},{\"text\":\" [K]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key K\"}},{\"text\":\" [L]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key L\"}},{\"text\":\" [Enter]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Enter\"}}]");
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName()
+ " [\"\",{\"text\":\" [Z]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Z\"}},{\"text\":\" [X]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key X\"}},{\"text\":\" [C]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key C\"}},{\"text\":\" [V]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key V\"}},{\"text\":\" [B]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key B\"}},{\"text\":\" [N]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key N\"}},{\"text\":\" [M]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key M\"}}]");
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), "tellraw " + sender.getName()
+ " [\"\",{\"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;
case "mouse":
MouseLockerPlayerListener.toggleLock((Player) sender);
break;
case "mspeed":
case "mousespeed":
if (args.length < 3) {
sender.sendMessage("§cUsage: /computer input mspeed <number>");
return true;
}
try {
MouseLockerPlayerListener.LockedSpeed = Float.parseFloat(args[2]);
} catch(NumberFormatException e) {
sender.sendMessage("§cThe speed must be a number.");
break;
}
sender.sendMessage("§aMouse speed set to " + MouseLockerPlayerListener.LockedSpeed);
}
break;
}
}
return true;
}
/**
* Checks the 2nd parameter
*
* @return The index of the machine or -1 on usage error
*/
private int getMachineIndex(String[] args) {
int c = 0;
if (args.length >= 2) {
try {
c = Integer.parseInt(args[1]);
} catch (Exception ignored) {
return -1;
}
}
return c;
}
}

View file

@ -0,0 +1,235 @@
package sznp.virtualcomputer;
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.events.MachineEventHandler;
import sznp.virtualcomputer.events.VBoxEventHandler;
import sznp.virtualcomputer.renderer.GPURenderer;
import sznp.virtualcomputer.renderer.MCFrameBuffer;
import sznp.virtualcomputer.util.Scancode;
import javax.annotation.Nullable;
import java.util.Arrays;
public final class Computer {
@Getter
private static Computer instance;
private final PluginMain plugin;
private ISession session;
private IVirtualBox vbox;
private IMachine machine;
private MachineEventHandler handler;
private IEventListener listener;
private VirtualBoxManager manager;
@java.beans.ConstructorProperties({"plugin"})
public Computer(PluginMain plugin, VirtualBoxManager manager, IVirtualBox vbox) {
this.plugin = plugin;
this.manager = manager;
session = manager.getSessionObject();
this.vbox = vbox;
if (instance != null) throw new IllegalStateException("A computer already exists!");
instance = this;
}
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
VBoxEventHandler.getInstance().setup(machine.getId(), sender); //TODO: Sometimes null
} catch (VBoxException e) {
if (e.getResultCode() == 0x80070005) { //lockMachine: "The object functionality is limited"
sendMessage(sender, "§6Cannot start computer, the machine may be inaccessible");
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 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());
}
}
});
}
/**
* Gets called when the machine is locked after {@link #Start(CommandSender, int)}
*
* @param sender The sender which started the machine
*/
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
handler.setProgress(progress);
handler.registerTo(progress.getEventSource()); //TODO: Show progress bar some way?
console.getDisplay().attachFramebuffer(0L,
new IFramebuffer(new MCFrameBuffer(console.getDisplay(), true)));
}
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)) {
onMachineStop(sender); //Needed for session reset
sendMessage(sender, "§eComputer was already off, released it.");
}
return;
}
sendMessage(sender, "§eStopping computer...");
session.getConsole().powerDown();
}
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 = Scancode.getCode("sc_" + key.toLowerCase());
if (code == -1) {
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) throws Exception {
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 Exception("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) throws Exception {
if (checkMachineNotRunning(sender))
return;
UpdateMouse(sender, x, y, z, w, mbs, true);
UpdateMouse(sender, x, y, z, w, mbs, false);
}
public void onMachineStart(CommandSender sender) {
sendMessage(sender, "§eComputer started.");
}
public void onMachineStop(CommandSender sender) {
Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> {
if (session.getState() == SessionState.Locked) {
session.unlockMachine(); //Needs to be outside of the event handler
handler = null;
machine = null;
session = manager.getSessionObject();
sendMessage(sender, "§eComputer powered off."); //This block runs later
}
});
GPURenderer.update(new byte[1], 0, 0, 0, 0, 640, 480); //Black screen
stopEvents();
MouseLockerPlayerListener.computerStop();
}
public void stopEvents() {
/*if(session!=null && listener!=null)
session.getConsole().getEventSource().unregisterListener(listener);*/
if (listener != null)
handler.disable();
listener = null;
}
public void pluginDisable(CommandSender ccs) {
stopEvents();
if (session.getState() == SessionState.Locked) {
if (session.getMachine().getState().equals(MachineState.Running)) {
ccs.sendMessage("§aSaving machine state...");
session.getMachine().saveState().waitForCompletion(10000);
}
session.unlockMachine();
}
}
}

View file

@ -0,0 +1,57 @@
package sznp.virtualcomputer;
import org.bukkit.Location;
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 java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class MouseLockerPlayerListener implements Runnable, Listener {
private static final Map<Player, Location> LockedPlayers = new HashMap<>();
public static float LockedSpeed = 5;
@Override
public void run() {
for (Entry<Player, Location> entry : LockedPlayers.entrySet()) {
float yaw1 = entry.getValue().getYaw();
float pitch1 = entry.getValue().getPitch();
float yaw2 = entry.getKey().getLocation().getYaw();
float pitch2 = entry.getKey().getLocation().getPitch();
if (yaw2 - yaw1 == 0 || pitch2 - pitch1 == 0)
return;
try {
Computer.getInstance().UpdateMouse(null, (int) ((yaw2 - yaw1) * LockedSpeed),
(int) ((pitch2 - pitch1) * LockedSpeed), 0, 0, "");
} catch (Exception e) { //Should not happen
e.printStackTrace();
}
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

@ -0,0 +1,129 @@
package sznp.virtualcomputer;
import jnr.ffi.LibraryLoader;
import lombok.val;
import org.bukkit.Bukkit;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.virtualbox_6_0.IEventListener;
import org.virtualbox_6_0.IVirtualBox;
import org.virtualbox_6_0.VirtualBoxManager;
import sznp.virtualcomputer.events.VBoxEventHandler;
import sznp.virtualcomputer.renderer.BukkitRenderer;
import sznp.virtualcomputer.renderer.GPURenderer;
import sznp.virtualcomputer.renderer.IRenderer;
import sznp.virtualcomputer.util.Utils;
import sznp.virtualcomputer.util.VBoxLib;
import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Predicate;
public class PluginMain extends JavaPlugin {
private static final int MCX = 5;
private static final int MCY = 4;
private BukkitTask mousetask;
private IEventListener listener;
public static PluginMain Instance;
//public static ByteBuffer allpixels = ByteBuffer.allocate(640 * 480 * 4); // It's set on each change
/**
* Only used if {@link #direct} is false.
*/
public static ByteBuffer allpixels; // It's set on each change
private static ArrayList<IRenderer> renderers = new ArrayList<>();
/*
* Only used if {@link #direct} is true.
*/
//public static PXCLib pxc;
public static boolean direct;
public static boolean sendAll;
// Fired when plugin is first enabled
@Override
public void onEnable() {
Instance = this;
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"
: "/opt/virtualbox";
//noinspection ConstantConditions
Predicate<File> notGoodDir= ff->!ff.isDirectory() || Arrays.stream(ff.list()).noneMatch(s -> s.contains("xpcom"));
if (notGoodDir.test(new File(vbpath)))
vbpath = "/usr/lib/virtualbox";
if(notGoodDir.test(new File(vbpath)))
error("Could not find VirtualBox! Download from https://www.virtualbox.org/wiki/Downloads");
if (System.getProperty("vbox.home") == null || System.getProperty("vbox.home").isEmpty())
System.setProperty("vbox.home", vbpath);
if (System.getProperty("sun.boot.library.path") == null
|| System.getProperty("sun.boot.library.path").isEmpty())
System.setProperty("sun.boot.library.path", vbpath);
if (System.getProperty("java.library.path") == null || System.getProperty("java.library.path").isEmpty())
System.setProperty("java.library.path", vbpath);
Utils.addLibraryPath(vbpath);
final VirtualBoxManager manager = VirtualBoxManager.createInstance(getDataFolder().getAbsolutePath());
VBoxLib vbl = LibraryLoader.create(VBoxLib.class).load("vboxjxpcom"); //TODO: Test for MSCOM
vbl.RTR3InitExe(0, "", 0);
IVirtualBox vbox = manager.getVBox();
listener = new VBoxEventHandler().registerTo(vbox.getEventSource());
new Computer(this, manager, vbox); //Saves itself
ccs.sendMessage("§bLoading Screen...");
try {
//throw new NoClassDefFoundError("Test error pls ignore");
for (short i = 0; i < MCX; i++)
for (short j = 0; j < MCY; 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");
direct=true;
ccs.sendMessage("§bUsing Direct Renderer, all good");
} catch (NoClassDefFoundError | Exception e) {
for (short i = 0; i < 20; i++)
renderers.add(new BukkitRenderer(i, Bukkit.getWorlds().get(0), i * 128 * 128 * 4));
direct=false;
e.printStackTrace();
ccs.sendMessage("§6Compatibility error, using slower renderer");
}
ccs.sendMessage("§bLoaded!");
val mlpl = new MouseLockerPlayerListener();
mousetask = getServer().getScheduler().runTaskTimer(this, mlpl, 0, 0);
getServer().getPluginManager().registerEvents(mlpl, this);
} catch (final Exception e) {
e.printStackTrace();
error(e.getMessage());
}
}
private void error(String message) {
getLogger().severe("A fatal error occured, disabling plugin!");
Bukkit.getPluginManager().disablePlugin(this);
throw new RuntimeException(message);
}
// Fired when plugin is disabled
@Override
public void onDisable() {
ConsoleCommandSender ccs = getServer().getConsoleSender();
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)
}*/
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.");
saveConfig();
}
}

View file

@ -0,0 +1,107 @@
package sznp.virtualcomputer;
import com.aparapi.Kernel;
import com.aparapi.Range;
import com.sun.jna.Pointer;
import jnr.ffi.LibraryLoader;
import org.bukkit.Color;
import org.bukkit.map.MapPalette;
import sznp.virtualcomputer.util.PXCLib;
import java.io.File;
import java.lang.reflect.Field;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.util.stream.IntStream;
public class Test {
private int[] x = new int[]{10};
@SuppressWarnings("deprecation")
public static void main(String[] args) {
/*System.out.println(new File("").getAbsolutePath());
PXCLib pxc = LibraryLoader.create(PXCLib.class).search(new File("").getAbsolutePath()).load("pxc");
ByteBuffer bb = ByteBuffer.allocateDirect(2);
long[] x = new long[]{Pointer.nativeValue(Native.getDirectBufferPointer(bb))};
pxc.convert(new int[]{5, 10}, x);
System.out.println(bb.get(0)); //19 AYY //TO!DO: Use setSource, we don't want to wrap the native array*/
//final int[] a={5,6,8,2,3,10,5,26,5,416,41,85,416,41};
//final int[] b={10,80,10,3,32,20,56,85,51,968,156,5894,10,60,52};
//final int[] a={5,6};
//final int[] b={10,80};
int[] a = IntStream.range(0, 640 * 480).toArray();
final int[] res = new int[a.length];
//java.awt.Color tc=new java.awt.Color(0);
/*GPURenderer gr;
try {
gr=new GPURenderer((short) 0, null, 0, 0);
} catch (Exception e) {
e.printStackTrace();
return;
}*/
//gr.pixels=new byte[1];
int[] x = new Test().x;
Kernel kernel=new Kernel() {
@Override
public void run() {
int i=getGlobalId();
//System.out.println(i);
//res[i]=a[i]+b[i];
//res[i]= MapPalette.matchColor(a[i] & 0x0000FF, a[i] & 0x00FF00 >> 8, a[i] & 0xFF0000 >> 16);
//res[i] = a[i];
//res[i]=tc.getBlue();
//gr.pixels[0]=5;
res[i] = x[0];
//GPURenderer.px[0]=10;
//GPURendererInternal.test[0]=10; - LAMBDAS
}
};
long t = System.nanoTime();
kernel.put(a).execute(Range.create(res.length)).get(res);
//System.out.println(Arrays.toString(res));
System.out.println(a[10]);
System.out.println("OpenCL time: "+(System.nanoTime()-t)/1000000f+"ms");
a[50] = 652; //Massive speedups after the fist pass
t = System.nanoTime();
kernel.put(a).execute(Range.create(res.length)).get(res);
System.out.println(a[10]);
System.out.println("Second OpenCL time: " + (System.nanoTime() - t) / 1000000f + "ms");
t=System.nanoTime();
for (int i = 0; i < res.length; i++) {
Color c = Color.fromBGR(a[i]);
res[i]= MapPalette.matchColor(c.getRed(), c.getGreen(), c.getBlue());
}
System.out.println("For loop time: "+(System.nanoTime()-t)/1000000f+"ms");
t=System.nanoTime();
System.arraycopy(a, 0, res, 0, res.length);
System.out.println("Sys time: "+(System.nanoTime()-t)/1000000f+"ms");
PXCLib pxc = LibraryLoader.create(PXCLib.class).search(new File("").getAbsolutePath()).load("pxc");
ByteBuffer bb = ByteBuffer.allocateDirect(640 * 480 * 4);
try {
Field f=Buffer.class.getDeclaredField("address");
f.setAccessible(true);
long addr= (long) f.get(bb);
pxc.setSource(addr, 640, 480, 5, 4);
t = System.nanoTime();
long p = pxc.updateAndGetMap(0, 0, 640, 480, null);
if (p == 0) return;
byte[] img = new Pointer(p).getByteArray(0, 128 * 128);
System.out.println("img[50]: " + img[50]);
System.out.println("Native time: " + (System.nanoTime() - t) / 1000000f + "ms");
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
kernel = new Kernel() {
@Override
public void run() {
PXCLib pxc = LibraryLoader.create(PXCLib.class).search(new File("").getAbsolutePath()).load("pxc");
pxc.updateAndGetMap(0, 0, 0, 0, null);
}
};
kernel.execute(Range.create(1));
}
}

View file

@ -0,0 +1,63 @@
package sznp.virtualcomputer.events;
import lombok.val;
import org.bukkit.Bukkit;
import org.mozilla.interfaces.IEvent;
import org.mozilla.interfaces.IEventListener;
import org.virtualbox_6_0.IEventSource;
import org.virtualbox_6_0.VBoxEventType;
import sznp.virtualcomputer.util.COMObjectBase;
import sznp.virtualcomputer.util.Utils;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
/**
* A Bukkit-like event system which calls the appropriate methods on an event.
*/
public abstract class EventHandlerBase extends COMObjectBase implements IEventListener {
/**
* The events to listen for. It will only look for these handlers.
*/
private final Map<VBoxEventType, Class<? extends org.virtualbox_6_0.IEvent>> eventMap;
private boolean enabled = true;
protected EventHandlerBase(Map<VBoxEventType, Class<? extends org.virtualbox_6_0.IEvent>> eventMap) {
//this.eventMap = eventMap.entrySet().stream().collect(Collectors.toMap(e -> e.getKey().value(), Map.Entry::getValue));
this.eventMap = eventMap;
}
@Override
public final void handleEvent(IEvent iEvent) {
//val cl=eventMap.get((int)iEvent.getType()); - We can afford to search through the events for this handler
if (!enabled)
return;
val kv = eventMap.entrySet().stream().filter(e -> e.getKey().value() == iEvent.getType()).findAny();
if (!kv.isPresent()) return; //Event not supported
val cl = kv.get().getValue();
for (Method method : getClass().getMethods()) {
if (method.isAnnotationPresent(org.bukkit.event.EventHandler.class)
&& method.getParameterCount() == 1 && method.getParameterTypes()[0] == cl) {
try {
method.invoke(this, Utils.getEvent(iEvent, cl));
return;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
Bukkit.getLogger().warning("Error while handling VirtualBox event!");
e.getCause().printStackTrace();
}
}
}
}
public <T extends EventHandlerBase> org.virtualbox_6_0.IEventListener registerTo(IEventSource source) {
return Utils.registerListener(source, this, new ArrayList<>(eventMap.keySet()));
}
public void disable() {
enabled = false;
}
}

View file

@ -0,0 +1,67 @@
package sznp.virtualcomputer.events;
import com.google.common.collect.ImmutableMap;
import lombok.Setter;
import lombok.experimental.var;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.virtualbox_6_0.IProgress;
import org.virtualbox_6_0.IStateChangedEvent;
import org.virtualbox_6_0.VBoxEventType;
import sznp.virtualcomputer.Computer;
import sznp.virtualcomputer.PluginMain;
import java.util.logging.Logger;
public class MachineEventHandler extends EventHandlerBase {
private final Computer computer;
private final CommandSender sender;
private boolean starting = false;
@Setter
private IProgress progress;
public MachineEventHandler(Computer computer, CommandSender sender) {
super(ImmutableMap.of(VBoxEventType.OnStateChanged, IStateChangedEvent.class));
//VBoxEventType.OnProgressPercentageChanged, IProgressPercentageChangedEvent.class)); - Doesn't fire at all, the complete event only fires on success
this.computer = computer;
this.sender = sender;
}
@EventHandler
public void handleStateChange(IStateChangedEvent event) { //https://www.virtualbox.org/sdkref/_virtual_box_8idl.html#a80b08f71210afe16038e904a656ed9eb
switch (event.getState()) {
case Stuck:
computer.Stop(null);
break;
case PoweredOff:
case Saved:
if (starting) {
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, () -> {
progress.waitForCompletion(-1);
if (progress != null && 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("----------------");
l.warning("VBox: " + info.getText());
l.warning("Component: " + info.getComponent());
}
}
});
}
computer.onMachineStop(sender);
break;
case Starting:
starting = true;
break;
case Running:
starting = false;
computer.onMachineStart(sender);
break;
}
}
}

View file

@ -0,0 +1,34 @@
package sznp.virtualcomputer.events;
import com.google.common.collect.ImmutableMap;
import lombok.Getter;
import org.bukkit.command.CommandSender;
import org.bukkit.event.EventHandler;
import org.virtualbox_6_0.ISessionStateChangedEvent;
import org.virtualbox_6_0.SessionState;
import org.virtualbox_6_0.VBoxEventType;
import sznp.virtualcomputer.Computer;
public class VBoxEventHandler extends EventHandlerBase {
public VBoxEventHandler() {
super(ImmutableMap.of(VBoxEventType.OnSessionStateChanged, ISessionStateChangedEvent.class));
instance = this;
}
@Getter
private static VBoxEventHandler instance;
private String machineID;
private CommandSender sender;
@EventHandler
public void onSessionStateChange(ISessionStateChangedEvent event) {
if (!event.getMachineId().equals(machineID)) return;
if (event.getState() == SessionState.Locked) //Need to check here, because we can't access the console yet
Computer.getInstance().onLock(sender);
}
public void setup(String machineID, CommandSender sender) {
this.machineID = machineID;
this.sender = sender;
}
}

View file

@ -0,0 +1,83 @@
package sznp.virtualcomputer.renderer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapRenderer;
import org.bukkit.map.MapView;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;
public class BukkitRenderer extends MapRenderer implements IRenderer {
private ByteBuffer allpixels;
private BufferedImage image;
private int startindex;
/**
* The raw pixel data from the machine in BGRA format
*/
public void setAllPixels(ByteBuffer allpixels) {
this.allpixels = allpixels;
}
/**
* Generic implementation, should work on most versions
*
* @param id
* The ID of the current map
* @param world
* The world to create new maps in
* @param startindex
* The index to start from in allpixels
*/
public BukkitRenderer(short id, World world, int startindex) {
MapView map = IRenderer.prepare(id, world);
map.addRenderer(this);
this.startindex = startindex;
image = new BufferedImage(128, 128, BufferedImage.TYPE_INT_RGB);
}
private int progress = 0;
public static int updatepixels = 15;
@Override
public void render(MapView view, MapCanvas canvas, Player player) {
if (allpixels == null)
return;
long time = System.nanoTime();
final int[] a = ((DataBufferInt) image.getRaster().getDataBuffer()).getData(); // Directly update the bytes of the image
// (byte) bgra to rgb (int)
for (int i = startindex, j = 0; i < startindex + 128 * 128; i = i + 4, j++) {
int b, g, r;
b = allpixels.get(i) & 0xFF; //TODO: <-- IndexOutOfBoundsException sometimes
g = allpixels.get(i + 1) & 0xFF;
r = allpixels.get(i + 2) & 0xFF;
a[j] = (r << 16) | (g << 8) | b;
}
try {
canvas.drawImage(0, progress * updatepixels, image.getSubimage(0, progress * updatepixels, 128,
(progress * updatepixels + updatepixels >= 128 ? 128 - progress * updatepixels : updatepixels)));
if (progress < 128 / updatepixels)
progress++;
else
progress = 0;
long diff = System.nanoTime() - time;
if (TimeUnit.NANOSECONDS.toMillis(diff) > 40) {
System.out.println("Map rendering took " + TimeUnit.NANOSECONDS.toMillis(diff) + " ms");
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Progess: " + progress);
System.out.println("UpdatePixels: " + updatepixels);
}
}
}

View file

@ -0,0 +1,117 @@
package sznp.virtualcomputer.renderer;
import net.minecraft.server.v1_12_R1.WorldMap;
import org.bukkit.World;
import org.bukkit.entity.Player;
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 final GPURendererInternal kernel;
private WorldMap wmap;
private int mapx, mapy;
//Store at central location after conversion
private static int[] colors_;
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) {
kernel = null;
return; //Testing
}
if (colors_ == null) {
Field field = MapPalette.class.getDeclaredField("colors");
field.setAccessible(true);
Color[] cs = (Color[]) field.get(null);
colors_ = new int[cs.length];
for (int i = 0; i < colors_.length; i++) {
colors_[i] = cs[i].getRGB();
}
}
this.mapx = mapx;
this.mapy = mapy;
Field field = map.getClass().getDeclaredField("worldMap");
field.setAccessible(true);
wmap = (WorldMap) field.get(map);
kernel = new GPURendererInternal(mapx, mapy, colors_);
renderers.add(this);
map.addRenderer(this);
}
@Override
public void render(MapView map, MapCanvas canvas, Player player) {
Timing t = new Timing();
try {
if (kernel.isRendered()) return;
if (buffer == null) { //The buffer remains the same, as the canvas remains the same
Field field = canvas.getClass().getDeclaredField("buffer");
field.setAccessible(true);
buffer = (byte[]) field.get(canvas);
}
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();
}
if (t.elapsedMS() > 60)
System.out.println("Map rendering took " + t.elapsedMS() + "ms");
}
public static void update(byte[] pixels, int width, int height, int changedX, int changedY, int changedWidth, int changedHeight) {
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

@ -0,0 +1,109 @@
package sznp.virtualcomputer.renderer;
import com.aparapi.Kernel;
import com.aparapi.Range;
import lombok.Getter;
//Accessing the GPURenderer results in ArrayIndexOutOfBoundsExceptions - IT'S THE LAMBDAS
public class GPURendererInternal extends Kernel {
private int mapx;
private int mapy;
private int width;
private int height;
private byte[] pixels;
//Can't use static fields because it leads to incorrect CL code
private int[] colors;
@SuppressWarnings({"FieldCanBeLocal", "unused"})
private byte[] buffer; //References the map buffer
private Range range;
@Getter
private boolean rendered;
//public static byte[] test=new byte[1]; - LAMBDAS
public GPURendererInternal(int mapx, int mapy, int[] colors) {
this.mapx = mapx;
this.mapy = mapy;
this.colors = colors;
range = Range.create2D(128, 128);
//Do an intial draw of a black screen with Aparapi so it doesn't lag at start
pixels = new byte[1];
width = height = 0;
rendered = false;
}
@Override
public void run() {
//Single booleans not found (no such field error)
int mx = getGlobalId(0);
int my = getGlobalId(1);
int imgx = mx + mapx * 128;
int imgy = my + mapy * 128;
int imgi = (imgy * width + imgx) * 4;
if (imgx >= width || imgy >= height) { //Array length check --> Unhandled exception string
buffer[my * 128 + mx] = matchColor(0, 0, 0);
//buffer[my*128+mx]=10; - LAMBDAS
return;
}
buffer[my * 128 + mx] = matchColor(pixels[imgi] & 0xFF, pixels[imgi + 1] & 0xFF, pixels[imgi + 2] & 0xFF); //Byte.toUnsignedInt
//buffer[my*128+mx]=10; - LAMBDAS
//Unhandled exception string (used & 255, after using toUnsignedInt on the blue color) - Not that, see above
}
//Modified version of MapPalette.matchColor
private byte matchColor(int b, int g, int r) {
int index = 0;
double best = -1;
for (int i = 4; i < colors.length; i++) {
double distance = distance(b, g, r, colors[i]);
if (distance < best || best == -1) {
best = distance;
index = i;
}
}
// Minecraft has 143 colors, some of which have negative byte representations
return (byte) (index < 128 ? index : -129 + (index - 127));
}
//Can't use getXY prefix because it treats it as a getter
private double distance(int b1, int g1, int r1, int c2) {
int red2 = color(c2, RED);
double rmean = (r1 + red2) / 2.0;
double r = r1 - red2;
double g = g1 - color(c2, GREEN);
int b = b1 - color(c2, BLUE);
double weightR = 2 + rmean / 256.0;
double weightG = 4.0;
double weightB = 2 + (255 - rmean) / 256.0;
return weightR * r * r + weightG * g * g + weightB * b * b;
}
private static int color(int bgra, int oc) {
return (bgra >> (oc * 8)) & 0xFF;
}
private static final int RED = 2;
private static final int GREEN = 1;
private static final int BLUE = 0;
//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) {
if (pixels == null || rendered) return;
this.buffer = buffer;
put(buffer).put(pixels).execute(range).get(buffer);
rendered = true;
}
void ignoreChange() {
rendered = true;
}
}

View file

@ -0,0 +1,17 @@
package sznp.virtualcomputer.renderer;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.map.MapView;
public interface IRenderer {
static MapView prepare(short id, World world) {
if (world == null) return null; //Testing
@SuppressWarnings("deprecation")
MapView map = Bukkit.getMap(id);
if (map == null)
map = Bukkit.createMap(world);
map.getRenderers().clear();
return map;
}
}

View file

@ -0,0 +1,154 @@
package sznp.virtualcomputer.renderer;
import com.sun.jna.Pointer;
import org.bukkit.Bukkit;
import org.bukkit.scheduler.BukkitTask;
import org.mozilla.interfaces.IFramebuffer;
import org.mozilla.interfaces.IFramebufferOverlay;
import org.mozilla.interfaces.nsISupports;
import org.mozilla.xpcom.Mozilla;
import org.virtualbox_6_0.*;
import sznp.virtualcomputer.PluginMain;
import sznp.virtualcomputer.util.Timing;
import java.util.Arrays;
public class MCFrameBuffer implements IFramebuffer {
private IDisplay display;
private Holder<IDisplaySourceBitmap> holder = new Holder<>();
public MCFrameBuffer(IDisplay display, boolean VBoxDirect) { //TODO: Implement param
this.display = display;
}
@Override
public nsISupports queryInterface(String id) {
return Mozilla.queryInterface(this, id);
}
@Override
public long getBitsPerPixel() {
return 32;
}
@Override
public long getBytesPerLine() {
return 640L;
}
@Override
public long[] getCapabilities(long[] arg0) {
try {
System.out.println("Capabilities queried");
System.out.println("Capabilities: " + Arrays.toString(arg0));
return new long[]{FramebufferCapabilities.UpdateImage.value()};
}
catch(Exception e) {
e.printStackTrace();
return new long[]{};
}
}
@Override
public long getHeight() {
return 480;
}
@Override
public long getHeightReduction() {
return 0;
}
@Override
public IFramebufferOverlay getOverlay() {
return null;
}
@Override
public long getPixelFormat() {
return BitmapFormat.BGRA.value();
}
@Override
public long getVisibleRegion(byte arg0, long arg1) {
return 0;
}
@Override
public long getWidth() {
return 640;
}
@Override
public long getWinId() {
return 0; // Zero means no win id
}
@Override
public void notify3DEvent(long arg0, byte[] arg1) {
}
private BukkitTask tt;
private Pointer pointer;
private int width;
private int height;
@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];
holder.value.getTypedWrapped().queryBitmapInfo(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));
}
} 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");
}
@Override
public void notifyUpdateImage(long arg0, long arg1, long arg2, long arg3, byte[] arg4) {
System.out.println("Update image!");
}
@Override
public void setVisibleRegion(byte arg0, long arg1) {
}
@Override
public void processVHWACommand(byte b, int i, boolean b1) {
}
@Override
public boolean videoModeSupported(long arg0, long arg1, long arg2) {
return true;
}
}

View file

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

View file

@ -0,0 +1,30 @@
package sznp.virtualcomputer.util;
import jnr.ffi.Pointer;
@SuppressWarnings("unused")
public interface PXCLib {
/**
* Testing only
* @param px Input array
* @param out Output array
* @return 0
*/
int convert(int[] px, long[] out);
/**
* Set source bitmap
* @param address Bitmap address from VirtualBox
* @param w Width of the screen
* @param h Height of the screen
* @param mcx Width of the screen in maps
* @param mcy Height of the screen in maps
*/
void setSource(long address, int w, int h, int mcx, int mcy);
/**
* Updates map and returns it's content, where affected
* @return Partial map data [mapc][data]
*/
long updateAndGetMap(int x, int y, int width, int height, Pointer out_changed); //TODO: Only update parts that actually updated and return them per-map (flagDirty)
}

View file

@ -0,0 +1,136 @@
package sznp.virtualcomputer.util;
/*
The scancode values come from:
- http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/scancode.doc (March 16), 2000).
- http://www.computer-engineering.org/ps2keyboard/scancodes1.html
- using MapVirtualKeyEx( VK_*), MAPVK_VK_TO_VSC_EX), 0 ) with the english us keyboard layout
- reading win32 WM_INPUT keyboard messages.
*/
import java.util.HashMap;
@SuppressWarnings("unused")
public enum Scancode { // https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names
sc_escape(0x01), sc_1(0x02), sc_2(0x03), sc_3(0x04), sc_4(0x05), sc_5(0x06), sc_6(0x07), sc_7(0x08), sc_8(
0x09), sc_9(0x0A), sc_0(0x0B), sc_minus(0x0C), sc_equals(0x0D), sc_backspace(0x0E), sc_tab(0x0F), sc_q(
0x10), sc_w(0x11), sc_e(0x12), sc_r(0x13), sc_t(0x14), sc_y(0x15), sc_u(0x16), sc_i(0x17), sc_o(
0x18), sc_p(0x19), sc_bracketLeft(0x1A), sc_bracketRight(0x1B), sc_enter(
0x1C), sc_controlLeft(0x1D), sc_a(0x1E), sc_s(0x1F), sc_d(
0x20), sc_f(0x21), sc_g(0x22), sc_h(0x23), sc_j(0x24), sc_k(0x25), sc_l(
0x26), sc_semicolon(0x27), sc_apostrophe(0x28), sc_grave(
0x29), sc_shiftLeft(0x2A), sc_backslash(0x2B), sc_z(
0x2C), sc_x(0x2D), sc_c(0x2E), sc_v(0x2F), sc_b(
0x30), sc_n(0x31), sc_m(0x32), sc_comma(
0x33), sc_period(0x34), sc_slash(
0x35), sc_shiftRight(
0x36), sc_numpad_multiply(
0x37), sc_altLeft(
0x38), sc_space(
0x39), sc_capsLock(
0x3A), sc_f1(
0x3B), sc_f2(
0x3C), sc_f3(
0x3D), sc_f4(
0x3E), sc_f5(
0x3F), sc_f6(
0x40), sc_f7(
0x41), sc_f8(
0x42), sc_f9(
0x43), sc_f10(
0x44), sc_numLock(
0x45), sc_scrollLock(
0x46), sc_numpad_7(
0x47), sc_numpad_8(
0x48), sc_numpad_9(
0x49), sc_numpad_minus(
0x4A), sc_numpad_4(
0x4B), sc_numpad_5(
0x4C), sc_numpad_6(
0x4D), sc_numpad_plus(
0x4E), sc_numpad_1(
0x4F), sc_numpad_2(
0x50), sc_numpad_3(
0x51), sc_numpad_0(
0x52), sc_numpad_period(
0x53), sc_alt_printScreen(
0x54), /*
* Alt
* +
* print
* screen.
* MapVirtualKeyEx(
* VK_SNAPSHOT
* )
* ,
* MAPVK_VK_TO_VSC_EX
* )
* ,
* 0
* )
* returns
* scancode
* 0x54.
*/
sc_bracketAngle(0x56), /* Key between the left shift and Z. */
sc_f11(0x57), sc_f12(0x58), sc_oem_1(0x5a), /* VK_OEM_WSCTRL */
sc_oem_2(0x5b), /* VK_OEM_FINISH */
sc_oem_3(0x5c), /* VK_OEM_JUMP */
sc_eraseEOF(0x5d), sc_oem_4(0x5e), /* VK_OEM_BACKTAB */
sc_oem_5(0x5f), /* VK_OEM_AUTO */
sc_zoom(0x62), sc_help(0x63), sc_f13(0x64), sc_f14(0x65), sc_f15(0x66), sc_f16(0x67), sc_f17(0x68), sc_f18(
0x69), sc_f19(
0x6a), sc_f20(0x6b), sc_f21(0x6c), sc_f22(0x6d), sc_f23(0x6e), sc_oem_6(0x6f), /* VK_OEM_PA3 */
sc_katakana(0x70), sc_oem_7(0x71), /* VK_OEM_RESET */
sc_f24(0x76), sc_sbcschar(0x77), sc_convert(0x79), sc_nonconvert(0x7B), /* VK_OEM_PA1 */
sc_media_previous(0xE010), sc_media_next(0xE019), sc_numpad_enter(0xE01C), sc_controlRight(0xE01D), sc_volume_mute(
0xE020), sc_launch_app2(0xE021), sc_media_play(0xE022), sc_media_stop(
0xE024), sc_volume_down(0xE02E), sc_volume_up(
0xE030), sc_browser_home(0xE032), sc_numpad_divide(0xE035), sc_printScreen(0xE037),
/*
* sc_printScreen: - make: 0xE02A 0xE037 - break: 0xE0B7 0xE0AA - MapVirtualKeyEx( VK_SNAPSHOT), MAPVK_VK_TO_VSC_EX), 0 ) returns scancode 0x54; - There is no VK_KEYDOWN with VK_SNAPSHOT.
*/
sc_altRight(0xE038), sc_cancel(0xE046), /* CTRL + Pause */
sc_home(0xE047), sc_arrowUp(0xE048), sc_pageUp(0xE049), sc_arrowLeft(0xE04B), sc_arrowRight(0xE04D), sc_end(
0xE04F), sc_arrowDown(0xE050), sc_pageDown(0xE051), sc_insert(0xE052), sc_delete(0xE053), sc_metaLeft(
0xE05B), sc_metaRight(0xE05C), sc_application(0xE05D), sc_power(0xE05E), sc_sleep(0xE05F), sc_wake(
0xE063), sc_browser_search(0xE065), sc_browser_favorites(0xE066), sc_browser_refresh(
0xE067), sc_browser_stop(0xE068), sc_browser_forward(0xE069), sc_browser_back(
0xE06A), sc_launch_app1(
0xE06B), sc_launch_email(0xE06C), sc_launch_media(0xE06D),
sc_pause(0xE11D45);
/*
* sc_pause: - make: 0xE11D 45 0xE19D C5 - make in raw input: 0xE11D 0x45 - break: none - No repeat when you hold the key down - There are no break so I don't know how the key down/up is expected
* to work. Raw input sends "keydown" and "keyup" messages), and it appears that the keyup message is sent directly after the keydown message (you can't hold the key down) so depending on when
* GetMessage or PeekMessage will return messages), you may get both a keydown and keyup message "at the same time". If you use VK messages most of the time you only get keydown messages), but
* some times you get keyup messages too. - when pressed at the same time as one or both control keys, generates a 0xE046 (sc_cancel) and the string for that scancode is "break".
*/
private static final HashMap<String, Integer> scanCodes = new HashMap<>();
static {
for (Scancode sc : values())
scanCodes.put(sc.toString().toLowerCase(), sc.Code);
}
/**
* Gets the scancode from a lowercased string (O(1))
*
* @param keyLowerCased The key name, lowercased (sc_...)
* @return The code or -1 if not found
*/
public static int getCode(String keyLowerCased) {
Integer code = scanCodes.get(keyLowerCased);
if (code == null) return -1;
return code;
}
public int Code;
Scancode(int code) {
Code = code;
}
}

View file

@ -0,0 +1,9 @@
package sznp.virtualcomputer.util;
public class Timing {
private long start = System.nanoTime();
public long elapsedMS() {
return (System.nanoTime() - start) / 1000000L;
}
}

View file

@ -0,0 +1,61 @@
package sznp.virtualcomputer.util;
import lombok.val;
import org.mozilla.interfaces.IEventListener;
import org.virtualbox_6_0.IEvent;
import org.virtualbox_6_0.IEventSource;
import org.virtualbox_6_0.VBoxEventType;
import org.virtualbox_6_0.xpcom.IUnknown;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
public class Utils {
/**
* Adds the specified path to the java library path
*
* @param pathToAdd the path to add
* @throws Exception
*/
public static void addLibraryPath(String pathToAdd) throws Exception {
final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths");
usrPathsField.setAccessible(true);
// get array of paths
final String[] paths = (String[]) usrPathsField.get(null);
// check if the path to add is already present
for (String path : paths) {
if (path.equals(pathToAdd)) {
return;
}
}
// add the new path
final String[] newPaths = Arrays.copyOf(paths, paths.length + 1);
newPaths[newPaths.length - 1] = pathToAdd;
usrPathsField.set(null, newPaths);
}
//public static void registerListener(IEventSource source, IEventListener listener, VBoxEventType... types) {
public static org.virtualbox_6_0.IEventListener registerListener(IEventSource source, IEventListener listener, List<VBoxEventType> types) {
val ret = new org.virtualbox_6_0.IEventListener(listener);
source.registerListener(ret, types, true);
return ret;
}
@SuppressWarnings("unchecked")
public static <T extends IEvent> T getEvent(org.mozilla.interfaces.IEvent event, Class<T> cl) {
//if (event.getType() != type.value()) return null;
//return (T) T.queryInterface(new IEvent(event)); - Probably won't work
try {
val method = cl.getMethod("queryInterface", IUnknown.class);
return (T) method.invoke(null, new IEvent(event));
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return null;
}
}
}

View file

@ -0,0 +1,5 @@
package sznp.virtualcomputer.util;
public interface VBoxLib {
void RTR3InitExe(int argc, String argv, int somethingzero);
}

View file

@ -0,0 +1,10 @@
package sznp.virtualcomputer.util;
import com.sun.jna.Library;
import com.sun.jna.Native;
public interface WinLib extends Library {
WinLib INSTANCE = Native.loadLibrary("VirtualComputerWin", WinLib.class);
public void init();
}

View file

@ -0,0 +1,7 @@
name: VirtualComputer
main: sznp.virtualcomputer.PluginMain
version: 2.0
commands:
computer:
usage: Use /computer start|stop|reset|key|mouse|input|fix
aliases: c

View file

@ -1,201 +0,0 @@
package sznp.virtualcomputer;
import net.countercraft.movecraft.craft.Craft;
import net.countercraft.movecraft.craft.CraftManager;
import org.bukkit.Bukkit;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class Commands implements CommandExecutor
{
@Override
public boolean onCommand(CommandSender sender, Command cmd, String label,
String[] args)
{
switch (cmd.getName().toLowerCase())
{
case "computer":
{
if (args.length == 0)
return false;
switch (args[0].toLowerCase())
{
case "start":
PluginMain.getPlugin(PluginMain.class).Start(sender);
break;
case "stop":
PluginMain.getPlugin(PluginMain.class).Stop(sender);
break;
case "debug":
World w = Bukkit.getWorlds().get(0);
Craft[] crafts = CraftManager.getInstance().getCraftsInWorld(w);
sender.sendMessage("World: " + w);
sender.sendMessage("Crafts: " + crafts);
sender.sendMessage("Craft type: "
+ crafts[0].getType().getCraftName());
sender.sendMessage("DX: " + crafts[0].getLastDX());
sender.sendMessage("DY: " + crafts[0].getLastDY());
sender.sendMessage("DZ: " + crafts[0].getLastDZ());
sender.sendMessage("MouseSpeed: " + PluginMain.MouseSpeed);
sender.sendMessage("Block: "
+ Bukkit.getWorlds()
.get(0)
.getBlockAt(crafts[0].getMinX(),
crafts[0].getMinY() - 1,
crafts[0].getMinZ()).getType()); // Block:
// AIR
break;
case "powerbutton":
PluginMain.getPlugin(PluginMain.class).PowerButton(sender);
break;
case "reset":
PluginMain.getPlugin(PluginMain.class).Reset(sender);
break;
case "fix":
PluginMain.getPlugin(PluginMain.class).FixScreen(sender);
break;
case "key":
if (args.length < 2)
{
sender.sendMessage("§cUsage: /computer key <key> [down/up|interval]");
return true;
}
if (args.length < 3)
PluginMain.getPlugin(PluginMain.class).PressKey(sender,
args[1], "");
else
PluginMain.getPlugin(PluginMain.class).PressKey(sender,
args[1], args[2]);
break;
case "mouse":
boolean showusage = true;
if (args.length < 6)
{
// Command overloading, because I can :P
if (args.length > 4) // 4<x<6
{
PluginMain.getPlugin(PluginMain.class).UpdateMouse(
sender, Integer.parseInt(args[1]),
Integer.parseInt(args[2]),
Integer.parseInt(args[3]),
Integer.parseInt(args[4]), "", false);
showusage = false;
} else
{
if (args.length == 3)
{
PluginMain.getPlugin(PluginMain.class).UpdateMouse(
sender, 0, 0, 0, 0, args[1],
(args[2].equals("down")));
showusage = false;
} else if (args.length == 2)
{
PluginMain.getPlugin(PluginMain.class).UpdateMouse(
sender, 0, 0, 0, 0, args[1]);
showusage = false;
}
}
}
if (showusage)
{
sender.sendMessage("§cUsage: /computer mouse <relx> <rely> <relz> <relw>");
sender.sendMessage("§cOr: /computer mouse <button> [up/down]");
}
break;
case "mspeed":
if (args.length < 2)
{
sender.sendMessage("§cUsage: /computer mspeed <speed>");
return true;
}
PluginMain.MouseSpeed = Integer.parseInt(args[1]);
sender.sendMessage("Mouse speed set to " + args[1]);
break;
case "input":
{
if (!(sender instanceof Player))
{
sender.sendMessage("§cError: Only players can use this command.");
return true;
}
if (args.length < 2)
{
sender.sendMessage("§cUsage: /computer input <key|mouse>");
return true;
}
if (args[1].equalsIgnoreCase("key"))
{
Bukkit.getServer()
.dispatchCommand(
Bukkit.getConsoleSender(),
"tellraw "
+ sender.getName()
+ " [\"\",{\"text\":\" [0]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D0\"}},{\"text\":\" [1]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D1\"}},{\"text\":\" [2]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D2\"}},{\"text\":\" [3]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D3\"}},{\"text\":\" [4]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D4\"}},{\"text\":\" [5]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D5\"}},{\"text\":\" [6]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D6\"}},{\"text\":\" [7]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D7\"}},{\"text\":\" [8]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D8\"}},{\"text\":\" [9]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D9\"}}]");
Bukkit.getServer()
.dispatchCommand(
Bukkit.getConsoleSender(),
"tellraw "
+ sender.getName()
+ " [\"\",{\"text\":\" [Tab]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Tab\"}},{\"text\":\" [Q]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Q\"}},{\"text\":\" [W]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key W\"}},{\"text\":\" [E]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key E\"}},{\"text\":\" [R]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key R\"}},{\"text\":\" [T]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key T\"}},{\"text\":\" [Y]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Y\"}},{\"text\":\" [U]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key U\"}},{\"text\":\" [I]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key I\"}},{\"text\":\" [O]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key O\"}},{\"text\":\" [P]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key P\"}}]");
Bukkit.getServer()
.dispatchCommand(
Bukkit.getConsoleSender(),
"tellraw "
+ sender.getName()
+ " [\"\",{\"text\":\" [CapsLock]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key CapsLock\"}},{\"text\":\" [A]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key A\"}},{\"text\":\" [S]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key S\"}},{\"text\":\" [D]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key D\"}},{\"text\":\" [F]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key F\"}},{\"text\":\" [G]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key G\"}},{\"text\":\" [H]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key H\"}},{\"text\":\" [J]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key J\"}},{\"text\":\" [K]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key K\"}},{\"text\":\" [L]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key L\"}},{\"text\":\" [Return]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Return\"}}]");
Bukkit.getServer()
.dispatchCommand(
Bukkit.getConsoleSender(),
"tellraw "
+ sender.getName()
+ " [\"\",{\"text\":\" [Z]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key Z\"}},{\"text\":\" [X]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key X\"}},{\"text\":\" [C]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key C\"}},{\"text\":\" [V]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key V\"}},{\"text\":\" [B]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key B\"}},{\"text\":\" [N]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key N\"}},{\"text\":\" [M]\",\"color\":\"green\",\"clickEvent\":{\"action\":\"run_command\",\"value\":\"/computer key M\"}}]");
Bukkit.getServer()
.dispatchCommand(
Bukkit.getConsoleSender(),
"tellraw "
+ sender.getName()
+ " [\"\",{\"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\"}}]");
} else if (args[1].equalsIgnoreCase("mouse"))
{
if (!(sender instanceof Player))
{
sender.sendMessage("§cOnly ingame players can use this command.");
return true;
}
if (!MouseLockerPlayerListener.LockedPlayers
.contains(sender))
{
MouseLockerPlayerListener.LockedPlayers
.add((Player) sender);
sender.sendMessage("§aMouse locked.");
} else
{
MouseLockerPlayerListener.LockedPlayers.remove(sender);
sender.sendMessage("§bMouse unlocked.");
}
} else if (args[1].equalsIgnoreCase("mspeed"))
{
if (args.length < 3)
{
sender.sendMessage("§cUsage: /computer input mspeed <integer>");
return true;
}
MouseLockerPlayerListener.LockedSpeed = Float
.parseFloat(args[2]);
sender.sendMessage("§aMouse speed set to "
+ MouseLockerPlayerListener.LockedSpeed);
}
break;
}
}
return true;
}
}
return false;
}
}

View file

@ -1,90 +0,0 @@
package sznp.virtualcomputer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class JarUtils {
public static boolean extractFromJar(final String fileName,
final String dest) throws IOException {
if (getRunningJar() == null) {
return false;
}
final File file = new File(dest);
if (file.isDirectory()) {
file.mkdir();
return false;
}
if (!file.exists()) {
file.getParentFile().mkdirs();
}
final JarFile jar = getRunningJar();
final Enumeration<JarEntry> e = jar.entries();
while (e.hasMoreElements()) {
final JarEntry je = e.nextElement();
if (!je.getName().contains(fileName)) {
continue;
}
final InputStream in = new BufferedInputStream(
jar.getInputStream(je));
final OutputStream out = new BufferedOutputStream(
new FileOutputStream(file));
copyInputStream(in, out);
jar.close();
return true;
}
jar.close();
return false;
}
private final static void copyInputStream(final InputStream in,
final OutputStream out) throws IOException {
try {
final byte[] buff = new byte[4096];
int n;
while ((n = in.read(buff)) > 0) {
out.write(buff, 0, n);
}
} finally {
out.flush();
out.close();
in.close();
}
}
public static URL getJarUrl(final File file) throws IOException {
return new URL("jar:" + file.toURI().toURL().toExternalForm() + "!/");
}
public static JarFile getRunningJar() throws IOException {
if (!RUNNING_FROM_JAR) {
return null; // null if not running from jar
}
String path = new File(JarUtils.class.getProtectionDomain()
.getCodeSource().getLocation().getPath()).getAbsolutePath();
path = URLDecoder.decode(path, "UTF-8");
return new JarFile(path);
}
private static boolean RUNNING_FROM_JAR = false;
static {
final URL resource = JarUtils.class.getClassLoader().getResource(
"plugin.yml");
if (resource != null) {
RUNNING_FROM_JAR = true;
}
}
}

View file

@ -1,34 +0,0 @@
package sznp.virtualcomputer;
import java.util.ArrayList;
import java.util.List;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerMoveEvent;
public class MouseLockerPlayerListener implements Listener
{
public static List<Player> LockedPlayers = new ArrayList<Player>();
public static float LockedSpeed = 1;
@EventHandler
public void onPlayerMoveMouse(PlayerMoveEvent e)
{
if (!LockedPlayers.contains(e.getPlayer()))
return;
float yaw1 = e.getFrom().getYaw();
float pitch1 = e.getFrom().getPitch();
float yaw2 = e.getTo().getYaw();
float pitch2 = e.getTo().getPitch();
if (yaw2 - yaw1 == 0 || pitch2 - pitch1 == 0)
return;
PluginMain.Instance.UpdateMouse(null,
(int) ((yaw2 - yaw1) * LockedSpeed),
(int) ((pitch2 - pitch1) * LockedSpeed), 0, 0, "");
e.setTo(e.getFrom());
}
}

View file

@ -1,179 +0,0 @@
package sznp.virtualcomputer;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.util.HashMap;
import net.countercraft.movecraft.craft.Craft;
import net.countercraft.movecraft.craft.CraftManager;
import net.sf.jni4net.Bridge;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import virtualcomputersender.Computer;
import com.mcplugindev.slipswhitley.sketchmap.map.RelativeLocation;
import com.mcplugindev.slipswhitley.sketchmap.map.SketchMap;
public class PluginMain extends JavaPlugin {
private Computer computer;
private SketchMap smap;
public static PluginMain Instance;
// Fired when plugin is first enabled
@Override
public void onEnable() {
Instance = this;
try {
ConsoleCommandSender ccs = getServer().getConsoleSender();
this.getCommand("computer").setExecutor(new Commands());
ccs.sendMessage("§bExtracting necessary libraries...");
final File[] libs = new File[] {
// new File(getDataFolder(), "jni4net.j-0.8.8.0.jar"),
new File(getDataFolder(), "jni4net.n-0.8.8.0.dll"),
new File(getDataFolder(), "jni4net.n.w64.v40-0.8.8.0.dll"),
// new File(getDataFolder(), "VirtualComputerSender.j4n.jar"),
new File(getDataFolder(), "VirtualComputerSender.j4n.dll"),
new File(getDataFolder(), "VirtualComputerSender.dll"),
new File(getDataFolder(), "Interop.VirtualBox.dll") };
for (final File lib : libs) {
if (!lib.exists()) {
JarUtils.extractFromJar(lib.getName(), lib.getAbsolutePath());
}
}
ccs.sendMessage("§bInitializing bridge...");
Bridge.init(new File(getDataFolder(), "jni4net.n.w64.v40-0.8.8.0.dll").getAbsoluteFile());
Bridge.LoadAndRegisterAssemblyFrom(new File(getDataFolder(), "VirtualComputerSender.j4n.dll"));
ccs.sendMessage("§bInititalizing VirtualBox interface...");
computer = new Computer();
ccs.sendMessage("§bLoading SketchMap...");
img = new BufferedImage(640, 480, BufferedImage.TYPE_INT_ARGB);
HashMap<Short, RelativeLocation> map = new HashMap<>();
for (int i = 0; i < 5; i++)
for (int j = 0; j < 4; j++)
map.put((short) (i * 4 + j), new RelativeLocation(i, j));
smap = new SketchMap(img, "Screen", 5, 4, false, map);
ccs.sendMessage("§bLoaded!");
getServer().getPluginManager().registerEvents(new MouseLockerPlayerListener(), this);
DoStart();
} catch (final Exception e) {
e.printStackTrace();
}
}
// Fired when plugin is disabled
@Override
public void onDisable() {
ConsoleCommandSender ccs = getServer().getConsoleSender();
ccs.sendMessage("§aHuh.");
saveConfig();
}
private volatile BufferedImage img;
private volatile BukkitTask task = null;
public void Start(CommandSender sender) {
sender.sendMessage("§eStarting computer...");
computer.Start();
sender.sendMessage("§eComputer started.");
DoStart();
}
public static int MouseSpeed = 1;
private void DoStart() {
if (task == null)
task = this.getServer().getScheduler().runTaskTimerAsynchronously(this, new Runnable() {
public void run() {
final int[] a = ((DataBufferInt) smap.image.getRaster().getDataBuffer()).getData();
final int[] data = computer.GetScreenPixelColors();
System.arraycopy(data, 0, a, 0, data.length);
}
}, 1, 10);
if (getServer().getPluginManager().isPluginEnabled("Movecraft")) {
this.getServer().getScheduler().scheduleSyncRepeatingTask(this, new Runnable() {
public void run() {
Craft[] crafts = CraftManager.getInstance().getCraftsInWorld(Bukkit.getWorlds().get(0));
if (crafts == null)
return;
for (Craft c : crafts) {
if (c.getType().getCraftName().equalsIgnoreCase("mouse")) {
int dx = c.getLastDX();
// int dy = c.getLastDY();
int dz = c.getLastDZ();
if (Bukkit.getWorlds().get(0).getBlockAt(c.getMinX(), c.getMinY() - 1, c.getMinZ())
.getType() != Material.AIR && (dx != 0 || dz != 0))
UpdateMouse(null, dx * MouseSpeed, dz * MouseSpeed, 0, 0, "");
c.setLastDX(0);
c.setLastDZ(0);
}
}
}
}, 1, 1);
}
}
public void Stop(CommandSender sender) {
sender.sendMessage("§eStopping computer...");
computer.PowerOff();
sender.sendMessage("§eComputer stopped.");
}
public void PowerButton(CommandSender sender) {
sender.sendMessage("§eStarting/stoppping computer...");
final CommandSender s = sender;
getServer().getScheduler().runTaskAsynchronously(this, new Runnable() {
@Override
public void run() {
if (computer.PowerButton()) {
DoStart();
s.sendMessage("§eComputer started.");
} else
s.sendMessage("§ePowerbutton pressed.");
}
});
}
public void Reset(CommandSender sender) {
sender.sendMessage("§eResetting computer...");
computer.Reset();
sender.sendMessage("§eComputer reset.");
}
public void FixScreen(CommandSender sender) {
sender.sendMessage("§eFixing screen...");
computer.FixScreen();
sender.sendMessage("§eScreen fixed.");
}
public void PressKey(CommandSender sender, String key, String stateorduration) {
if (stateorduration.length() == 0)
computer.PressKey(key, (short) 0);
else if (stateorduration.equalsIgnoreCase("down"))
computer.PressKey(key, (short) -1);
else if (stateorduration.equalsIgnoreCase("up"))
computer.PressKey(key, (short) -2);
else
computer.PressKey(key, Short.parseShort(stateorduration));
}
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs, boolean down) {
if (down)
computer.UpdateMouse(x, y, z, w, mbs);
else
computer.UpdateMouse(x, y, z, w, "");
}
public void UpdateMouse(CommandSender sender, int x, int y, int z, int w, String mbs) {
UpdateMouse(sender, x, y, z, w, mbs, true);
UpdateMouse(sender, x, y, z, w, mbs, false);
}
}

View file

@ -1,28 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualComputerSender", "VirtualComputerSender\VirtualComputerSender.csproj", "{5EF12535-ACDF-4D60-8E32-087F5A277946}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Debug|x64.ActiveCfg = Debug|x64
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Debug|x64.Build.0 = Debug|x64
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Release|Any CPU.Build.0 = Release|Any CPU
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Release|x64.ActiveCfg = Release|x64
{5EF12535-ACDF-4D60-8E32-087F5A277946}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
</configuration>

View file

@ -1,145 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VirtualBox;
namespace VirtualComputerSender //Copyright © NorbiPeti 2015-2016
{
public class Computer
{ //Self-note: Don't add/edit public members
private VirtualBoxClass vbox;
private Session session;
public Computer()
{
vbox = new VirtualBoxClass();
session = new Session();
}
public void Start()
{
var machine = (IMachine)vbox.Machines.GetValue(0);
var progress = machine.LaunchVMProcess(session, "headless", "");
progress.WaitForCompletion(100000);
var fb = new MCFrameBuffer(session.Console.Display);
Screen = fb.Screen; //fb.Screen is assigned on object creation
session.Console.Display.AttachFramebuffer(0, fb);
session.Console.Display.SetSeamlessMode(0);
}
public bool PowerButton()
{
if (session.State != SessionState.SessionState_Locked || session.Machine == null)
{
Start();
return true;
}
else
{
session.Console.PowerButton();
if (session.State != SessionState.SessionState_Locked)
Screen = null;
return false;
}
}
public void PowerOff()
{
if (session.State == SessionState.SessionState_Locked)
{
session.Console.PowerDown().WaitForCompletion(10000);
Screen = null;
}
}
public void Reset()
{
if (session.State == SessionState.SessionState_Locked)
session.Console.Reset();
}
private volatile int[] Screen;
public int[] GetScreenPixelColors()
{
if (Screen == null)
{
Screen = new int[640 * 480];
for (int i = 0; i < Screen.Length; i++)
Screen[i] = Color.Black.ToArgb();
}
return Screen;
}
[DllImport("user32.dll")]
static extern uint MapVirtualKey(uint uCode, uint uMapType);
const uint MAPVK_VK_TO_VSC = 0x00;
const uint MAPVK_VSC_TO_VK = 0x01;
const uint MAPVK_VK_TO_CHAR = 0x02;
const uint MAPVK_VSC_TO_VK_EX = 0x03;
const uint MAPVK_VK_TO_VSC_EX = 0x04;
public void PressKey(string key, short durationorstate)
{
if (session.State == SessionState.SessionState_Locked)
{
int code = 0;
if (key == "testall")
{
int x = 0;
session.Console.Keyboard.PutScancodes(new int[128].Select(i => x++).ToArray());
return;
}
//Virtual key code taken from Kennedy.ManagedHooks project
//Release key scan code concept taken from VirtualBox source code (KeyboardImpl.cpp:putCAD())
//+128
code = (int)MapVirtualKey((uint)(VirtualKeys)Enum.Parse(typeof(VirtualKeys), key, true), MAPVK_VK_TO_VSC);
int codeShift = (int)MapVirtualKey((uint)VirtualKeys.ShiftLeft, MAPVK_VK_TO_VSC);
int codeCtrl = (int)MapVirtualKey((uint)VirtualKeys.ControlLeft, MAPVK_VK_TO_VSC);
int codeAlt = (int)MapVirtualKey((uint)VirtualKeys.AltLeft, MAPVK_VK_TO_VSC);
if (durationorstate != -2) //<-- 2016.02.22.
session.Console.Keyboard.PutScancode(code);
if (durationorstate == 0 || durationorstate == -2)
session.Console.Keyboard.PutScancodes(new int[] { code + 128, codeCtrl + 128, codeShift + 128, codeAlt + 128 });
if (durationorstate > 0)
{
Timer t = new Timer();
t.Tick += delegate
{
session.Console.Keyboard.PutScancode(code + 128);
t.Stop();
};
t.Interval = durationorstate;
t.Start();
}
}
}
public void UpdateMouse(int x, int y, int z, int w, string mbs)
{
if (session.State != SessionState.SessionState_Locked)
return;
int state = 0;
if (mbs.Length > 0)
state = (int)(MouseBS)Enum.Parse(typeof(MouseBS), mbs, true);
session.Console.Mouse.PutMouseEvent(x, y, z, w, state);
}
public void FixScreen()
{
session.Console.Display.SetSeamlessMode(0);
session.Console.Display.SetVideoModeHint(0, 1, 0, 0, 0, 640, 480, 32);
}
~Computer()
{
if (session.State == SessionState.SessionState_Locked)
session.Machine.SaveState();
}
}
}

View file

@ -1,59 +0,0 @@
namespace VirtualComputerSender
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.panel1 = new System.Windows.Forms.Panel();
this.SuspendLayout();
//
// panel1
//
this.panel1.BackColor = System.Drawing.Color.Black;
this.panel1.Location = new System.Drawing.Point(12, 12);
this.panel1.Name = "panel1";
this.panel1.Size = new System.Drawing.Size(800, 600);
this.panel1.TabIndex = 0;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(861, 662);
this.Controls.Add(this.panel1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Panel panel1;
}
}

View file

@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using VirtualBox;
namespace VirtualComputerSender //Copyright © NorbiPeti 2015-2016
{
public partial class Form1: Form
{
private static Form1 Instance;
public Form1()
{
Instance = this;
InitializeComponent();
Screen = panel1.CreateGraphics();
var vbox = new VirtualBoxClass();
var session = new Session();
var machine = (IMachine)vbox.Machines.GetValue(0);
var progress = machine.LaunchVMProcess(session, "headless", "");
progress.WaitForCompletion(100000);
session.Console.Display.AttachFramebuffer(0, new NetFrameBuffer(session.Console.Display));
}
public static Graphics Screen;
}
}

View file

@ -1,120 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,179 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using VirtualBox;
namespace VirtualComputerSender //Copyright © NorbiPeti 2015-2016
{
public class MCFrameBuffer : IFramebuffer
{
private IDisplay Display;
private Timer LastFullUpdateTimer;
private UdpClient Client;
public MCFrameBuffer(IDisplay display)
{
Display = display;
LastFullUpdateTimer = new Timer();
LastFullUpdateTimer.Interval = 5000;
LastFullUpdateTimer.Elapsed += UpdateScreen;
Client = new UdpClient();
Client.Connect(new IPEndPoint(IPAddress.Loopback, 5896));
LastFullUpdateTimer.Start();
}
private void UpdateScreen(object sender, EventArgs args)
{
Display.InvalidateAndUpdateScreen(0);
}
public IntPtr Address
{
get
{
return IntPtr.Zero;
}
}
public const uint CBitsPerPixel = 32;
public uint BitsPerPixel
{
get
{
return CBitsPerPixel;
}
}
public uint BytesPerLine
{
get
{
return ScreenWidth;
}
}
public uint Height
{
get
{
Console.WriteLine("Screen height queried.");
return ScreenHeight;
}
}
public uint HeightReduction
{
get
{
return 2;
}
}
public IFramebufferOverlay Overlay
{
get
{
return null;
}
}
public BitmapFormat PixelFormat
{
get
{
return BitmapFormat.BitmapFormat_RGBA;
}
}
public uint Width
{
get
{
Console.WriteLine("Screen width queried.");
return ScreenWidth;
}
}
public long WinId
{
get
{
return 0;
}
}
public Array Capabilities
{
get
{
return new FramebufferCapabilities[] { FramebufferCapabilities.FramebufferCapabilities_UpdateImage };
}
}
public uint GetVisibleRegion(ref byte aRectangles, uint aCount)
{
throw new InvalidOperationException("This should not be used.");
}
public void NotifyUpdate(uint aX, uint aY, uint aWidth, uint aHeight)
{
}
public void ProcessVHWACommand(ref byte aCommand)
{
}
public void SetVisibleRegion(ref byte aRectangles, uint aCount)
{
}
public int VideoModeSupported(uint aWidth, uint aHeight, uint aBpp)
{
return 1;
}
public const int ScreenWidth = 640;
public const int ScreenHeight = 480;
public volatile int[] Screen = new int[640 * 480];
public void NotifyUpdateImage(uint aX, uint aY, uint aWidth, uint aHeight, Array aImage)
{
Task.Run(() =>
{
var img = (byte[])aImage;
int x = 0;
for (int j = (int)aY; j < aHeight && j < ScreenHeight; j++)
{
for (int i = (int)aX; i < aWidth && i < ScreenWidth; i++)
{
if (x + 4 > aImage.Length)
return;
Screen[640 * j + i] = Color.FromArgb(img[x + 2], img[x + 1], img[x]).ToArgb(); //TODO: Touchscreen and/or left click right click forwarding
x += 4;
}
x += (int)aX * 4;
int add = ((int)(aX + aWidth) - ScreenWidth);
if (add > 0)
x += add * 4;
}
});
}
public void NotifyChange(uint aScreenId, uint aXOrigin, uint aYOrigin, uint aWidth, uint aHeight)
{
}
public void Notify3DEvent(uint aType, Array aData)
{
}
}
}

View file

@ -1,19 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VirtualComputerSender
{
public enum MouseBS
{
LeftButton = 1,
MiddleButton = 4,
RightButton = 2,
WheelDown = 16,
WheelUp = 8,
XButton1 = 32,
XButton2 = 64
}
}

View file

@ -1,178 +0,0 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using VirtualBox;
namespace VirtualComputerSender //Copyright © NorbiPeti 2015-2016
{
public class NetFrameBuffer : IFramebuffer
{
private IDisplay Display;
private Timer LastFullUpdateTimer;
private UdpClient Client;
public NetFrameBuffer(IDisplay display)
{
//address = Marshal.AllocHGlobal(1440 * 900 * 4);
Display = display;
LastFullUpdateTimer = new Timer();
LastFullUpdateTimer.Interval = 60000;
LastFullUpdateTimer.Elapsed += UpdateScreen;
Client = new UdpClient();
Client.Connect(new IPEndPoint(IPAddress.Loopback, 5896));
LastFullUpdateTimer.Start();
}
private void UpdateScreen(object sender, EventArgs args)
{
Display.InvalidateAndUpdateScreen(0);
}
public IntPtr Address
{
get
{
return IntPtr.Zero;
}
}
public const uint CBitsPerPixel = 32;
public uint BitsPerPixel
{
get
{
return CBitsPerPixel;
}
}
public uint BytesPerLine
{
get
{
return ScreenWidth;
}
}
public uint Height
{
get
{
return ScreenHeight;
}
}
public uint HeightReduction
{
get
{
return 2;
}
}
public IFramebufferOverlay Overlay
{
get
{
return null;
}
}
public BitmapFormat PixelFormat
{
get
{
return BitmapFormat.BitmapFormat_RGBA;
}
}
public uint Width
{
get
{
return ScreenWidth;
}
}
public long WinId
{
get
{
return 0;
}
}
public Array Capabilities
{
get
{
return new FramebufferCapabilities[] { FramebufferCapabilities.FramebufferCapabilities_UpdateImage };
}
}
public uint GetVisibleRegion(ref byte aRectangles, uint aCount)
{
throw new InvalidOperationException("This should not be used.");
}
public void NotifyUpdate(uint aX, uint aY, uint aWidth, uint aHeight)
{
//throw new InvalidOperationException("This should not be used. (Only UpdateImage.)");
}
public void ProcessVHWACommand(ref byte aCommand)
{
}
public void SetVisibleRegion(ref byte aRectangles, uint aCount)
{
}
public int VideoModeSupported(uint aWidth, uint aHeight, uint aBpp)
{
return 1;
}
public const int ScreenWidth = 640;
public const int ScreenHeight = 480;
private Color[,] Screen = new Color[640, 480];
public void NotifyUpdateImage(uint aX, uint aY, uint aWidth, uint aHeight, Array aImage)
{
var img = aImage.Cast<byte>().ToArray();
int x = 0;
for (int j = (int)aY; j < aHeight && j < ScreenHeight; j++)
{
//for (int i = (int)aX; (j % 20 == 0 ? (i < aWidth - 1 && i < ScreenWidth - 1) : (i < aWidth && i < ScreenWidth)); i++)
for (int i = (int)aX; i < aWidth && i < ScreenWidth; i++)
{
if (x + 4 > aImage.Length)
return;
//Form1.Screen.FillRectangle(new SolidBrush(Color.FromArgb(255, img[x + 2], img[x + 1], img[x])), i, j, 1, 1);
Screen[i, j] = Color.FromArgb(img[x + 2], img[x + 1], img[x]);
//Form1.Screen.FillRectangle(new SolidBrush(Color.FromArgb(255, img[x], img[x + 1], img[x + 2])), i, j, 1, 1);
x += 4;
}
x += (int)aX * 4;
int add = ((int)(aX + aWidth) - ScreenWidth);
if (add > 0)
x += add * 4;
}
}
public void NotifyChange(uint aScreenId, uint aXOrigin, uint aYOrigin, uint aWidth, uint aHeight)
{
}
public void Notify3DEvent(uint aType, Array aData)
{
}
}
}

View file

@ -1,22 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace VirtualComputerSender
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}

View file

@ -1,63 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace VirtualComputerSender.Properties {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VirtualComputerSender.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}

View file

@ -1,117 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View file

@ -1,26 +0,0 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace VirtualComputerSender.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}

View file

@ -1,7 +0,0 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View file

@ -1,159 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5EF12535-ACDF-4D60-8E32-087F5A277946}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VirtualComputerSender</RootNamespace>
<AssemblyName>VirtualComputerSender</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<TargetFrameworkProfile />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>..\..\TheButtonMCAutoFlairProto\Spigot server\plugins\VirtualComputer\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Computer.cs" />
<Compile Include="Form1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Form1.Designer.cs">
<DependentUpon>Form1.cs</DependentUpon>
</Compile>
<Compile Include="MCFrameBuffer.cs" />
<Compile Include="MouseBS.cs" />
<Compile Include="NetFrameBuffer.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VirtualKeys.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<COMReference Include="VirtualBox">
<Guid>{D7569351-1750-46F0-936E-BD127D5BC264}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>3</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

View file

@ -1,129 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VirtualComputerSender
{
internal enum VirtualKeys
{
Back = 0x08,
Tab = 0x09,
Clear = 0x0C,
Return = 0x0D,
ShiftLeft = 0xA0,
ControlLeft = 0xA2,
ShiftRight = 0xA1,
ControlRight = 0xA3,
AltLeft = 0xA4,
AltRight = 0xA5,
Menu = 0x12,
Pause = 0x13,
Capital = 0x14,
Escape = 0x1B,
Space = 0x20,
Prior = 0x21,
Next = 0x22,
End = 0x23,
Home = 0x24,
Left = 0x25,
Up = 0x26,
Right = 0x27,
Down = 0x28,
Select = 0x29,
Print = 0x2A,
Execute = 0x2B,
Snapshot = 0x2C,
Insert = 0x2D,
Delete = 0x2E,
Help = 0x2F,
D0 = 0x30,
D1 = 0x31,
D2 = 0x32,
D3 = 0x33,
D4 = 0x34,
D5 = 0x35,
D6 = 0x36,
D7 = 0x37,
D8 = 0x38,
D9 = 0x39,
A = 0x41,
B = 0x42,
C = 0x43,
D = 0x44,
E = 0x45,
F = 0x46,
G = 0x47,
H = 0x48,
I = 0x49,
J = 0x4A,
K = 0x4B,
L = 0x4C,
M = 0x4D,
N = 0x4E,
O = 0x4F,
P = 0x50,
Q = 0x51,
R = 0x52,
S = 0x53,
T = 0x54,
U = 0x55,
V = 0x56,
W = 0x57,
X = 0x58,
Y = 0x59,
Z = 0x5A,
LWindows = 0x5B,
RWindows = 0x5C,
Apps = 0x5D,
NumPad0 = 0x60,
NumPad1 = 0x61,
NumPad2 = 0x62,
NumPad3 = 0x63,
NumPad4 = 0x64,
NumPad5 = 0x65,
NumPad6 = 0x66,
NumPad7 = 0x67,
NumPad8 = 0x68,
NumPad9 = 0x69,
Multiply = 0x6A,
Add = 0x6B,
Separator = 0x6C,
Subtract = 0x6D,
Decimal = 0x6E,
Divide = 0x6F,
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
F4 = 0x73,
F5 = 0x74,
F6 = 0x75,
F7 = 0x76,
F8 = 0x77,
F9 = 0x78,
F10 = 0x79,
F11 = 0x7A,
F12 = 0x7B,
F13 = 0x7C,
F14 = 0x7D,
F15 = 0x7E,
F16 = 0x7F,
F17 = 0x80,
F18 = 0x81,
F19 = 0x82,
F20 = 0x83,
F21 = 0x84,
F22 = 0x85,
F23 = 0x86,
F24 = 0x87,
NumLock = 0x90,
Scroll = 0x91,
}
}

View file

@ -0,0 +1,34 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.7
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualComputerWindows", "VirtualComputerWindows\VirtualComputerWindows.csproj", "{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|x64.ActiveCfg = Debug|x64
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|x64.Build.0 = Debug|x64
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|x86.ActiveCfg = Debug|x86
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Debug|x86.Build.0 = Debug|x86
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|Any CPU.Build.0 = Release|Any CPU
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|x64.ActiveCfg = Release|x64
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|x64.Build.0 = Release|x64
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|x86.ActiveCfg = Release|x86
{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using VirtualBox;
namespace VirtualComputerWindows
{
public static class Exports
{
[DllImport(@"C:\Program Files\Oracle\VirtualBox\VBoxRT.dll", CallingConvention = CallingConvention.StdCall)]
private static extern void RTR3InitExe(int argc, string argv, int zeroflags);
/*[DllImport(@"C:\Program Files\Oracle\VirtualBox\VBoxVMM.dll", CallingConvention = CallingConvention.StdCall)]
private static extern int VMMDoHmTest(IntPtr vmstruct);*/
private static VirtualBoxClient vbc;
public static async Task<IVirtualBox> Init() => await Task.Run(() =>
{
try
{
//Environment.SetEnvironmentVariable("VBOX_HOME", @"C:\Program Files\Oracle\VirtualBox\");
//TODO: Only finds the VBoxVMM.dll when placed in the VirtualBox dir (regardless of working dir)
//Even then there are hardening issues: VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1
//https://www.virtualbox.org/svn/vbox/trunk/src/VBox/HostDrivers/Support/win/SUPDrv-win.cpp
vbc = new VirtualBoxClientClass();
var vbox = vbc.VirtualBox;
RTR3InitExe(0, "", 0);
var ses = vbc.Session;
var machine = vbox.Machines.GetValue(0) as IMachine;
ses.Name = "minecraft";
machine.LockMachine(ses, LockType.LockType_VM);
Console.WriteLine("Locking...");
while (ses.State != SessionState.SessionState_Locked) ;
Console.WriteLine("Locked");
machine = ses.Machine;
Console.WriteLine("Powering up...");
ses.Console.PowerUp().WaitForCompletion(10000);
Console.WriteLine("Framebuffer attach");
ses.Console.Display.AttachFramebuffer(0, new VBFB(ses.Console.Display));
return vbox;
}
catch(Exception e)
{
Console.WriteLine(e);
Console.ReadLine();
return null;
}
});
public static void Main()
{
Init();
Console.ReadLine();
}
}
}

View file

@ -5,12 +5,12 @@ using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("VirtualComputerSender")]
[assembly: AssemblyTitle("VirtualComputerWindows")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("VirtualComputerSender")]
[assembly: AssemblyCopyright("Copyright © NorbiPeti 2015-2016")]
[assembly: AssemblyProduct("VirtualComputerWindows")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("5ef12535-acdf-4d60-8e32-087f5a277946")]
[assembly: Guid("5e734f17-ff74-4187-a6e4-b7e1dab272f8")]
// Version information for an assembly consists of the following four values:
//

View file

@ -0,0 +1,75 @@
using System;
using VirtualBox;
namespace VirtualComputerWindows
{
internal class VBFB : IFramebuffer
{
private IDisplay display;
public VBFB(IDisplay display)
{
this.display = display;
}
public void NotifyUpdate(uint aX, uint aY, uint aWidth, uint aHeight)
{
Console.WriteLine("Update: " + aX + " " + aY + " " + aWidth + " " + aHeight);
}
public void NotifyUpdateImage(uint aX, uint aY, uint aWidth, uint aHeight, Array aImage)
{
Console.WriteLine("UpdateImage: " + aX + " " + aY + " " + aWidth + " " + aHeight);
}
public void NotifyChange(uint aScreenId, uint aXOrigin, uint aYOrigin, uint aWidth, uint aHeight)
{
Console.WriteLine("Change: " + aXOrigin + " " + aYOrigin + " " + aWidth + " " + aHeight);
display.QuerySourceBitmap(0, out var isd);
var addr = new IntPtr();
isd.QueryBitmapInfo(addr, out var w, out var h, out var bpp, out var bpl, out var bf);
Console.WriteLine("Bitmap info: " + addr + " " + w + " " + h + " " + bpp + " " + bpl + " " + bf);
}
public int VideoModeSupported(uint aWidth, uint aHeight, uint aBpp)
{
return 1;
}
public uint GetVisibleRegion(ref byte aRectangles, uint aCount)
{
return aCount;
}
public void SetVisibleRegion(ref byte aRectangles, uint aCount)
{
}
public void ProcessVHWACommand(ref byte aCommand, int aEnmCmd, int aFromGuest)
{
}
public void Notify3DEvent(uint aType, Array aData)
{
}
public uint Width => 640;
public uint Height => 480;
public uint BitsPerPixel => 32;
public uint BytesPerLine => 640 * 4;
public BitmapFormat PixelFormat => BitmapFormat.BitmapFormat_BGRA;
public uint HeightReduction => 0;
public IFramebufferOverlay Overlay => null;
public long WinId => 0;
//public Array Capabilities => new[] { FramebufferCapabilities.FramebufferCapabilities_UpdateImage };
public Array Capabilities => new FramebufferCapabilities[] { };
}
}

View file

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5E734F17-FF74-4187-A6E4-B7E1DAB272F8}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VirtualComputerWindows</RootNamespace>
<AssemblyName>VirtualComputerWindows</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<DllExportNamespace>VirtualComputerWindows</DllExportNamespace>
<DllExportDDNSCecil>true</DllExportDDNSCecil>
<DllExportSkipOnAnyCpu>false</DllExportSkipOnAnyCpu>
<DllExportOrdinalsBase>1</DllExportOrdinalsBase>
<DllExportGenExpLib>false</DllExportGenExpLib>
<DllExportOurILAsm>false</DllExportOurILAsm>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>AnyCPU</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Runtime.InteropServices.RuntimeInformation, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Exports.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="VBFB.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<COMReference Include="VirtualBox">
<Guid>{D7569351-1750-46F0-936E-BD127D5BC264}</Guid>
<VersionMajor>1</VersionMajor>
<VersionMinor>3</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>tlbimp</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="../packages/DllExport.1.5.2/tools/net.r_eg.DllExport.targets" Condition="Exists('../packages/DllExport.1.5.2/tools/net.r_eg.DllExport.targets')" />
</Project>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.InteropServices" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net462" />
</packages>

3
libpxc/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
obj/
out/

11
libpxc/makefile Normal file
View file

@ -0,0 +1,11 @@
CC=gcc
# CFLAGS=-I.
pxct: pxct.c pxc
$(CC) -Wall pxct.c -Lout -lpxc -Wl,-rpath=out -o out/pxct
pxc: pxc.c
$(CC) -Wall -O4 -c -fpic pxc.c -o obj/pxc.o
$(CC) -Wall -shared obj/pxc.o -o out/libpxc.so
cp out/libpxc.so ../

183
libpxc/pxc.c Normal file
View file

@ -0,0 +1,183 @@
#include <stdio.h>
#include <stdlib.h>
#define MAPSIZE 128
#if MAPSIZE>255
#error MAPSIZE must be a short value
#endif
//---------------------------------------------------------------------
// http://www.pixelbeat.org/programming/gcc/static_assert.html
#define ct_assert(e) {enum { ct_assert_value = 1/(!!(e)) };}
//---------------------------------------------------------------------
typedef long long int addr;
typedef struct { //RGB
unsigned int red : 8;
unsigned int green : 8;
unsigned int blue : 8;
} Color; //Used for Bukkit's initializers (for simplicity)
typedef struct { //BGRA
unsigned int blue : 8;
unsigned int green : 8;
unsigned int red : 8;
unsigned int alpha : 8;
} NativeColor; //Used for the screen data
char matchColor(NativeColor nc);
void* image=NULL;
void* maps=NULL; //Per map data (1st map, second map etc.)
short width, height, mapcx, mapcy;
void setSource(addr address, short w, short h, short mcx, short mcy) {
ct_assert(sizeof(char)==1); //Compile-time assert
ct_assert(sizeof(Color)==4); //Compile-time assert
image=(void*)address;
maps=malloc(MAPSIZE*MAPSIZE*mcx*mcy); //1 byte per pixel
width=w, height=h, mapcx=mcx, mapcy=mcy;
printf("PXC: w=%d h=%d mcx=%d mcy=%d\n", w, h, mcx, mcy);
}
NativeColor* getNativeColor(int x, int y) {
if(x<0||x>width||y<0||y>height) return NULL;
return ((NativeColor*)image)+x+y*width;
}
char* getMapColor(int x, int y) {
if(x<0||x>width||y<0||y>height) return NULL;
int mc=x/MAPSIZE+y/MAPSIZE*mapcx;
return maps+mc*MAPSIZE*MAPSIZE; //TODO: Use
}
//May return 0
void* updateAndGetMap(int x, int y, int w, int h, int** out_changed) { //TODO: Support the parameters
if(image==NULL || maps==NULL) return 0;
for(int l=y; l<y+h; l++) {
//printf("PXC: l=%d\n", l);
for(int k=x; k<x+w; k++) {
//printf("PXC: k=%d\n", k);
char *mapp=getMapColor(k, l);
char color=matchColor(*getNativeColor(k, l));
//NativeColor x={.red=0, .green=0, .blue=255, .alpha=255};
//*mapp=matchColor(x);
*mapp=color;
//printf("PXC: mapp: %d %d - %x\n", k, l, *mapp); //TODO: The bottom of the image
//printf("PXC: mapcx: %d mapcy: %d\n", k, l); //TODO: Has nothing
}
}
printf("PXC: ret maps=%p\n", maps);
return maps; //TODO: Return changed only
}
const Color colors[] = {
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
{89, 125, 39}, {109, 153, 48}, {127, 178, 56}, {67, 94, 29},
{174, 164, 115}, {213, 201, 140}, {247, 233, 163}, {130, 123, 86},
{140, 140, 140}, {171, 171, 171}, {199, 199, 199}, {105, 105, 105},
{180, 0, 0}, {220, 0, 0}, {255, 0, 0}, {135, 0, 0},
{112, 112, 180}, {138, 138, 220}, {160, 160, 255}, {84, 84, 135},
{117, 117, 117}, {144, 144, 144}, {167, 167, 167}, {88, 88, 88},
{0, 87, 0}, {0, 106, 0}, {0, 124, 0}, {0, 65, 0},
{180, 180, 180}, {220, 220, 220}, {255, 255, 255}, {135, 135, 135},
{115, 118, 129}, {141, 144, 158}, {164, 168, 184}, {86, 88, 97},
{106, 76, 54}, {130, 94, 66}, {151, 109, 77}, {79, 57, 40},
{79, 79, 79}, {96, 96, 96}, {112, 112, 112}, {59, 59, 59},
{45, 45, 180}, {55, 55, 220}, {64, 64, 255}, {33, 33, 135},
{100, 84, 50}, {123, 102, 62}, {143, 119, 72}, {75, 63, 38},
{180, 177, 172}, {220, 217, 211}, {255, 252, 245}, {135, 133, 129},
{152, 89, 36}, {186, 109, 44}, {216, 127, 51}, {114, 67, 27},
{125, 53, 152}, {153, 65, 186}, {178, 76, 216}, {94, 40, 114},
{72, 108, 152}, {88, 132, 186}, {102, 153, 216}, {54, 81, 114},
{161, 161, 36}, {197, 197, 44}, {229, 229, 51}, {121, 121, 27},
{89, 144, 17}, {109, 176, 21}, {127, 204, 25}, {67, 108, 13},
{170, 89, 116}, {208, 109, 142}, {242, 127, 165}, {128, 67, 87},
{53, 53, 53}, {65, 65, 65}, {76, 76, 76}, {40, 40, 40},
{108, 108, 108}, {132, 132, 132}, {153, 153, 153}, {81, 81, 81},
{53, 89, 108}, {65, 109, 132}, {76, 127, 153}, {40, 67, 81},
{89, 44, 125}, {109, 54, 153}, {127, 63, 178}, {67, 33, 94},
{36, 53, 125}, {44, 65, 153}, {51, 76, 178}, {27, 40, 94},
{72, 53, 36}, {88, 65, 44}, {102, 76, 51}, {54, 40, 27},
{72, 89, 36}, {88, 109, 44}, {102, 127, 51}, {54, 67, 27},
{108, 36, 36}, {132, 44, 44}, {153, 51, 51}, {81, 27, 27},
{17, 17, 17}, {21, 21, 21}, {25, 25, 25}, {13, 13, 13},
{176, 168, 54}, {215, 205, 66}, {250, 238, 77}, {132, 126, 40},
{64, 154, 150}, {79, 188, 183}, {92, 219, 213}, {48, 115, 112},
{52, 90, 180}, {63, 110, 220}, {74, 128, 255}, {39, 67, 135},
{0, 153, 40}, {0, 187, 50}, {0, 217, 58}, {0, 114, 30},
{91, 60, 34}, {111, 74, 42}, {129, 86, 49}, {68, 45, 25},
{79, 1, 0}, {96, 1, 0}, {112, 2, 0}, {59, 1, 0},
{147, 124, 113}, {180, 152, 138}, {209, 177, 161}, {110, 93, 85},
{112, 57, 25}, {137, 70, 31}, {159, 82, 36}, {84, 43, 19},
{105, 61, 76}, {128, 75, 93}, {149, 87, 108}, {78, 46, 57},
{79, 76, 97}, {96, 93, 119}, {112, 108, 138}, {59, 57, 73},
{131, 93, 25}, {160, 114, 31}, {186, 133, 36}, {98, 70, 19},
{72, 82, 37}, {88, 100, 45}, {103, 117, 53}, {54, 61, 28},
{112, 54, 55}, {138, 66, 67}, {160, 77, 78}, {84, 40, 41},
{40, 28, 24}, {49, 35, 30}, {57, 41, 35}, {30, 21, 18},
{95, 75, 69}, {116, 92, 84}, {135, 107, 98}, {71, 56, 51},
{61, 64, 64}, {75, 79, 79}, {87, 92, 92}, {46, 48, 48},
{86, 51, 62}, {105, 62, 75}, {122, 73, 88}, {64, 38, 46},
{53, 43, 64}, {65, 53, 79}, {76, 62, 92}, {40, 32, 48},
{53, 35, 24}, {65, 43, 30}, {76, 50, 35}, {40, 26, 18},
{53, 57, 29}, {65, 70, 36}, {76, 82, 42}, {40, 43, 22},
{100, 42, 32}, {122, 51, 39}, {142, 60, 46}, {75, 31, 24},
{26, 15, 11}, {31, 18, 13}, {37, 22, 16}, {19, 11, 8}
};
//Code from Bukkit's MapPalette class
double getDistance(Color c1, Color c2) {
double rmean = (c1.red + c2.red) / 2.0;
double r = c1.red - c2.red;
double g = c1.green - c2.green;
int b = c1.blue - c2.blue;
double weightR = 2 + rmean / 256.0;
double weightG = 4.0;
double weightB = 2 + (255 - rmean) / 256.0;
return weightR * r * r + weightG * g * g + weightB * b * b;
}
//Code from Bukkit's MapPalette class
char matchColor(NativeColor nc) {
//if (nc.alpha < 128) return 0;
Color color={.red=nc.red, .green=nc.green, .blue=nc.blue};
char index = 0;
double best = -1;
for (short i = 4; i < sizeof(colors)/sizeof(Color); i++) {
double distance = getDistance(color, colors[i]);
if (distance < best || best == -1) {
best = distance;
index = i;
}
}
// Minecraft has 143 colors, some of which have negative byte representations
//return (byte) (index < 128 ? index : -129 + (index - 127));
return index;
}
//Testing only
int convert(int px[], int *out[]) {
printf("convert...\n");
printf("px0: %d\n", px[0]);
*out[0]=19;
return 0;
}
void __attribute__ ((constructor)) initLibrary(void) {
//
// Function that is called when the library is loaded
//
printf("Library is initialized\n");
}
void __attribute__ ((destructor)) cleanUpLibrary(void) {
//
// Function that is called when the library is »closed«.
//
printf("Library is exited\n");
}

31
libpxc/pxct.c Normal file
View file

@ -0,0 +1,31 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
gcc -Wall -c -fpic pxc.c
gcc -Wall -shared pxc.o -o pxc.so
gcc -Wall pxct.c -L. -lpxc -Wl,-rpath=.
*/
int convert(int px[], int *out[]);
typedef long long int addr;
void setSource(addr address, short w, short h, short mcx, short mcy);
void* updateAndGetMap(int x, int y, int w, int h, int** out_changed);
int main() {
printf("Setting source...");
void* p = malloc(640*480*4);
setSource((addr)p, 640, 480, 5, 4);
printf("Adding random values...\n");
srand(time(NULL));
unsigned int* xp=p;
for(int i=0; i<640*480; i++)
*(xp++)=rand();
printf("Updating map...");
void* x=updateAndGetMap(0, 0, 320, 240, NULL);
free(p);
return 0;
}