Skip to content

Commit

Permalink
Potential fix for xrandr xvfb on old versions
Browse files Browse the repository at this point in the history
  • Loading branch information
3arthqu4ke committed Nov 13, 2024
1 parent 9518393 commit 2bfdfc6
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 4 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ HeadlessMc can run inside Termux.
* Download the headlessmc-launcher-wrapper.jar into Termux.
* Disable JLine, as we could not get it to work on Termux for now,
by adding `hmc.jline.enabled=false` to the HeadlessMC/config.properties.
* Now you can use HeadlessMc like you do on Desktop or Docker.
* Now you can use HeadlessMc like you would on Desktop or Docker.

### Web

Expand All @@ -87,7 +87,7 @@ but it does not support all features we need to launch the game.
The CheerpJ instance can be tried out [here](https://3arthqu4ke.github.io/headlessmc/).
Secondly, there is [container2wasm](https://github.com/headlesshq/hmc-container2wasm),
which can translate the HeadlessMc Docker container
to WebAssembly and the run it inside the browser, but this is extremly slow.
to WebAssembly and the run it inside the browser, but this is extremely slow.

### Optimizations

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ public interface LauncherProperties extends HmcProperties {
Property<Boolean> GAME_DIR_FOR_EACH_VERSION = bool("hmc.game.dir.for.each.version");

Property<Boolean> INSTALL_LOGGING = bool("hmc.install.mc.logging");

Property<Boolean> CHECK_XVFB = bool("hmc.check.xvfb");

}
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
package me.earth.headlessmc.launcher.instrumentation;

import lombok.CustomLog;
import lombok.experimental.UtilityClass;
import lombok.val;
import me.earth.headlessmc.launcher.instrumentation.log4j.Patchers;
import me.earth.headlessmc.launcher.instrumentation.lwjgl.HmcLwjglTransformer;
import me.earth.headlessmc.launcher.instrumentation.modlauncher.BootstrapLauncherTransformer;
import me.earth.headlessmc.launcher.instrumentation.paulscode.PaulscodeTransformer;
import me.earth.headlessmc.launcher.instrumentation.xvfb.XvfbLwjglTransformer;
import me.earth.headlessmc.launcher.launch.LaunchOptions;
import me.earth.headlessmc.launcher.version.Library;
import me.earth.headlessmc.launcher.version.family.FamilyUtil;
import org.jetbrains.annotations.VisibleForTesting;

import java.util.ArrayList;
import java.util.List;

@CustomLog
@UtilityClass
public class InstrumentationHelper {
public static final String RUNTIME_JAR = "headlessmc-runtime.jar";
public static final String LWJGL_JAR = "headlessmc-lwjgl.jar";

public static Instrumentation create(LaunchOptions options) {
val transformers = new ArrayList<Transformer>(6);
val transformers = new ArrayList<Transformer>(8);
if (options.isLwjgl()) {
transformers.add(new HmcLwjglTransformer());
transformers.add(new ResourceExtractor(options.getFiles(), LWJGL_JAR));
Expand All @@ -42,7 +49,32 @@ public static Instrumentation create(LaunchOptions options) {
transformers.add(new BootstrapLauncherTransformer());
}

if (options.isXvfb()) {
addXvfbTransformer(options, transformers);
}

return new Instrumentation(transformers, options.getFiles().getBase());
}

@VisibleForTesting
static void addXvfbTransformer(LaunchOptions options, List<Transformer> transformers) {
log.error("Hello?!");
Boolean oldLwjgl = FamilyUtil.iterateParents(options.getVersion(), version -> {
for (Library library : version.getLibraries()) {
log.error("Cehcking " + library.getName());
if ("org.lwjgl.lwjgl".equals(library.getPackage()) && library.getVersionNumber().startsWith("2")) {
log.error("Hello? " + library);
return true;
}
}

return null;
});

if (oldLwjgl != null && oldLwjgl) {
log.info("Running with old lwjgl, using xvfb transformer");
transformers.add(new XvfbLwjglTransformer());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package me.earth.headlessmc.launcher.instrumentation.xvfb;

import lombok.CustomLog;
import me.earth.headlessmc.launcher.instrumentation.AbstractClassTransformer;
import me.earth.headlessmc.launcher.instrumentation.InstrumentationHelper;
import me.earth.headlessmc.launcher.instrumentation.Target;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;

import java.util.Locale;

@CustomLog
public class XvfbLwjglTransformer extends AbstractClassTransformer {
public XvfbLwjglTransformer() {
super("org/lwjgl/opengl/LinuxDisplay");
}

@Override
protected void transform(ClassNode cn) {
for (MethodNode mn : cn.methods) {
if ("getBestDisplayModeExtension".equals(mn.name) && "()I".equals(mn.desc)) {
for (AbstractInsnNode insnNode : mn.instructions) {
if (insnNode instanceof IntInsnNode && insnNode.getOpcode() == Opcodes.BIPUSH) {
IntInsnNode intInsnNode = (IntInsnNode) insnNode;
if (intInsnNode.operand == 10) { // private static final int XRANDR = 10;
log.info("Found BI_PUSH XRANDR, replacing with XF86VIDMODE");
intInsnNode.operand = 11; // XF86VIDMODE, idk lets just try this?
}
}
}
}
}
}

@Override
public boolean matches(Target target) {
return target.getPath().toLowerCase(Locale.ENGLISH).contains("lwjgl")
&& !target.getPath().endsWith(InstrumentationHelper.LWJGL_JAR);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ public class LaunchOptions {
private final boolean inMemory;
private final boolean forceSimple;
private final boolean forceBoot;
private final boolean xvfb;
private final boolean prepare;

@SuppressWarnings("unused")
Expand All @@ -46,10 +47,12 @@ private LaunchOptionsBuilder() {

public LaunchOptionsBuilder parseFlags(
Launcher ctx, boolean quit, String... args) {
boolean xvfb = false;
boolean lwjgl = flag(ctx, "-lwjgl", INVERT_LWJGL_FLAG, ALWAYS_LWJGL_FLAG, args);
// if offline only allow launching with the lwjgl flag!
if (!lwjgl && launcher.getAccountManager().getOfflineChecker().isOffline()) {
if (!new XvfbService(launcher.getConfigService(), launcher.getProcessFactory().getOs()).isRunningWithXvfb()) {
xvfb = new XvfbService(launcher.getConfigService(), launcher.getProcessFactory().getOs()).isRunningWithXvfb();
if (!xvfb) {
log.warning("You are offline, game will start in headless mode!");
lwjgl = true;
} else {
Expand All @@ -68,6 +71,7 @@ public LaunchOptionsBuilder parseFlags(
.forceSimple(CommandUtil.hasFlag("-forceSimple", args))
.forceBoot(CommandUtil.hasFlag("-forceBoot", args))
.parseJvmArgs(args)
.xvfb(xvfb)
.noIn(quit);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package me.earth.headlessmc.launcher.instrumentation;

import me.earth.headlessmc.launcher.UsesResources;
import me.earth.headlessmc.launcher.launch.LaunchOptions;
import me.earth.headlessmc.launcher.version.ParsesVersions;
import me.earth.headlessmc.launcher.version.Version;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class InstrumentationHelperTest implements UsesResources, ParsesVersions {
@Test
public void testAddXvfbTransformer() {
Version version = parseVersion(getJsonObject("version_with_old_lwjgl.json"));
LaunchOptions launchOptions = LaunchOptions.builder().version(version).build();
List<Transformer> transformers = new ArrayList<>();
InstrumentationHelper.addXvfbTransformer(launchOptions, transformers);
assertEquals(1, transformers.size());

version = parseVersion(getJsonObject("version_with_new_lwjgl.json"));
launchOptions = LaunchOptions.builder().version(version).build();
transformers = new ArrayList<>();
InstrumentationHelper.addXvfbTransformer(launchOptions, transformers);
assertEquals(0, transformers.size());
}

}
20 changes: 20 additions & 0 deletions headlessmc-launcher/src/test/resources/version_with_new_lwjgl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "version-without-parent",
"inheritsFrom": "1.18",
"releaseTime": "2022-06-17T19:10:29+0000",
"time": "2022-06-17T19:10:29+0000",
"type": "release",
"mainClass": "me.earth.headlessmc.runtime.Main",
"arguments": {
"game": [],
"jvm": [
"-DMainClass\u003d net.minecraft.client.main.Main "
]
},
"libraries": [
{
"name": "org.lwjgl.lwjgl:lwjgl-platform:3.1.0",
"url": "http://lwjgl-url"
}
]
}
20 changes: 20 additions & 0 deletions headlessmc-launcher/src/test/resources/version_with_old_lwjgl.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"id": "version-without-parent",
"inheritsFrom": "1.18",
"releaseTime": "2022-06-17T19:10:29+0000",
"time": "2022-06-17T19:10:29+0000",
"type": "release",
"mainClass": "me.earth.headlessmc.runtime.Main",
"arguments": {
"game": [],
"jvm": [
"-DMainClass\u003d net.minecraft.client.main.Main "
]
},
"libraries": [
{
"name": "org.lwjgl.lwjgl:lwjgl-platform:2.9.4-nightly-20150209",
"url": "http://lwjgl-url"
}
]
}

0 comments on commit 2bfdfc6

Please sign in to comment.