diff --git a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/LauncherProperties.java b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/LauncherProperties.java index eea8dac..69d5039 100644 --- a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/LauncherProperties.java +++ b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/LauncherProperties.java @@ -97,5 +97,6 @@ public interface LauncherProperties extends HmcProperties { Property GAME_DIR_FOR_EACH_VERSION = bool("hmc.game.dir.for.each.version"); Property INSTALL_LOGGING = bool("hmc.install.mc.logging"); + Property CHECK_XVFB = bool("hmc.check.xvfb"); } diff --git a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/LaunchOptions.java b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/LaunchOptions.java index 7a409e8..bf18633 100644 --- a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/LaunchOptions.java +++ b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/LaunchOptions.java @@ -49,8 +49,12 @@ public LaunchOptionsBuilder parseFlags( 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()) { - log.warning("You are offline, game will start in headless mode!"); - lwjgl = true; + if (!new XvfbService(launcher.getConfigService(), launcher.getProcessFactory().getOs()).isRunningWithXvfb()) { + log.warning("You are offline, game will start in headless mode!"); + lwjgl = true; + } else { + log.info("You are offline but running with xvfb, not using headless mode."); + } } return this diff --git a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/XvfbService.java b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/XvfbService.java new file mode 100644 index 0000000..c12a4ac --- /dev/null +++ b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/launch/XvfbService.java @@ -0,0 +1,52 @@ +package me.earth.headlessmc.launcher.launch; + +import lombok.Cleanup; +import lombok.CustomLog; +import lombok.RequiredArgsConstructor; +import me.earth.headlessmc.launcher.LauncherProperties; +import me.earth.headlessmc.launcher.files.ConfigService; +import me.earth.headlessmc.launcher.os.OS; +import me.earth.headlessmc.launcher.util.IOUtil; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Locale; + +@CustomLog +@RequiredArgsConstructor +public class XvfbService { + private final ConfigService configService; + private final OS os; + + private boolean checked; + private boolean runningWithXvfb; + + public boolean isRunningWithXvfb() { + if (!checked) { + try { + runningWithXvfb = checkRunningWithXvfb(); + } catch (IOException e) { + log.error(e); + } finally { + checked = true; + } + } + + return runningWithXvfb; + } + + private boolean checkRunningWithXvfb() throws IOException { + if (os.getType() != OS.Type.LINUX || !configService.getConfig().get(LauncherProperties.CHECK_XVFB, false)) { + return false; + } + + Process process = new ProcessBuilder().command("ps", "aux").start(); + @Cleanup + BufferedReader reader = IOUtil.reader(process.getInputStream()); + String output = IOUtil.read(reader); + boolean result = output.toLowerCase(Locale.ENGLISH).contains("xvfb"); + log.info(result ? "Running with xvfb" : "Not running with xvfb"); + return result; + } + +} diff --git a/headlessmc-lwjgl/src/main/java/me/earth/headlessmc/lwjgl/redirections/LwjglRedirections.java b/headlessmc-lwjgl/src/main/java/me/earth/headlessmc/lwjgl/redirections/LwjglRedirections.java index 6283d26..728bdaf 100644 --- a/headlessmc-lwjgl/src/main/java/me/earth/headlessmc/lwjgl/redirections/LwjglRedirections.java +++ b/headlessmc-lwjgl/src/main/java/me/earth/headlessmc/lwjgl/redirections/LwjglRedirections.java @@ -277,6 +277,18 @@ public static void register(RedirectionManager manager) { // 1.20.4 (3?) MemReallocRedirections.redirect(manager); + + // Embeddium + // https://github.com/3arthqu4ke/headlessmc/issues/208 + // manager.redirect("Lorg/lwjgl/opengl/GL32C;glFenceSync(II)J", of(1L)); + // not enough, game now crashes with SIGSEGV, use xvfb for embeddium + // v ~StubRoutines::jlong_disjoint_arraycopy + //J 10112 c2 jdk.internal.misc.Unsafe.copyMemory(Ljava/lang/Object;JLjava/lang/Object;JJ)V java.base@17.0.12 (33 bytes) @ 0x00007ea004efdf19 [0x00007ea004efdda0+0x0000000000000179] + //j jdk.internal.misc.Unsafe.copyMemory(JJJ)V+7 java.base@17.0.12 + //j sun.misc.Unsafe.copyMemory(JJJ)V+7 jdk.unsupported@17.0.12 + //j net.caffeinemc.mods.sodium.api.memory.MemoryIntrinsics.copyMemory(JJI)V+8 + //j net.minecraft.class_287.push(Lorg/lwjgl/system/MemoryStack;JILnet/caffeinemc/mods/sodium/api/vertex/format/VertexFormatDescription;)V+47 + //j me.jellysquid.mods.sodium.client.render.vertex.buffer.SodiumBufferBuilder.push(Lorg/lwjgl/system/MemoryStack;JILnet/caffeinemc/mods/sodium/api/vertex/format } }