Skip to content

Commit

Permalink
Refactor[jar launcher]: rework swap thread & classpath
Browse files Browse the repository at this point in the history
  • Loading branch information
khanhduytran0 committed Jan 28, 2024
1 parent d72d84d commit 7829917
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 120 deletions.
10 changes: 5 additions & 5 deletions JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,13 @@ public void uncaughtException(Thread t, Throwable th) {
}
});

System.setProperty("cacio.managed.screensize", args[2]);
try {
// Try to initialize Caciocavallo17
Class.forName("com.github.caciocavallosilano.cacio.ctc.CTCPreloadClassLoader");
} catch (ClassNotFoundException e) {}

if (args[0].equals("--launchJar")) {
UIKit.callback_JavaGUIViewController_launchJarFile(args[1]);
if (args[0].equals("-jar")) {
UIKit.callback_JavaGUIViewController_launchJarFile(args[1], Arrays.copyOfRange(args, 2, args.length));
} else {
launchMinecraft(args);
}
Expand All @@ -61,8 +60,9 @@ public static void launchMinecraft(String[] args) throws Throwable {
System.setProperty("appdir", "./spiral");
System.setProperty("resource_dir", "./spiral/rsrc");

System.setProperty("glfw.windowSize", args[2]);
String[] size = args[2].split("x");
String sizeStr = System.getProperty("cacio.managed.screensize");
System.setProperty("glfw.windowSize", sizeStr);
String[] size = sizeStr.split("x");
MCOptionUtils.load();
MCOptionUtils.set("fullscreen", "false");
MCOptionUtils.set("overrideWidth", size[0]);
Expand Down
47 changes: 3 additions & 44 deletions JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,45 +29,7 @@ private static void patch_FlatLAF_setLinux() {
System.setProperty("os.name", osName);
}

public static void callback_JavaGUIViewController_launchJarFile(final String filepath) throws Throwable {
// Thread for refreshing the AWT buffer
new Thread(() -> {
Method getCurrentScreenRGB;
try {
try {
getCurrentScreenRGB = Class.forName("net.java.openjdk.cacio.ctc.CTCScreen").getMethod("getCurrentScreenRGB");
} catch (ClassNotFoundException e) {
getCurrentScreenRGB = Class.forName("com.github.caciocavallosilano.cacio.ctc.CTCScreen").getMethod("getCurrentScreenRGB");
}
} catch (Throwable th) {
System.err.println("Failed to find class CTCScreen");
th.printStackTrace();
System.exit(1);
return;
}

long lastTime = System.currentTimeMillis();
while (true) {
int[] pixelsArray = null;
try{
pixelsArray = (int[])getCurrentScreenRGB.invoke(null);
} catch (Throwable e) {}
if (pixelsArray != null) {
//System.out.println(java.util.Arrays.toString(pixelsArray));
refreshAWTBuffer(pixelsArray);
}
long currentTime = System.currentTimeMillis();
if (currentTime - lastTime < 16) {
try {
Thread.sleep(16 - (currentTime - lastTime));
} catch (InterruptedException e) {
break;
}
}
lastTime = currentTime;
}
}, "AWTFBRefreshThread").start();

public static void callback_JavaGUIViewController_launchJarFile(final String filepath, String[] args) throws Throwable {
// Launch the JAR file
String mainClassName = null;

Expand All @@ -78,15 +40,12 @@ public static void callback_JavaGUIViewController_launchJarFile(final String fil
throw new IllegalArgumentException("no main manifest attribute, in \"" + filepath + "\"");
}

PojavClassLoader loader = (PojavClassLoader) ClassLoader.getSystemClassLoader();
loader.addURL(new File(filepath).toURI().toURL());

// LabyMod Installer uses FlatLAF which has some macOS-specific codes, so we make it think it's running on Linux.
patch_FlatLAF_setLinux();

Class<?> clazz = loader.loadClass(mainClass);
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass(mainClass);
Method method = clazz.getMethod("main", String[].class);
method.invoke(null, new Object[]{new String[]{}});
method.invoke(null, new Object[]{args});
}

public static void updateMCGuiScale() {
Expand Down
105 changes: 72 additions & 33 deletions Natives/JavaGUIViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,43 +13,17 @@
#define SPECIALBTN_LOGOUTPUT -100

static BOOL shouldHitEnterAfterWindowShown;
static int* rgbArray;
static SurfaceView* surfaceView;

static jclass class_CTCAndroidInput;
static jmethodID method_ReceiveInput;

JNIEXPORT void JNICALL Java_net_kdt_pojavlaunch_uikit_UIKit_refreshAWTBuffer(JNIEnv* env, jclass clazz, jintArray jreRgbArray) {
if (!runtimeJNIEnvPtr) {
dispatch_async(dispatch_get_main_queue(), ^{
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL);
assert(runtimeJNIEnvPtr);
});
}

int *tmpArray = (*env)->GetIntArrayElements(env, jreRgbArray, 0);
memcpy(rgbArray, tmpArray, windowWidth * windowHeight * 4);
(*env)->ReleaseIntArrayElements(env, jreRgbArray, tmpArray, JNI_ABORT);
dispatch_async(dispatch_get_main_queue(), ^{
[surfaceView displayLayer];
});

// Wait until something renders at the middle
if (shouldHitEnterAfterWindowShown && rgbArray[windowWidth/2 + windowWidth*windowHeight/2] != 0) {
shouldHitEnterAfterWindowShown = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^(void){
// Auto hit Enter to install immediately
AWTInputBridge_sendKey('\n');
});
}
}

void AWTInputBridge_nativeSendData(int type, int i1, int i2, int i3, int i4) {
if (runtimeJNIEnvPtr == NULL) {
if (!runtimeJNIEnvPtr) {
return;
}

if (method_ReceiveInput == NULL) {
if (!method_ReceiveInput) {
class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/java/openjdk/cacio/ctc/CTCAndroidInput");
if ((*runtimeJNIEnvPtr)->ExceptionCheck(runtimeJNIEnvPtr) == JNI_TRUE) {
(*runtimeJNIEnvPtr)->ExceptionClear(runtimeJNIEnvPtr);
Expand Down Expand Up @@ -78,11 +52,66 @@ void AWTInputBridge_sendKey(int keycode) {
AWTInputBridge_nativeSendData(EVENT_TYPE_KEY, ' ', keycode, 0, 0);
}

@interface SurfaceView()
@interface SurfaceView() {
JNIEnv *surfaceJNIEnv;
jclass class_CTCScreen;
jmethodID method_GetRGB;
int *rgbArray;
}
@property(nonatomic) CGColorSpaceRef colorSpace;
@end

@implementation SurfaceView
- (void)refreshBuffer {
if (!runtimeJavaVMPtr) {
// JVM is not ready yet
return;
} else if (!surfaceJNIEnv) {
// Obtain JNIEnvs
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &surfaceJNIEnv, NULL);
assert(surfaceJNIEnv);
dispatch_async(dispatch_get_main_queue(), ^{
(*runtimeJavaVMPtr)->AttachCurrentThread(runtimeJavaVMPtr, &runtimeJNIEnvPtr, NULL);
assert(runtimeJNIEnvPtr);
});

// Obtain CTCScreen.getCurrentScreenRGB()
class_CTCScreen = (*surfaceJNIEnv)->FindClass(surfaceJNIEnv, "net/java/openjdk/cacio/ctc/CTCScreen");
if ((*surfaceJNIEnv)->ExceptionCheck(surfaceJNIEnv) == JNI_TRUE) {
(*surfaceJNIEnv)->ExceptionClear(surfaceJNIEnv);
class_CTCScreen = (*surfaceJNIEnv)->FindClass(surfaceJNIEnv, "com/github/caciocavallosilano/cacio/ctc/CTCScreen");
}
assert(class_CTCScreen != NULL);
method_GetRGB = (*surfaceJNIEnv)->GetStaticMethodID(surfaceJNIEnv, class_CTCScreen, "getCurrentScreenRGB", "()[I");
assert(method_GetRGB != NULL);
rgbArray = calloc(4, (size_t) (windowWidth * windowHeight));
}

jintArray jreRgbArray = (jintArray) (*surfaceJNIEnv)->CallStaticObjectMethod(
surfaceJNIEnv,
class_CTCScreen,
method_GetRGB
);
if (!jreRgbArray) {
return;
}
int *tmpArray = (*surfaceJNIEnv)->GetIntArrayElements(surfaceJNIEnv, jreRgbArray, 0);
memcpy(rgbArray, tmpArray, windowWidth * windowHeight * 4);
(*surfaceJNIEnv)->ReleaseIntArrayElements(surfaceJNIEnv, jreRgbArray, tmpArray, JNI_ABORT);
dispatch_async(dispatch_get_main_queue(), ^{
[surfaceView displayLayer];
});

// Wait until something renders at the middle
if (shouldHitEnterAfterWindowShown && rgbArray[windowWidth/2 + windowWidth*windowHeight/2] != 0) {
shouldHitEnterAfterWindowShown = NO;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC), dispatch_get_main_queue(), ^(void){
// Auto hit Enter to install immediately
AWTInputBridge_sendKey('\n');
});
}
}

- (void)displayLayer {
CGDataProviderRef bitmapProvider = CGDataProviderCreateWithData(NULL, rgbArray, windowWidth * windowHeight * 4, NULL);
CGImageRef bitmap = CGImageCreate(windowWidth, windowHeight, 8, 32, 4 * windowWidth, _colorSpace, kCGImageAlphaFirst | kCGBitmapByteOrder32Little, bitmapProvider, NULL, FALSE, kCGRenderingIntentDefault);
Expand Down Expand Up @@ -266,9 +295,21 @@ - (void)viewDidLoad {
self.logOutputView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.view addSubview:self.logOutputView];

rgbArray = calloc(4, (size_t) (windowWidth * windowHeight));

setenv("POJAV_SKIP_JNI_GLFW", "1", 1);

// Register the display loop
CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:surfaceView selector:@selector(refreshBuffer)];
if (@available(iOS 15.0, tvOS 15.0, *)) {
if(getPrefBool(@"video.max_framerate")) {
displayLink.preferredFrameRateRange = CAFrameRateRangeMake(30, 120, 120);
} else {
displayLink.preferredFrameRateRange = CAFrameRateRangeMake(30, 60, 60);
}
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[displayLink addToRunLoop:NSRunLoop.currentRunLoop forMode:NSRunLoopCommonModes];
});


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
launchJVM(nil, self.filepath, windowWidth, windowHeight, _requiredJavaVersion);
Expand Down Expand Up @@ -373,8 +414,6 @@ - (int)requiredJavaVersion {
}

- (void)showErrorMessage:(NSString *)message {
free(rgbArray);
rgbArray = NULL;
surfaceView = nil;
showDialog(localize(@"Error", nil), message);
}
Expand Down
33 changes: 20 additions & 13 deletions Natives/JavaLauncher.m
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
init_loadDefaultEnv();
init_loadCustomEnv();

BOOL launchJar = NO;
NSString *gameDir;

NSString *defaultJRETag;
if ([launchTarget isKindOfClass:NSDictionary.class]) {
// Get preferred Java version from current profile
Expand Down Expand Up @@ -126,6 +126,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
} else {
defaultJRETag = @"execute_jar";
gameDir = @(getenv("POJAV_GAME_DIR"));
launchJar = YES;
}
NSLog(@"[JavaLauncher] Looking for Java %d or later", minVersion);
NSString *javaHome = getSelectedJavaHome(defaultJRETag, minVersion);
Expand Down Expand Up @@ -171,7 +172,9 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi

margv[++margc] = [NSString stringWithFormat:@"%@/bin/java", javaHome].UTF8String;
margv[++margc] = "-XstartOnFirstThread";
margv[++margc] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader";
if (!launchJar) {
margv[++margc] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader";
}
margv[++margc] = "-Xms128M";
margv[++margc] = [NSString stringWithFormat:@"-Xmx%dM", allocmem].UTF8String;
margv[++margc] = [NSString stringWithFormat:@"-Djava.library.path=%@/Frameworks", NSBundle.mainBundle.bundlePath].UTF8String;
Expand Down Expand Up @@ -204,11 +207,6 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
margv[++margc] = "-XX:+UnlockExperimentalVMOptions";
margv[++margc] = "-XX:+DisablePrimordialThreadGuardPages";

// Setup Caciocavallo
margv[++margc] = "-Djava.awt.headless=false";
margv[++margc] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager";
margv[++margc] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler";

// Disable Forge 1.16.x early progress window
margv[++margc] = "-Dfml.earlyprogresswindow=false";

Expand All @@ -227,17 +225,21 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
return 1;
}

// Setup Caciocavallo
margv[++margc] = "-Djava.awt.headless=false";
margv[++margc] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager";
margv[++margc] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler";
margv[++margc] = [NSString stringWithFormat:@"-Dcacio.managed.screensize=%dx%d", width, height].UTF8String;
margv[++margc] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel";
if (isJava8) {
// Setup Caciocavallo
margv[++margc] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel";
margv[++margc] = "-Dawt.toolkit=net.java.openjdk.cacio.ctc.CTCToolkit";
margv[++margc] = "-Djava.awt.graphicsenv=net.java.openjdk.cacio.ctc.CTCGraphicsEnvironment";
} else {
// Required by Cosmetica to inject DNS
margv[++margc] = "--add-opens=java.base/java.net=ALL-UNNAMED";

// Setup Caciocavallo
margv[++margc] = "-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel";
margv[++margc] = "-Dawt.toolkit=com.github.caciocavallosilano.cacio.ctc.CTCToolkit";
margv[++margc] = "-Djava.awt.graphicsenv=com.github.caciocavallosilano.cacio.ctc.CTCGraphicsEnvironment";

Expand Down Expand Up @@ -289,21 +291,26 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi
init_loadCustomJvmFlags(&margc, (const char **)margv);
NSLog(@"[Init] Found JLI lib");

NSString *classpath = [NSString stringWithFormat:@"%@/*", librariesPath];
if (launchJar) {
classpath = [classpath stringByAppendingFormat:@":%@", launchTarget];
}
margv[++margc] = "-cp";
margv[++margc] = [NSString stringWithFormat:@"%@/*", librariesPath].UTF8String;
margv[++margc] = classpath.UTF8String;
margv[++margc] = "net.kdt.pojavlaunch.PojavLauncher";

if (username == nil) {
margv[++margc] = "--launchJar";
if (launchJar) {
margv[++margc] = "-jar";
} else {
margv[++margc] = username.UTF8String;
}

if ([launchTarget isKindOfClass:NSDictionary.class]) {
margv[++margc] = [launchTarget[@"id"] UTF8String];
} else {
margv[++margc] = [launchTarget UTF8String];
}
margv[++margc] = [NSString stringWithFormat:@"%dx%d", width, height].UTF8String;
//margv[++margc] = "ghidra.GhidraRun";

pJLI_Launch = (JLI_Launch_func *)dlsym(libjli, "JLI_Launch");

Expand Down
1 change: 1 addition & 0 deletions Natives/PLLogOutputView.m
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ + (void)appendToLog:(NSString *)string {
}

+ (void)handleExitCode:(int)code {
if (!current) return;
dispatch_async(dispatch_get_main_queue(), ^(void){
if (current.hidden) {
[current actionToggleLogOutput];
Expand Down
Loading

0 comments on commit 7829917

Please sign in to comment.