diff --git a/.github/workflows/development.yml b/.github/workflows/development.yml index 80f7fea3..c09612aa 100644 --- a/.github/workflows/development.yml +++ b/.github/workflows/development.yml @@ -25,11 +25,33 @@ jobs: - name: Checkout repository submodules run: git submodule update --init --recursive + - name: Get JRE8 + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + path: depends + workflow_conclusion: success + repo: PojavLauncherTeam/android-openjdk-build-multiarch + branch: jre8-ios-jitjailed + name: jre8-ios-aarch64 + + - name: Get JRE17 + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + path: depends + workflow_conclusion: success + repo: PojavLauncherTeam/android-openjdk-build-multiarch + branch: buildjre17 + name: jre17-ios-aarch64 + - name: Build packages env: password: ${{ secrets.ELLIE_MINI_SECRET }} run: | - export NOSTDIN=1 SUDOPASS=$password + export NOSTDIN=1 SUDOPASS=$password RUNNER=1 export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) gmake -j$(sysctl -n hw.ncpu) ipa diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ff9a7226..e59796b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -25,12 +25,34 @@ jobs: - name: Checkout repository submodules run: git submodule update --init --recursive + - name: Get JRE8 + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + path: depends + workflow_conclusion: success + repo: PojavLauncherTeam/android-openjdk-build-multiarch + branch: jre8-ios-jitjailed + name: jre8-ios-aarch64 + + - name: Get JRE17 + uses: dawidd6/action-download-artifact@v2 + with: + github_token: ${{secrets.GITHUB_TOKEN}} + workflow: build.yml + path: depends + workflow_conclusion: success + repo: PojavLauncherTeam/android-openjdk-build-multiarch + branch: buildjre17 + name: jre17-ios-aarch64 + - name: Build packages env: password: ${{ secrets.ELLIE_MINI_SECRET }} run: | export RELEASE=1 - export NOSTDIN=1 SUDOPASS=$password + export NOSTDIN=1 SUDOPASS=$password RUNNER=1 export JAVA_HOME=$(/usr/libexec/java_home -v 1.8) gmake -j$(sysctl -n hw.ncpu) ipa diff --git a/JavaApp/libs_caciocavallo17/cacio-shared-1.18-SNAPSHOT.jar b/JavaApp/libs_caciocavallo17/cacio-shared-1.18-SNAPSHOT.jar new file mode 100644 index 00000000..0d4859d2 Binary files /dev/null and b/JavaApp/libs_caciocavallo17/cacio-shared-1.18-SNAPSHOT.jar differ diff --git a/JavaApp/libs_caciocavallo17/cacio-tta-1.18-SNAPSHOT.jar b/JavaApp/libs_caciocavallo17/cacio-tta-1.18-SNAPSHOT.jar new file mode 100644 index 00000000..aba8d955 Binary files /dev/null and b/JavaApp/libs_caciocavallo17/cacio-tta-1.18-SNAPSHOT.jar differ diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java index b3457649..1e7fd4c5 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/PojavLauncher.java @@ -43,6 +43,10 @@ public class PojavLauncher { }); 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]); diff --git a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java index 7997e812..e0426508 100644 --- a/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java +++ b/JavaApp/src/main/java/net/kdt/pojavlaunch/uikit/UIKit.java @@ -3,7 +3,6 @@ package net.kdt.pojavlaunch.uikit; import java.io.*; import java.lang.reflect.*; import java.util.jar.*; -import net.java.openjdk.cacio.ctc.CTCScreen; import net.kdt.pojavlaunch.utils.MCOptionUtils; import net.kdt.pojavlaunch.*; import org.lwjgl.glfw.*; @@ -32,27 +31,39 @@ public class UIKit { public static void callback_JavaGUIViewController_launchJarFile(final String filepath) throws Throwable { // Thread for refreshing the AWT buffer new Thread(() -> { + Method getCurrentScreenRGB; try { - long lastTime = System.currentTimeMillis(); - while (true) { - int[] pixelsArray = null; - try{ - pixelsArray = CTCScreen.getCurrentScreenRGB(); - } catch (NullPointerException e) { - Thread.sleep(500); - } - if (pixelsArray != null) { - //System.out.println(java.util.Arrays.toString(pixelsArray)); - refreshAWTBuffer(pixelsArray); - } - long currentTime = System.currentTimeMillis(); - if (currentTime - lastTime < 16) { - Thread.sleep(16 - (currentTime - lastTime)); - } - lastTime = currentTime; + 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 (InterruptedException e) { - e.printStackTrace(); + } 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(); diff --git a/JavaApp/src/main/java/org/lwjgl/MemoryUtil.java b/JavaApp/src/main/java/org/lwjgl/MemoryUtil.java new file mode 100644 index 00000000..d41aa767 --- /dev/null +++ b/JavaApp/src/main/java/org/lwjgl/MemoryUtil.java @@ -0,0 +1,382 @@ +/* + * Copyright (c) 2002-2011 LWJGL Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of 'LWJGL' nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.lwjgl; + +import java.lang.reflect.Field; +import java.nio.*; +import java.nio.charset.*; + +/** + * [INTERNAL USE ONLY] + *

+ * This class provides utility methods for passing buffers to JNI API calls. + * + * @author Spasi + */ +public final class MemoryUtil { + + private static final Charset ascii; + private static final Charset utf8; + + static { + ascii = Charset.forName("ISO-8859-1"); + utf8 = Charset.forName("UTF-8"); + } + + private MemoryUtil() { + } + + /** + * Returns the memory address of the specified buffer. [INTERNAL USE ONLY] + * + * @param buffer the buffer + * + * @return the memory address + */ + public static long getAddress0(Buffer buffer) { return org.lwjgl.system.MemoryUtil.memAddress0(buffer); } + + public static long getAddress0Safe(Buffer buffer) { return buffer == null ? 0L : getAddress0(buffer); } + + public static long getAddress0(PointerBuffer buffer) { return getAddress0(buffer.getBuffer()); } + + public static long getAddress0Safe(PointerBuffer buffer) { return buffer == null ? 0L : getAddress0(buffer.getBuffer()); } + + // --- [ API utilities ] --- + + public static long getAddress(ByteBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(ByteBuffer buffer, int position) { return getAddress0(buffer) + position; } + + public static long getAddress(ShortBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(ShortBuffer buffer, int position) { return getAddress0(buffer) + (position << 1); } + + public static long getAddress(CharBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(CharBuffer buffer, int position) { return getAddress0(buffer) + (position << 1); } + + public static long getAddress(IntBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(IntBuffer buffer, int position) { return getAddress0(buffer) + (position << 2); } + + public static long getAddress(FloatBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(FloatBuffer buffer, int position) { return getAddress0(buffer) + (position << 2); } + + public static long getAddress(LongBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(LongBuffer buffer, int position) { return getAddress0(buffer) + (position << 3); } + + public static long getAddress(DoubleBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(DoubleBuffer buffer, int position) { return getAddress0(buffer) + (position << 3); } + + public static long getAddress(PointerBuffer buffer) { return getAddress(buffer, buffer.position()); } + + public static long getAddress(PointerBuffer buffer, int position) { return getAddress0(buffer) + (position * PointerBuffer.getPointerSize()); } + + // --- [ API utilities - Safe ] --- + + public static long getAddressSafe(ByteBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(ByteBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(ShortBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(ShortBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(CharBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(CharBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(IntBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(IntBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(FloatBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(FloatBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(LongBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(LongBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(DoubleBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(DoubleBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + public static long getAddressSafe(PointerBuffer buffer) { return buffer == null ? 0L : getAddress(buffer); } + + public static long getAddressSafe(PointerBuffer buffer, int position) { return buffer == null ? 0L : getAddress(buffer, position); } + + // --- [ String utilities ] --- + + /** + * Returns a ByteBuffer containing the specified text ASCII encoded and null-terminated. + * If text is null, null is returned. + * + * @param text the text to encode + * + * @return the encoded text or null + * + * @see String#getBytes() + */ + public static ByteBuffer encodeASCII(final CharSequence text) { + return encode(text, ascii); + } + + /** + * Returns a ByteBuffer containing the specified text UTF-8 encoded and null-terminated. + * If text is null, null is returned. + * + * @param text the text to encode + * + * @return the encoded text or null + * + * @see String#getBytes() + */ + public static ByteBuffer encodeUTF8(final CharSequence text) { + return encode(text, utf8); + } + + /** + * Returns a ByteBuffer containing the specified text UTF-16LE encoded and null-terminated. + * If text is null, null is returned. + * + * @param text the text to encode + * + * @return the encoded text + */ + public static ByteBuffer encodeUTF16(final CharSequence text) { + return org.lwjgl.system.MemoryUtil.memUTF16(text); + } + + /** + * Wraps the specified text in a null-terminated CharBuffer and encodes it using the specified Charset. + * + * @param text the text to encode + * @param charset the charset to use for encoding + * + * @return the encoded text + */ + private static ByteBuffer encode(final CharSequence text, final Charset charset) { + if ( text == null ) + return null; + + return encode(CharBuffer.wrap(new CharSequenceNT(text)), charset); + } + + /** + * A {@link CharsetEncoder#encode(java.nio.CharBuffer)} implementation that uses {@link BufferUtils#createByteBuffer(int)} + * instead of {@link ByteBuffer#allocate(int)}. + * + * @see CharsetEncoder#encode(java.nio.CharBuffer) + */ + private static ByteBuffer encode(final CharBuffer in, final Charset charset) { + final CharsetEncoder encoder = charset.newEncoder(); // encoders are not thread-safe, create a new one on every call + + int n = (int)(in.remaining() * encoder.averageBytesPerChar()); + ByteBuffer out = BufferUtils.createByteBuffer(n); + + if ( n == 0 && in.remaining() == 0 ) + return out; + + encoder.reset(); + while ( true ) { + CoderResult cr = in.hasRemaining() ? encoder.encode(in, out, true) : CoderResult.UNDERFLOW; + if ( cr.isUnderflow() ) + cr = encoder.flush(out); + + if ( cr.isUnderflow() ) + break; + + if ( cr.isOverflow() ) { + n = 2 * n + 1; // Ensure progress; n might be 0! + ByteBuffer o = BufferUtils.createByteBuffer(n); + out.flip(); + o.put(out); + out = o; + continue; + } + + try { + cr.throwException(); + } catch (CharacterCodingException e) { + throw new RuntimeException(e); + } + } + out.flip(); + return out; + } + + public static String decodeASCII(final ByteBuffer buffer) { + return decode(buffer, ascii); + } + + public static String decodeUTF8(final ByteBuffer buffer) { + return decode(buffer, utf8); + } + + public static String decodeUTF16(final ByteBuffer buffer) { + return org.lwjgl.system.MemoryUtil.memUTF16(buffer); + } + + private static String decode(final ByteBuffer buffer, final Charset charset) { + if ( buffer == null ) + return null; + + return decodeImpl(buffer, charset); + } + + private static String decodeImpl(final ByteBuffer in, final Charset charset) { + final CharsetDecoder decoder = charset.newDecoder(); // decoders are not thread-safe, create a new one on every call + + int n = (int)(in.remaining() * decoder.averageCharsPerByte()); + CharBuffer out = BufferUtils.createCharBuffer(n); + + if ( (n == 0) && (in.remaining() == 0) ) + return ""; + + decoder.reset(); + for (; ; ) { + CoderResult cr = in.hasRemaining() ? decoder.decode(in, out, true) : CoderResult.UNDERFLOW; + if ( cr.isUnderflow() ) + cr = decoder.flush(out); + + if ( cr.isUnderflow() ) + break; + if ( cr.isOverflow() ) { + n = 2 * n + 1; // Ensure progress; n might be 0! + CharBuffer o = BufferUtils.createCharBuffer(n); + out.flip(); + o.put(out); + out = o; + continue; + } + try { + cr.throwException(); + } catch (CharacterCodingException e) { + throw new RuntimeException(e); + } + } + out.flip(); + return out.toString(); + } + + /** A null-terminated CharSequence. */ + private static class CharSequenceNT implements CharSequence { + + final CharSequence source; + + CharSequenceNT(CharSequence source) { + this.source = source; + } + + public int length() { + return source.length() + 1; + + } + + public char charAt(final int index) { + return index == source.length() ? '\0' : source.charAt(index); + + } + + public CharSequence subSequence(final int start, final int end) { + return new CharSequenceNT(source.subSequence(start, Math.min(end, source.length()))); + } + + } + + interface Accessor { + + long getAddress(Buffer buffer); + + } + + private static Accessor loadAccessor(final String className) throws Exception { + return (Accessor)Class.forName(className).newInstance(); + } + + /** Default implementation. */ + private static class AccessorJNI implements Accessor { + + public long getAddress(final Buffer buffer) { + return BufferUtils.getBufferAddress(buffer); + } + + } + + /** Implementation using reflection on ByteBuffer. */ + private static class AccessorReflect implements Accessor { + + private final Field address; + + AccessorReflect() { + try { + address = getAddressField(); + } catch (NoSuchFieldException e) { + throw new UnsupportedOperationException(e); + } + address.setAccessible(true); + } + + public long getAddress(final Buffer buffer) { + try { + return address.getLong(buffer); + } catch (IllegalAccessException e) { + // cannot happen + return 0L; + } + } + + } + + static Field getAddressField() throws NoSuchFieldException { + return getDeclaredFieldRecursive(ByteBuffer.class, "address"); + } + + private static Field getDeclaredFieldRecursive(final Class root, final String fieldName) throws NoSuchFieldException { + Class type = root; + + do { + try { + return type.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + type = type.getSuperclass(); + } + } while ( type != null ); + + throw new NoSuchFieldException(fieldName + " does not exist in " + root.getSimpleName() + " or any of its superclasses."); + } + +} diff --git a/JavaApp/src/main/java/org/lwjgl/openal/AL.java b/JavaApp/src/main/java/org/lwjgl/openal/AL.java index 8c2a288f..8b25f2d0 100644 --- a/JavaApp/src/main/java/org/lwjgl/openal/AL.java +++ b/JavaApp/src/main/java/org/lwjgl/openal/AL.java @@ -4,7 +4,8 @@ */ package org.lwjgl.openal; -import org.lwjgl.*; +import org.lwjgl.BufferUtils; +import org.lwjgl.LWJGLException; import org.lwjgl.system.*; import javax.annotation.*; diff --git a/JavaApp/src/main/java/org/lwjgl/opengl/ARBShaderObjects.java b/JavaApp/src/main/java/org/lwjgl/opengl/ARBShaderObjects.java index c5ee3318..634279db 100644 --- a/JavaApp/src/main/java/org/lwjgl/opengl/ARBShaderObjects.java +++ b/JavaApp/src/main/java/org/lwjgl/opengl/ARBShaderObjects.java @@ -9,8 +9,7 @@ import javax.annotation.*; import java.nio.*; -import org.lwjgl.*; - +import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; import static org.lwjgl.system.Checks.*; @@ -127,25 +126,49 @@ public class ARBShaderObjects { glUniform4fvARB(location, value); } - public static void glUniform1ARB(@NativeType("GLint") int location, @NativeType("GLfloat const *") IntBuffer value) { + public static void glUniform1ARB(@NativeType("GLint") int location, @NativeType("GLint const *") IntBuffer value) { glUniform1ivARB(location, value); } - public static void glUniform2ARB(@NativeType("GLint") int location, @NativeType("GLfloat const *") IntBuffer value) { + public static void glUniform2ARB(@NativeType("GLint") int location, @NativeType("GLint const *") IntBuffer value) { glUniform2ivARB(location, value); } - public static void glUniform3ARB(@NativeType("GLint") int location, @NativeType("GLfloat const *") IntBuffer value) { + public static void glUniform3ARB(@NativeType("GLint") int location, @NativeType("GLint const *") IntBuffer value) { glUniform3ivARB(location, value); } - public static void glUniform4ARB(@NativeType("GLint") int location, @NativeType("GLfloat const *") IntBuffer value) { + public static void glUniform4ARB(@NativeType("GLint") int location, @NativeType("GLint const *") IntBuffer value) { glUniform4ivARB(location, value); } + + public static void glUniformMatrix2ARB(@NativeType("GLint") int location, @NativeType("GLboolean") boolean transpose, @NativeType("GLfloat const *") FloatBuffer value) { + glUniformMatrix2fvARB(location, transpose, value); + } + + public static void glUniformMatrix3ARB(@NativeType("GLint") int location, @NativeType("GLboolean") boolean transpose, @NativeType("GLfloat const *") FloatBuffer value) { + glUniformMatrix3fvARB(location, transpose, value); + } + + public static void glUniformMatrix4ARB(@NativeType("GLint") int location, @NativeType("GLboolean") boolean transpose, @NativeType("GLfloat const *") FloatBuffer value) { + glUniformMatrix4fvARB(location, transpose, value); + } + + public static void glGetObjectParameterARB(@NativeType("GLhandleARB") int obj, @NativeType("GLenum") int pname, @NativeType("GLfloat *") FloatBuffer params) { + glGetObjectParameterfvARB(obj, pname, params); + } public static void glGetObjectParameterARB(@NativeType("GLhandleARB") int obj, @NativeType("GLenum") int pname, @NativeType("GLint *") IntBuffer params) { glGetObjectParameterivARB(obj, pname, params); } + + public static void glGetUniformARB(@NativeType("GLhandleARB") int programObj, @NativeType("GLint") int location, @NativeType("GLfloat *") FloatBuffer params) { + glGetUniformfvARB(programObj, location, params); + } + + public static void glGetUniformARB(@NativeType("GLhandleARB") int programObj, @NativeType("GLint") int location, @NativeType("GLint *") IntBuffer params) { + glGetUniformivARB(programObj, location, params); + } // -- End LWJGL2 part -- // --- [ glDeleteObjectARB ] --- diff --git a/JavaApp/src/main/java/org/lwjgl/opengl/GL11.java b/JavaApp/src/main/java/org/lwjgl/opengl/GL11.java index 32835e5e..687d98aa 100644 --- a/JavaApp/src/main/java/org/lwjgl/opengl/GL11.java +++ b/JavaApp/src/main/java/org/lwjgl/opengl/GL11.java @@ -9,7 +9,7 @@ import javax.annotation.*; import java.nio.*; -import org.lwjgl.*; +import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; diff --git a/JavaApp/src/main/java/org/lwjgl/opengl/GL15.java b/JavaApp/src/main/java/org/lwjgl/opengl/GL15.java index 373c620e..cac36f1f 100644 --- a/JavaApp/src/main/java/org/lwjgl/opengl/GL15.java +++ b/JavaApp/src/main/java/org/lwjgl/opengl/GL15.java @@ -9,7 +9,7 @@ import javax.annotation.*; import java.nio.*; -import org.lwjgl.*; +import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; diff --git a/JavaApp/src/main/java/org/lwjgl/opengl/GL20.java b/JavaApp/src/main/java/org/lwjgl/opengl/GL20.java index 92151666..b4e164e4 100644 --- a/JavaApp/src/main/java/org/lwjgl/opengl/GL20.java +++ b/JavaApp/src/main/java/org/lwjgl/opengl/GL20.java @@ -9,7 +9,8 @@ import javax.annotation.*; import java.nio.*; -import org.lwjgl.*; +import org.lwjgl.BufferUtils; +import org.lwjgl.PointerBuffer; import org.lwjgl.system.*; diff --git a/Makefile b/Makefile index 49367bbc..d47363ae 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,9 @@ IOS15PREF := private/preboot/procursus # Release vs Debug RELEASE ?= 0 +# Check if running on github runner +RUNNER ?= 0 + ifeq (1,$(RELEASE)) CMAKE_BUILD_TYPE := Release else @@ -149,7 +152,6 @@ DEPLOY = \ mv /var/tmp/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher && \ mv /var/tmp/*.jar $(1)/Applications/PojavLauncher.app/libs/ && \ cd $(1)/Applications/PojavLauncher.app/Frameworks && \ - ln -sf libawt_xawt.dylib libawt_headless.dylib && \ chown -R 501:501 $(1)/Applications/PojavLauncher.app/*"; \ else \ sudo rm -rf $(1)/Applications/PojavLauncher.app/Frameworks/libOSMesaOverride.dylib.framework; \ @@ -158,7 +160,6 @@ DEPLOY = \ sudo mv $(WORKINGDIR)/PojavLauncher.app/PojavLauncher $(1)/Applications/PojavLauncher.app/PojavLauncher; \ sudo mv $(SOURCEDIR)/JavaApp/local_out/*.jar $(1)/Applications/PojavLauncher.app/libs/; \ cd $(1)/Applications/PojavLauncher.app/Frameworks; \ - sudo ln -sf libawt_xawt.dylib libawt_headless.dylib; \ sudo chown -R 501:501 $(1)/Applications/PojavLauncher.app/*; \ fi @@ -297,13 +298,13 @@ deb: native java extras fi $(call DIRCHECK,$(WORKINGDIR)/PojavLauncher.app/libs) $(call DIRCHECK,$(WORKINGDIR)/PojavLauncher.app/libs_caciocavallo) + $(call DIRCHECK,$(WORKINGDIR)/PojavLauncher.app/libs_caciocavallo17) @cp -R $(SOURCEDIR)/Natives/resources/* $(WORKINGDIR)/PojavLauncher.app/ || exit 1 @cp $(WORKINGDIR)/*.dylib $(WORKINGDIR)/PojavLauncher.app/Frameworks/ || exit 1 - @( cd $(WORKINGDIR)/PojavLauncher.app/Frameworks; ln -sf libawt_xawt.dylib libawt_headless.dylib ) || exit 1 @cp -R $(WORKINGDIR)/*.framework $(WORKINGDIR)/PojavLauncher.app/Frameworks/ || exit 1 @cp -R $(SOURCEDIR)/JavaApp/libs/* $(WORKINGDIR)/PojavLauncher.app/libs/ || exit 1 @cp $(SOURCEDIR)/JavaApp/local_out/*.jar $(WORKINGDIR)/PojavLauncher.app/libs/ || exit 1 - @cp -R $(SOURCEDIR)/JavaApp/libs_caciocavallo/* $(WORKINGDIR)/PojavLauncher.app/libs_caciocavallo/ || exit 1 + @cp -R $(SOURCEDIR)/JavaApp/libs_caciocavallo* $(WORKINGDIR)/PojavLauncher.app/ || exit 1 @cp -R $(SOURCEDIR)/Natives/*.lproj $(WORKINGDIR)/PojavLauncher.app/ || exit 1 $(call DIRCHECK,$(OUTPUTDIR)) @cp -R $(WORKINGDIR)/PojavLauncher.app $(OUTPUTDIR) @@ -325,18 +326,22 @@ ipa: dsym echo 'Building PojavLauncher $(VERSION) - IPA - Start' mkdir -p $(SOURCEDIR)/depends; \ cd $(SOURCEDIR)/depends; \ - if [ ! -d "java-8-openjdk" ]; then \ + if [ ! -f "java-8-openjdk/bin/java" ] && [ ! -f "$(ls ../jre8-*.tar.xz)" ]; then \ + if [ "$(RUNNER)" != "1" ]; then \ + wget 'https://github.com/PojavLauncherTeam/android-openjdk-build-multiarch/releases/download/jre8-40df388/jre8-arm64-20220811-release.tar.xz'; \ + fi; \ mkdir java-8-openjdk && cd java-8-openjdk; \ - wget 'https://github.com/PojavLauncherTeam/android-openjdk-build-multiarch/releases/download/jre8-40df388/jre8-arm64-20220811-release.tar.xz'; \ - tar xvf *.tar.xz; \ - rm *.tar.xz; \ + tar xvf ../jre8-*.tar.xz; \ + rm ../jre8-*.tar.xz; \ fi; \ - cd ..; \ - if [ ! -d "java-17-openjdk" ]; then \ + cd ..; \ + if [ ! -f "java-17-openjdk/bin/java" ] && [ ! -f "$(ls ../jre17-*.tar.xz)" ]; then \ + if [ "$(RUNNER)" != "1" ]; then \ + wget 'https://github.com/PojavLauncherTeam/android-openjdk-build-multiarch/releases/download/jre17-ca01427/jre17-arm64-20220817-release.tar.xz'; \ + fi; \ mkdir java-17-openjdk && cd java-17-openjdk; \ - wget 'https://github.com/PojavLauncherTeam/android-openjdk-build-multiarch/releases/download/jre17-ca01427/jre17-arm64-20220817-release.tar.xz'; \ - tar xvf *.tar.xz; \ - rm *.tar.xz; \ + tar xvf ../jre17-*.tar.xz; \ + rm ../jre17-*.tar.xz; \ fi; \ mkdir -p $(OUTPUTDIR); \ cd $(OUTPUTDIR); \ @@ -346,6 +351,9 @@ ipa: dsym cp -R $(POJAV_JRE8_DIR) $(OUTPUTDIR)/Payload/PojavLauncher.app/jvm/; \ cp -R $(POJAV_JRE17_DIR) $(OUTPUTDIR)/Payload/PojavLauncher.app/jvm/; \ rm -rf $(OUTPUTDIR)/Payload/PojavLauncher.app/jvm/*/{bin,include,jre,lib/{ct.sym,libjsig.dylib,src.zip,tools.jar}}; \ + cp $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks/libawt_xawt.dylib $(OUTPUTDIR)/Payload/PojavLauncher.app/jvm/java-17-openjdk/lib/; \ + cp $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks/libawt_xawt.dylib $(OUTPUTDIR)/Payload/PojavLauncher.app/jvm/java-8-openjdk/lib/; \ + rm $(OUTPUTDIR)/Payload/PojavLauncher.app/Frameworks/libawt_*.dylib; \ ldid -S$(SOURCEDIR)/entitlements_ipa.xml $(OUTPUTDIR)/Payload/PojavLauncher.app/PojavLauncher; \ rm -f $(OUTPUTDIR)/*.ipa; \ cd $(OUTPUTDIR); \ diff --git a/Natives/CMakeLists.txt b/Natives/CMakeLists.txt index a8937bcd..6cdc08bd 100644 --- a/Natives/CMakeLists.txt +++ b/Natives/CMakeLists.txt @@ -21,7 +21,7 @@ include_directories( ) # For cacio support library -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rpath @executable_path/jvm/java-8-openjdk/lib -rpath /usr/lib/jvm/java-8-openjdk/lib") +set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rpath @loader_path -rpath @executable_path/jvm/java-8-openjdk/lib -rpath /usr/lib/jvm/java-8-openjdk/lib") add_definitions(-DCONFIG_COMMIT="${CONFIG_COMMIT}") add_definitions(-DCONFIG_RELEASE=${CONFIG_RELEASE}) @@ -103,6 +103,9 @@ add_executable(PojavLauncher external/DBNumberedSlider/Classes/DBNumberedSlider.m external/TOInsetGroupedTableView/TOInsetGroupedTableView/TOInsetGroupedTableView.m + input/ControllerInput.m + input/KeyboardInput.m + AboutLauncherViewController.m AccountListViewController.m AppDelegate.m @@ -110,7 +113,6 @@ add_executable(PojavLauncher FileListViewController.m GameSurfaceView.m JavaGUIViewController.m - KeyboardInput.m LauncherFAQViewController.m LauncherMenuViewController.m LauncherPreferences.m diff --git a/Natives/JavaGUIViewController.m b/Natives/JavaGUIViewController.m index 4a1690cc..13f72b9a 100644 --- a/Natives/JavaGUIViewController.m +++ b/Natives/JavaGUIViewController.m @@ -111,8 +111,16 @@ const void * _CGDataProviderGetBytePointerCallbackAWT(void *info) { } - (void)surfaceOnClick:(UITapGestureRecognizer *)sender { + if (runtimeJNIEnvPtr == NULL) { + return; + } + if (method_ReceiveInput == NULL) { class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "net/java/openjdk/cacio/ctc/CTCAndroidInput"); + if ((*runtimeJNIEnvPtr)->ExceptionCheck(runtimeJNIEnvPtr) == JNI_TRUE) { + (*runtimeJNIEnvPtr)->ExceptionClear(runtimeJNIEnvPtr); + class_CTCAndroidInput = (*runtimeJNIEnvPtr)->FindClass(runtimeJNIEnvPtr, "com/github/caciocavallosilano/cacio/ctc/CTCAndroidInput"); + } assert(class_CTCAndroidInput != NULL); method_ReceiveInput = (*runtimeJNIEnvPtr)->GetStaticMethodID(runtimeJNIEnvPtr, class_CTCAndroidInput, "receiveData", "(IIIII)V"); assert(method_ReceiveInput != NULL); diff --git a/Natives/JavaLauncher.m b/Natives/JavaLauncher.m index 525d2d5b..fb455aab 100644 --- a/Natives/JavaLauncher.m +++ b/Natives/JavaLauncher.m @@ -41,7 +41,9 @@ void init_loadCustomEnv() { /* Define default env */ // I accidentally patched a bit wrong, the value should be a path containing libawt_xawt.dylib, but here is libawt.dylib path (no need to exist) - setenv("JAVA_AWT_PATH", [NSString stringWithFormat:@"%s/Frameworks/libawt.dylib", getenv("BUNDLE_PATH")].UTF8String, 1); + if (getenv("POJAV_DETECTEDJB")) { + setenv("JAVA_AWT_PATH", [NSString stringWithFormat:@"%s/Frameworks/libawt.dylib", getenv("BUNDLE_PATH")].UTF8String, 1); + } // Disable overloaded functions hack for Minecraft 1.17+ setenv("LIBGL_NOINTOVLHACK", "1", 1); @@ -104,12 +106,7 @@ NSString* environmentFailsafes(int minVersion) { NSString *jre16Path = [NSString stringWithFormat:@"%@/java-16-openjdk", jvmPath]; NSString *jre17Path = [NSString stringWithFormat:@"%@/java-17-openjdk", jvmPath]; - BOOL foundJava8 = [fm fileExistsAtPath:jre8Path]; - if (!foundJava8) { - regLog("[JavaLauncher] Java 8 wasn't found on your device. Install Java 8 for more compatibility and the mod installer."); - } - - if (foundJava8 && minVersion <= 8) { + if ([fm fileExistsAtPath:jre8Path] && minVersion <= 8) { javaHome = jre8Path; } else if ([fm fileExistsAtPath:jre16Path] && minVersion <= 16) { javaHome = jre16Path; @@ -134,7 +131,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi NSString *javaHome_pre = getPreference(@"java_home"); // We handle unset JAVA_HOME right there - if (username == nil || getSelectedJavaVersion() < minVersion) { + if (getSelectedJavaVersion() < minVersion) { NSLog(@"[JavaLauncher] Attempting to change to Java %d (actual might be higher)", minVersion); javaHome_pre = environmentFailsafes(minVersion); NSLog(@"[JavaLauncher] JAVA_HOME is now set to %@", javaHome_pre); @@ -171,30 +168,9 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi allocmem_pre = [getPreference(@"allocated_memory") stringValue]; allocmem = [allocmem_pre cStringUsingEncoding:NSUTF8StringEncoding]; - - char classpath[10000]; // "/Applications/PojavLauncher.app/libs/launcher.jar:/Applications/PojavLauncher.app/libs/ExagearApacheCommons.jar:/Applications/PojavLauncher.app/libs/gson-2.8.6.jar:/Applications/PojavLauncher.app/libs/jsr305.jar:/Applications/PojavLauncher.app/libs/lwjgl3-minecraft.jar"; - // Generate classpath - DIR *d; - struct dirent *dir; - d = opendir(java_libs_path); - int cplen = -2; - if (d) { - // cplen += sprintf(classpath + cplen, "-Xbootclasspath/a:"); - while ((dir = readdir(d)) != NULL) { - if (cplen < 0) { - ++cplen; - continue; - } - cplen += sprintf(classpath + cplen, "%s/%s:", java_libs_path, dir->d_name); - } - classpath[cplen-1] = '\0'; - closedir(d); - } - debugLog("[JavaLauncher] Classpath generated: %s", classpath); - // Check if JVM restarts char *frameworkPath, *javaPath, *jnaLibPath, *userDir, *userHome, *memMin, *memMax, *arcDNS; asprintf(&frameworkPath, "-Djava.library.path=%1$s/Frameworks:%1$s/Frameworks/libOSMesaOverride.dylib.framework:%1$s/Frameworks/libMoltenVK.dylib.framework", getenv("BUNDLE_PATH")); @@ -202,7 +178,6 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi asprintf(&jnaLibPath, "-Djna.boot.library.path=%s/Frameworks/libjnidispatch.dylib.framework", getenv("BUNDLE_PATH")); asprintf(&userDir, "-Duser.dir=%s", getenv("POJAV_GAME_DIR")); asprintf(&userHome, "-Duser.home=%s", getenv("POJAV_HOME")); - asprintf(&memMin, "-Xms%sM", allocmem); asprintf(&memMax, "-Xmx%sM", allocmem); asprintf(&arcDNS, "-javaagent:%s/arc_dns_injector.jar=23.95.137.176", java_libs_path); NSLog(@"[JavaLauncher] Java executable path: %s", javaPath); @@ -211,7 +186,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi margv[++margc] = javaPath; margv[++margc] = "-XstartOnFirstThread"; margv[++margc] = "-Djava.system.class.loader=net.kdt.pojavlaunch.PojavClassLoader"; - margv[++margc] = memMin; + margv[++margc] = "-Xms128M"; margv[++margc] = memMax; margv[++margc] = frameworkPath; margv[++margc] = jnaLibPath; @@ -228,6 +203,11 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi margv[++margc] = (char *) [NSString stringWithFormat:@"-Dpojav.selectedAccount=%@", selectedAccount].UTF8String; } + // Setup Caciocavallo + margv[++margc] = "-Djava.awt.headless=false"; + margv[++margc] = "-Dcacio.font.fontmanager=sun.awt.X11FontManager"; + margv[++margc] = "-Dcacio.font.fontscaler=sun.font.FreetypeFontScaler"; + // Load java char libjlipath8[2048]; // java 8 char libjlipath16[2048]; // java 16+ (?) @@ -247,38 +227,69 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi } // 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] = "-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"; - - // Generate Caciocavallo bootclasspath - char cacio_libs_path[2048]; - char cacio_classpath[8192]; - sprintf((char*) cacio_libs_path, "%s/libs_caciocavallo", getenv("BUNDLE_PATH")); - cplen = sprintf(cacio_classpath, "-Xbootclasspath/p"); - d = opendir(cacio_libs_path); - int skip = 2; - if (d) { - while ((dir = readdir(d)) != NULL) { - if (skip > 0) { - --skip; - continue; - } - cplen += sprintf(cacio_classpath + cplen, ":%s/%s", cacio_libs_path, dir->d_name); - } - closedir(d); - } - margv[++margc] = cacio_classpath; } 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"; + // Required by Caciocavallo17 to access internal API + margv[++margc] = "--add-exports=java.desktop/java.awt=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/java.awt.peer=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.awt.image=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.java2d=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/java.awt.dnd.peer=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.awt=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.awt.event=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.awt.datatransfer=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.desktop/sun.font=ALL-UNNAMED"; + margv[++margc] = "--add-exports=java.base/sun.security.action=ALL-UNNAMED"; + margv[++margc] = "--add-opens=java.base/java.util=ALL-UNNAMED"; + margv[++margc] = "--add-opens=java.desktop/java.awt=ALL-UNNAMED"; + margv[++margc] = "--add-opens=java.desktop/sun.font=ALL-UNNAMED"; + margv[++margc] = "--add-opens=java.desktop/sun.java2d=ALL-UNNAMED"; + margv[++margc] = "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED"; + // TODO: workaround, will be removed once the startup part works without PLaunchApp margv[++margc] = "--add-exports=cpw.mods.bootstraplauncher/cpw.mods.bootstraplauncher=ALL-UNNAMED"; } + // Add Caciocavallo bootclasspath + NSString *cacio_classpath = [NSString stringWithFormat:@"-Xbootclasspath/%s", isJava8 ? "p" : "a"]; + NSString *cacio_libs_path = [NSString stringWithFormat:@"%s/libs_caciocavallo%s", getenv("BUNDLE_PATH"), isJava8 ? "" : "17"]; + NSArray *files = [fm contentsOfDirectoryAtPath:cacio_libs_path error:nil]; + for(NSString *file in files) { + if ([file hasSuffix:@".jar"]) { + cacio_classpath = [NSString stringWithFormat:@"%@:%@/%@", cacio_classpath, cacio_libs_path, file]; + } + } + margv[++margc] = (char *)cacio_classpath.UTF8String; + +/* + char cacio_libs_path[2048]; + char cacio_classpath[8192]; + sprintf((char*) cacio_libs_path, "%s/libs_caciocavallo", getenv("BUNDLE_PATH")); + cplen = sprintf(cacio_classpath, "-Xbootclasspath/p"); + d = opendir(cacio_libs_path); + int skip = 2; + if (d) { + while ((dir = readdir(d)) != NULL) { + if (skip > 0) { + --skip; + continue; + } + cplen += sprintf(cacio_classpath + cplen, ":%s/%s", cacio_libs_path, dir->d_name); + } + closedir(d); + } + margv[++margc] = cacio_classpath; +*/ + if (!getEntitlementValue(@"com.apple.developer.kernel.extended-virtual-addressing")) { // In jailed environment, where extended virtual addressing entitlement isn't // present (for free dev account), the maximum metaspace size is 896M. @@ -301,7 +312,7 @@ int launchJVM(NSString *username, id launchTarget, int width, int height, int mi regLog("[Init] Found JLI lib"); margv[++margc] = "-cp"; - margv[++margc] = classpath; + margv[++margc] = (char *)[NSString stringWithFormat:@"%s/*", java_libs_path].UTF8String; margv[++margc] = "net.kdt.pojavlaunch.PojavLauncher"; if (username == nil) { diff --git a/Natives/LauncherViewController.m b/Natives/LauncherViewController.m index 4338db19..a7eaae2a 100644 --- a/Natives/LauncherViewController.m +++ b/Natives/LauncherViewController.m @@ -253,24 +253,11 @@ int versionSelectedAt = 0; } - (void)enterModInstaller:(UIBarButtonItem*)sender { - NSString *javaVer = getPreference(@"java_home"); - NSFileManager *fileManager = [NSFileManager defaultManager]; - if(![fileManager fileExistsAtPath:JRE8_HOME_JB] && getenv("POJAV_DETECTEDJB")) { - UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Cannot use the mod installer" message:@"In order to use the mod installer, you need to install Java 8." preferredStyle:UIAlertControllerStyleActionSheet]; - if (alert.popoverPresentationController != nil) { - alert.popoverPresentationController.sourceView = self.view; - alert.popoverPresentationController.sourceRect = CGRectMake(self.view.frame.size.width-10.0, 0, 10, 10); - } - UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil]; - [self presentViewController:alert animated:YES completion:nil]; - [alert addAction:ok]; - } else { - UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"com.sun.java-archive"] - inMode:UIDocumentPickerModeImport]; - documentPicker.delegate = self; - documentPicker.modalPresentationStyle = UIModalPresentationFormSheet; - [self presentViewController:documentPicker animated:YES completion:nil]; - } + UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithDocumentTypes:@[@"com.sun.java-archive"] + inMode:UIDocumentPickerModeImport]; + documentPicker.delegate = self; + documentPicker.modalPresentationStyle = UIModalPresentationFormSheet; + [self presentViewController:documentPicker animated:YES completion:nil]; } - (void)documentPicker:(UIDocumentPickerViewController *)controller didPickDocumentAtURL:(NSURL *)url { diff --git a/Natives/LoginViewController.m b/Natives/LoginViewController.m index 445b7a59..c88cf80b 100644 --- a/Natives/LoginViewController.m +++ b/Natives/LoginViewController.m @@ -1,6 +1,7 @@ #include #include +#import "AFNetworking.h" #import #import "authenticator/BaseAuthenticator.h" @@ -188,6 +189,14 @@ technoNote.textAlignment = NSTextAlignmentCenter; [scrollView addSubview:technoNote]; } + + if (!getEntitlementValue(@"dynamic-codesigning")) { + if (isJITEnabled()) { + self.title = NSLocalizedString(@"login.jit.enabled", nil); + } else { + [self enableJITWithJitStreamer]; + } + } } - (void)displayProgress:(NSString *)title { @@ -375,6 +384,51 @@ [self presentViewController:vc animated:YES completion:nil]; } +- (void)enableJITWithJitStreamer +{ + [self displayProgress:NSLocalizedString(@"login.jit.checking", nil)]; + + // TODO: customizable address + NSString *address = @"69.69.0.1"; + + AFHTTPSessionManager *manager = AFHTTPSessionManager.manager; + manager.requestSerializer.timeoutInterval = 10; + manager.responseSerializer = AFHTTPResponseSerializer.serializer; + manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain", nil]; + [manager GET:[NSString stringWithFormat:@"http://%@/version", address] parameters:nil headers:nil progress:nil success:^(NSURLSessionDataTask *task, NSData *response) { + NSString *version = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding]; + NSLog(@"Found JitStreamer %@", version); + self.title = NSLocalizedString(@"login.jit.found.JitStreamer", nil); + manager.requestSerializer.timeoutInterval = 0; + manager.responseSerializer = AFJSONResponseSerializer.serializer; + void(^handleResponse)(NSURLSessionDataTask *task, id response) = ^void(NSURLSessionDataTask *task, id response){ + self.navigationItem.leftBarButtonItem = nil; + NSDictionary *responseDict; + // FIXME: successful response may fail due to serialization issues + if ([response isKindOfClass:NSError.class]) { + NSLog(@"Error?: %@", responseDict); + NSData *errorData = ((NSError *)response).userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; + responseDict = [NSJSONSerialization JSONObjectWithData:errorData options:0 error:nil]; + } else { + responseDict = response; + } + if ([responseDict[@"success"] boolValue]) { + self.title = NSLocalizedString(@"login.jit.enabled", nil); + } else { + self.title = [NSString stringWithFormat:NSLocalizedString(@"login.jit.fail.JitStreamer", nil), responseDict[@"message"]]; + showDialog(self, NSLocalizedString(@"Error", nil), responseDict[@"message"]); + // TODO: [self enableJITWithAltJIT]; + } + }; + [manager POST:[NSString stringWithFormat:@"http://%@/attach/%d/", address, getpid()] parameters:nil headers:nil progress:nil success:handleResponse failure:handleResponse]; + } failure:^(NSURLSessionDataTask *task, NSError *error) { + self.title = @""; + self.navigationItem.leftBarButtonItem = nil; + //showDialog(self, @"Error", [NSString stringWithFormat:@"%@", error]); + // TODO: [self enableJITWithAltJIT]; + }]; +} + - (void)aboutLauncher { AboutLauncherViewController *vc = [[AboutLauncherViewController alloc] init]; diff --git a/Natives/SurfaceViewController.m b/Natives/SurfaceViewController.m index bb5d1477..71752e1e 100644 --- a/Natives/SurfaceViewController.m +++ b/Natives/SurfaceViewController.m @@ -7,8 +7,10 @@ #import "customcontrols/ControlSubButton.h" #import "customcontrols/CustomControlsUtils.h" +#import "input/ControllerInput.h" +#import "input/KeyboardInput.h" + #import "JavaLauncher.h" -#import "KeyboardInput.h" #import "LauncherPreferences.h" #import "MinecraftResourceUtils.h" #import "SurfaceViewController.h" @@ -189,6 +191,7 @@ BOOL slideableHotbar; @property UIView *logOutputView; @property id mouseConnectCallback, mouseDisconnectCallback; +@property id controllerConnectCallback, controllerDisconnectCallback; @property CGRect clickRange; @property BOOL shouldTriggerClick; @@ -397,6 +400,22 @@ self.view.frame.size.width * 0.3 - 36.0 * 0.7, self.view.frame.size.height)]; } } + // TODO: deal with multiple controllers by letting users decide which one to use? + self.controllerConnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidConnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Controller connected!"); + GCController* controller = note.object; + [ControllerInput initKeycodeTable]; + [ControllerInput registerControllerCallbacks:controller]; + }]; + self.controllerDisconnectCallback = [[NSNotificationCenter defaultCenter] addObserverForName:GCControllerDidDisconnectNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { + NSLog(@"Input: Controller disconnected!"); + GCController* controller = note.object; + [ControllerInput unregisterControllerCallbacks:controller]; + }]; + if (GCController.controllers.count == 1) { + [ControllerInput registerControllerCallbacks:GCController.controllers.firstObject]; + } + [self.rootView addSubview:self.inputView]; /* diff --git a/Natives/awt_xawt/xawt_fake.m b/Natives/awt_xawt/xawt_fake.m index dfa29694..794112fc 100644 --- a/Natives/awt_xawt/xawt_fake.m +++ b/Natives/awt_xawt/xawt_fake.m @@ -1,8 +1,13 @@ #include "../jni.h" -jfieldID colorValueID; +//jfieldID colorValueID; // java.awt.* +JNIEXPORT void JNICALL +Java_java_awt_AWTEvent_initIDs(JNIEnv *env, jclass cls) +{ +} + JNIEXPORT void JNICALL Java_java_awt_Button_initIDs (JNIEnv *env, jclass cls) @@ -13,7 +18,7 @@ JNIEXPORT void JNICALL Java_java_awt_Color_initIDs (JNIEnv *env, jclass clazz) { - colorValueID = (*env)->GetFieldID(env, clazz, "value", "I"); + //colorValueID = (*env)->GetFieldID(env, clazz, "value", "I"); } JNIEXPORT void JNICALL @@ -97,6 +102,11 @@ Java_java_awt_Frame_initIDs { } +JNIEXPORT void JNICALL +Java_java_awt_Insets_initIDs(JNIEnv *env, jclass cls) +{ +} + JNIEXPORT void JNICALL Java_java_awt_KeyboardFocusManager_initIDs (JNIEnv *env, jclass cls) @@ -191,6 +201,16 @@ Java_java_awt_AWTEvent_nativeSetSource(JNIEnv *env, jobject self, jobject newSou // Maybe implement this? } +JNIEXPORT void JNICALL +Java_java_awt_event_InputEvent_initIDs(JNIEnv *env, jclass cls) +{ +} + +JNIEXPORT void JNICALL +Java_java_awt_event_KeyEvent_initIDs(JNIEnv *env, jclass cls) +{ +} + JNIEXPORT void JNICALL Java_java_awt_event_MouseEvent_initIDs (JNIEnv *env, jclass clazz) diff --git a/Natives/en.lproj/Localizable.strings b/Natives/en.lproj/Localizable.strings index 6bc7e7cc..b42bb591 100644 --- a/Natives/en.lproj/Localizable.strings +++ b/Natives/en.lproj/Localizable.strings @@ -21,6 +21,11 @@ "login.alert.title" = "Login"; "login.alert.field.username" = "Username"; +"login.jit.checking" = "Checking for JIT"; +"login.jit.enabled" = "JIT has been enabled"; +"login.jit.fail.JitStreamer" = "JitStreamer error: %@"; +"login.jit.found.JitStreamer" = "Found JitStreamer, enabling JIT"; + "login.menu.about" = "About PojavLauncher"; "login.menu.sendlogs" = "Send your logs"; "login.menu.updates" = "Recent updates"; diff --git a/Natives/input/ControllerInput.h b/Natives/input/ControllerInput.h new file mode 100644 index 00000000..14de3bc7 --- /dev/null +++ b/Natives/input/ControllerInput.h @@ -0,0 +1,10 @@ +#import +#import + +@interface ControllerInput : NSObject + ++ (void)initKeycodeTable; ++ (void)registerControllerCallbacks:(GCController *)controller; ++ (void)unregisterControllerCallbacks:(GCController *)controller; + +@end diff --git a/Natives/input/ControllerInput.m b/Natives/input/ControllerInput.m new file mode 100644 index 00000000..b4728bb4 --- /dev/null +++ b/Natives/input/ControllerInput.m @@ -0,0 +1,238 @@ +#import "ControllerInput.h" +#import "../SurfaceViewController.h" +#import "../utils.h" + +#include "../glfw_keycodes.h" + +@implementation ControllerInput + +NSMutableDictionary *gameMap, *menuMap; +BOOL leftShiftHeld; + ++ (void)initKeycodeTable { + if (gameMap && menuMap) { + return; + } + + gameMap = [[NSMutableDictionary alloc] init]; + + gameMap[@(GLFW_KEY_W)] = @(GLFW_KEY_W); + gameMap[@(GLFW_KEY_A)] = @(GLFW_KEY_A); + gameMap[@(GLFW_KEY_S)] = @(GLFW_KEY_S); + gameMap[@(GLFW_KEY_D)] = @(GLFW_KEY_D); + gameMap[@(SPECIALBTN_MOUSEPRI)] = @(SPECIALBTN_MOUSEPRI); + gameMap[@(SPECIALBTN_MOUSEMID)] = @(SPECIALBTN_MOUSEMID); + gameMap[@(SPECIALBTN_MOUSESEC)] = @(SPECIALBTN_MOUSESEC); + + gameMap[@(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)] = @(SPECIALBTN_SCROLLUP); + gameMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)] = @(SPECIALBTN_SCROLLDOWN); + + gameMap[@(GLFW_GAMEPAD_AXIS_LEFT_TRIGGER)] = @(SPECIALBTN_MOUSESEC); + gameMap[@(GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER)] = @(SPECIALBTN_MOUSEPRI); + + menuMap[@(GLFW_GAMEPAD_BUTTON_BACK)] = @(GLFW_KEY_TAB); + menuMap[@(GLFW_GAMEPAD_BUTTON_START)] = @(GLFW_KEY_ESCAPE); + //gameMap[@(GLFW_GAMEPAD_BUTTON_GUIDE)] = @(GLFW_KEY_UNKNOWN); + + gameMap[@(GLFW_GAMEPAD_BUTTON_A)] = @(GLFW_KEY_SPACE); + gameMap[@(GLFW_GAMEPAD_BUTTON_B)] = @(GLFW_KEY_Q); + gameMap[@(GLFW_GAMEPAD_BUTTON_X)] = @(GLFW_KEY_E); + gameMap[@(GLFW_GAMEPAD_BUTTON_Y)] = @(GLFW_KEY_F); + + gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_UP)] = @(GLFW_KEY_LEFT_SHIFT); + gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)] = @(GLFW_KEY_O); + gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)] = @(GLFW_KEY_J); + gameMap[@(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)] = @(GLFW_KEY_K); + + gameMap[@(GLFW_GAMEPAD_BUTTON_LEFT_THUMB)] = @(GLFW_KEY_LEFT_CONTROL); + gameMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_THUMB)] = @(-GLFW_KEY_LEFT_SHIFT); + + menuMap = [[NSMutableDictionary alloc] init]; + + menuMap[@(SPECIALBTN_MOUSEPRI)] = @(SPECIALBTN_MOUSEPRI); + menuMap[@(SPECIALBTN_MOUSEMID)] = @(SPECIALBTN_MOUSEMID); + menuMap[@(SPECIALBTN_MOUSESEC)] = @(SPECIALBTN_MOUSESEC); + + menuMap[@(GLFW_GAMEPAD_BUTTON_LEFT_BUMPER)] = @(SPECIALBTN_SCROLLUP); + menuMap[@(GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER)] = @(SPECIALBTN_SCROLLDOWN); + + menuMap[@(GLFW_GAMEPAD_BUTTON_A)] = @(SPECIALBTN_MOUSEPRI); + menuMap[@(GLFW_GAMEPAD_BUTTON_B)] = @(GLFW_KEY_ESCAPE); + menuMap[@(GLFW_GAMEPAD_BUTTON_X)] = @(SPECIALBTN_MOUSESEC); + menuMap[@(GLFW_GAMEPAD_BUTTON_Y)] = @(GLFW_KEY_LEFT_SHIFT); + + menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_DOWN)] = @(GLFW_KEY_O); + menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_LEFT)] = @(GLFW_KEY_J); + menuMap[@(GLFW_GAMEPAD_BUTTON_DPAD_RIGHT)] = @(GLFW_KEY_K); +} + ++ (void)sendKeyEvent:(int)controllerKeycode pressed:(BOOL)pressed { + int keycode; + if (isGrabbing) { + keycode = [gameMap[@(controllerKeycode)] intValue]; + } else { + keycode = [menuMap[@(controllerKeycode)] intValue]; + } + + switch (keycode) { + case GLFW_KEY_UNKNOWN: + // Do nothing + break; + case -GLFW_KEY_LEFT_SHIFT: + if (!pressed) { + leftShiftHeld = !leftShiftHeld; + CallbackBridge_nativeSendKey(GLFW_KEY_LEFT_SHIFT, 0, leftShiftHeld, 0); + } + break; + case SPECIALBTN_MOUSEPRI: + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_LEFT, pressed, leftShiftHeld ? GLFW_MOD_SHIFT : 0); + break; + case SPECIALBTN_MOUSEMID: + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_MIDDLE, pressed, leftShiftHeld ? GLFW_MOD_SHIFT : 0); + break; + case SPECIALBTN_MOUSESEC: + CallbackBridge_nativeSendMouseButton(GLFW_MOUSE_BUTTON_RIGHT, pressed, leftShiftHeld ? GLFW_MOD_SHIFT : 0); + break; + case SPECIALBTN_SCROLLUP: + CallbackBridge_nativeSendScroll(0, -1); + break; + case SPECIALBTN_SCROLLDOWN: + CallbackBridge_nativeSendScroll(0, 1); + break; + case GLFW_KEY_LEFT_SHIFT: + leftShiftHeld = pressed; + default: + CallbackBridge_nativeSendKey(keycode, 0, pressed, leftShiftHeld ? GLFW_MOD_SHIFT : 0); + break; + } +} + ++ (void)registerControllerCallbacks:(GCController *)controller { + GCExtendedGamepad *gamepad = controller.extendedGamepad; + + gamepad.leftShoulder.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_LEFT_BUMPER pressed:pressed]; + }; + gamepad.rightShoulder.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER pressed:pressed]; + }; + + gamepad.leftTrigger.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:SPECIALBTN_MOUSESEC pressed:pressed]; + }; + gamepad.rightTrigger.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:SPECIALBTN_MOUSEPRI pressed:pressed]; + }; + + if (@available(iOS 13.0, *)) { + gamepad.buttonOptions.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_BACK pressed:pressed]; + }; + gamepad.buttonMenu.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_START pressed:pressed]; + }; + } + if (@available(iOS 14.0, *)) { + gamepad.buttonHome.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_GUIDE pressed:pressed]; + }; + } + + gamepad.buttonA.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_A pressed:pressed]; + }; + gamepad.buttonB.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_B pressed:pressed]; + }; + gamepad.buttonX.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_X pressed:pressed]; + }; + gamepad.buttonY.pressedChangedHandler = ^(GCControllerButtonInput *button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_Y pressed:pressed]; + }; + + gamepad.dpad.up.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_UP pressed:pressed]; + }; + gamepad.dpad.down.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_DOWN pressed:pressed]; + }; + gamepad.dpad.left.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_LEFT pressed:pressed]; + }; + gamepad.dpad.right.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_DPAD_RIGHT pressed:pressed]; + }; + + gamepad.leftThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) { + if (isGrabbing) { + return; + } + + UIImageView *pointerView = [(id)currentVC() mousePointerView]; + virtualMouseFrame.origin.x += xValue; + virtualMouseFrame.origin.y += yValue; + pointerView.frame = virtualMouseFrame; + }; + gamepad.rightThumbstick.valueChangedHandler = ^(GCControllerDirectionPad * _Nonnull dpad, float xValue, float yValue) { + if (!isGrabbing) { + return; + } + + dpad.up.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_KEY_W pressed:pressed]; + }; + dpad.left.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_KEY_A pressed:pressed]; + }; + dpad.down.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_KEY_S pressed:pressed]; + }; + dpad.right.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_KEY_D pressed:pressed]; + }; + }; + if (@available(iOS 12.1, *)) { + gamepad.leftThumbstickButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_LEFT_THUMB pressed:pressed]; + }; + gamepad.rightThumbstickButton.pressedChangedHandler = ^(GCControllerButtonInput * _Nonnull button, float value, BOOL pressed) { + [self sendKeyEvent:GLFW_GAMEPAD_BUTTON_RIGHT_THUMB pressed:pressed]; + }; + } +} + ++ (void)unregisterControllerCallbacks:(GCController *)controller { + GCExtendedGamepad *gamepad = controller.extendedGamepad; + gamepad.leftShoulder.pressedChangedHandler = nil; + gamepad.rightShoulder.pressedChangedHandler = nil; + gamepad.leftTrigger.pressedChangedHandler = nil; + gamepad.rightTrigger.pressedChangedHandler = nil; + if (@available(iOS 13.0, *)) { + gamepad.buttonOptions.pressedChangedHandler = nil; + gamepad.buttonMenu.pressedChangedHandler = nil; + } + if (@available(iOS 14.0, *)) { + gamepad.buttonHome.pressedChangedHandler = nil; + } + gamepad.buttonA.pressedChangedHandler = nil; + gamepad.buttonB.pressedChangedHandler = nil; + gamepad.buttonX.pressedChangedHandler = nil; + gamepad.buttonY.pressedChangedHandler = nil; + gamepad.dpad.up.pressedChangedHandler = nil; + gamepad.dpad.down.pressedChangedHandler = nil; + gamepad.dpad.left.pressedChangedHandler = nil; + gamepad.dpad.right.pressedChangedHandler = nil; + gamepad.leftThumbstick.valueChangedHandler = nil; + gamepad.rightThumbstick.up.pressedChangedHandler = nil; + gamepad.rightThumbstick.down.pressedChangedHandler = nil; + gamepad.rightThumbstick.left.pressedChangedHandler = nil; + gamepad.rightThumbstick.right.pressedChangedHandler = nil; + gamepad.rightThumbstick.valueChangedHandler = nil; + if (@available(iOS 12.1, *)) { + gamepad.leftThumbstickButton.pressedChangedHandler = nil; + gamepad.rightThumbstickButton.pressedChangedHandler = nil; + } +} + +@end diff --git a/Natives/KeyboardInput.h b/Natives/input/KeyboardInput.h similarity index 82% rename from Natives/KeyboardInput.h rename to Natives/input/KeyboardInput.h index 3b3a8709..6810fc79 100644 --- a/Natives/KeyboardInput.h +++ b/Natives/input/KeyboardInput.h @@ -1,7 +1,5 @@ #import -NSMutableDictionary* keycodeTable; - @interface KeyboardInput : NSObject + (void)initKeycodeTable; diff --git a/Natives/KeyboardInput.m b/Natives/input/KeyboardInput.m similarity index 98% rename from Natives/KeyboardInput.m rename to Natives/input/KeyboardInput.m index 064da3f1..a366ed2c 100644 --- a/Natives/KeyboardInput.m +++ b/Natives/input/KeyboardInput.m @@ -1,10 +1,12 @@ #import "KeyboardInput.h" -#import "utils.h" +#import "../utils.h" -#include "glfw_keycodes.h" +#include "../glfw_keycodes.h" @implementation KeyboardInput +NSMutableDictionary* keycodeTable; + + (void)initKeycodeTable { if (@available(iOS 13.4, *)) { keycodeTable = [[NSMutableDictionary alloc] init]; diff --git a/Natives/ios_uikit_bridge.m b/Natives/ios_uikit_bridge.m index bc594c5c..0975e9ed 100644 --- a/Natives/ios_uikit_bridge.m +++ b/Natives/ios_uikit_bridge.m @@ -35,7 +35,7 @@ void internal_showDialog(UIViewController *viewController, NSString* title, NSSt void showDialog(UIViewController *viewController, NSString* title, NSString* message) { dispatch_async(dispatch_get_main_queue(), ^{ - internal_showDialog(currentVC(), title, message); + internal_showDialog(viewController ? viewController : currentVC(), title, message); }); } diff --git a/Natives/main.m b/Natives/main.m index ece20178..bb3e2b2b 100644 --- a/Natives/main.m +++ b/Natives/main.m @@ -208,6 +208,16 @@ void init_setupMultiDir() { [fm changeCurrentDirectoryPath:lasmPath]; } +void init_setupResolvConf() { + // Write known DNS servers to the config + NSString *path = [NSString stringWithFormat:@"%s/resolv.conf", getenv("POJAV_HOME")]; + if (![fm fileExistsAtPath:path]) { + [@"nameserver 8.8.8.8\n" + @"nameserver 8.8.4.4" + writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil]; + } +} + int main(int argc, char * argv[]) { if (pJLI_Launch) { return pJLI_Launch(argc, argv, @@ -233,8 +243,6 @@ int main(int argc, char * argv[]) { setenv("POJAV_HOME", "/usr/share/pojavlauncher", 1); } else { setenv("POJAV_HOME", [NSString stringWithFormat:@"%s/Documents", getenv("HOME")].UTF8String, 1); - - //init_hookFunctions(); } [fm createDirectoryAtPath:@(getenv("POJAV_HOME")) withIntermediateDirectories:NO attributes:nil error:nil]; @@ -242,7 +250,10 @@ int main(int argc, char * argv[]) { init_redirectStdio(); init_logDeviceAndVer(argv[0]); + init_hookFunctions(); + loadPreferences(); + init_setupResolvConf(); init_setupMultiDir(); init_setupLauncherProfiles(); init_setupAccounts(); diff --git a/Natives/main_hook.m b/Natives/main_hook.m index 968a9446..9b1c103d 100644 --- a/Natives/main_hook.m +++ b/Natives/main_hook.m @@ -1,103 +1,35 @@ -#include -#include -#include -#include -#include +#import #include "external/fishhook/fishhook.h" -#import "utils.h" -int main(int argc, char * argv[]); - -static CFRunLoopRunResult (*orig_CFRunLoopRunInMode)(CFRunLoopMode mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled); - -static int (*orig_dladdr)(const void* addr, Dl_info* info); static void* (*orig_dlopen)(const char* path, int mode); -//static void* (*orig_mmap)(void *addr, size_t len, int prot, int flags, int fd, off_t offset); -static char* (*orig_realpath)(const char *restrict path, char *restrict resolved_path); -pid_t (*orig_waitpid)(pid_t pid, int *status, int options); -//static void (*orig_sys_icache_invalidate)(void *start, size_t len); - - -int hooked_dladdr(const void* addr, Dl_info* info) { - //NSLog(@"hook dladdr(%p, %p)", addr, info); - int retVal = orig_dladdr(addr, info); - if (addr == main) { - //NSLog(@"hooked dladdr"); - info->dli_fname = getenv("JAVA_EXT_EXECNAME"); - } else if (retVal != 0) { - //NSLog(@"hooked dladdr"); - char *libname = basename((char *)info->dli_fname); - char src[2048], dst[2048]; - sprintf((char *)src, "%s/Frameworks", getenv("BUNDLE_PATH")); - if (0 == strncmp(info->dli_fname, src, strlen(src))) { - if (0 == strncmp(libname, "libjli.dylib", 12)) { - info->dli_fname = getenv("INTERNAL_JLI_PATH"); - } else if (0 == strncmp(libname, "libjvm.dylib", 12)) { - sprintf((char *)dst, "%s/lib/server/libjvm.dylib", getenv("JAVA_HOME")); - info->dli_fname = (char *)dst; - } - } - } - //if (retVal) NSLog(@"dli_fname=%s", info->dli_fname); - return retVal; -} +static int (*orig_open)(const char *path, int oflag, ...); void* hooked_dlopen(const char* path, int mode) { - //NSLog(@"dlopen(%s, %d)", path, mode); - - // Avoid loading the executable itself twice - if (path && [@(path) hasSuffix:@"PojavLauncher"]) { - return orig_dlopen(NULL, mode); + if (path && [@(path) hasSuffix:@"/libawt_xawt.dylib"]) { + return orig_dlopen([NSString stringWithFormat:@"%s/Frameworks/libawt_xawt.dylib", getenv("BUNDLE_PATH")].UTF8String, mode); } return orig_dlopen(path, mode); - } -/* -void *hooked_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset) { - NSLog(@"mmap(%p, %ld, %d, %d, %d, %lld)", addr, len, prot, flags, fd, offset); - - if (flags & MAP_JIT) { - NSLog(@"'-> Found JIT mmap"); - //flags &= ~MAP_JIT; +int hooked_open(const char *path, int oflag, ...) { + va_list args; + va_start(args, oflag); + mode_t mode = va_arg(args, int); + va_end(args); + if (path && !strcmp(path, "/etc/resolv.conf")) { + return orig_open([NSString stringWithFormat:@"%s/resolv.conf", getenv("POJAV_HOME")].UTF8String, oflag, mode); } - // raise(SIGINT); - return orig_mmap(addr, len, prot, flags, fd, offset); + return orig_open(path, oflag, mode); } -*/ - -char *hooked_realpath(const char *restrict path, char *restrict resolved_path) { - //NSLog(@"hook realpath %s", path); - const char *javaHome = getenv("JAVA_HOME"); - if (0 == strncmp(path, javaHome, strlen(javaHome))) { - strcpy(resolved_path, path); - return resolved_path; - } else { - return orig_realpath(path, resolved_path); - } -} - -/* -void hooked_sys_icache_invalidate(void *start, size_t len) { - // mprotect(start, 16384, PROT_EXEC | PROT_READ); - // NSLog(@"mprotect errno %d", errno); - orig_sys_icache_invalidate(start, len); -} -*/ void init_hookFunctions() { - // if (!started && strncmp(argv[0], "/Applications", 13)) - // Jailed only: hook some functions for symlinked JRE home dir - int retval = rebind_symbols((struct rebinding[3]){ - {"dladdr", hooked_dladdr, (void *)&orig_dladdr}, - {"dlopen", hooked_dlopen, (void *)&orig_dlopen}, - //{"realpath", hooked_realpath, (void *)&orig_realpath}, - {"realpath$DARWIN_EXTSN", hooked_realpath, (void *)&orig_realpath} - //{"mmap", hooked_mmap, (void *)&orig_mmap}, - //{"sys_icache_invalidate", hooked_sys_icache_invalidate, (void *)&orig_sys_icache_invalidate} - }, 3); - NSLog(@"hook retval = %d", retval); + if (getenv("POJAV_DETECTEDJB")) { + // In this environment, libawt_xawt is not available/X11 only. + // hook dlopen to use our libawt_xawt + rebind_symbols((struct rebinding[1]){{"dlopen", hooked_dlopen, (void *)&orig_dlopen}}, 1); + } + rebind_symbols((struct rebinding[1]){{"open", hooked_open, (void *)&orig_open}}, 1); } diff --git a/Natives/resources/Frameworks/libMoltenVK.dylib.framework/libMoltenVK.dylib b/Natives/resources/Frameworks/libMoltenVK.dylib.framework/libMoltenVK.dylib index d8b0e067..02c4b244 100755 Binary files a/Natives/resources/Frameworks/libMoltenVK.dylib.framework/libMoltenVK.dylib and b/Natives/resources/Frameworks/libMoltenVK.dylib.framework/libMoltenVK.dylib differ diff --git a/Natives/utils.h b/Natives/utils.h index 08c6da1a..dd3e136a 100644 --- a/Natives/utils.h +++ b/Natives/utils.h @@ -45,6 +45,10 @@ JavaVM* runtimeJavaVMPtr; JNIEnv* runtimeJNIEnvPtr; //__weak UIViewController *viewController; +#define CS_DEBUGGED 0x10000000 +int csops(pid_t pid, unsigned int ops, void *useraddr, size_t usersize); +BOOL isJITEnabled(); + void* gbuffer; // OSMesa framebuffer long showingWindow; int savedWidth, savedHeight; diff --git a/Natives/utils.m b/Natives/utils.m index 2fdd9606..b83df79a 100644 --- a/Natives/utils.m +++ b/Natives/utils.m @@ -5,9 +5,9 @@ #include #include "log.h" - #include "utils.h" +BOOL getEntitlementValue(NSString *key); @implementation UIWindow(ext) @@ -21,6 +21,9 @@ - (UIViewController *)visibleViewController { UIViewController *current = self.rootViewController; while (current.presentedViewController) { + if ([current.presentedViewController isKindOfClass:UIAlertController.class] || [current.presentedViewController isKindOfClass:NSClassFromString(@"UIInputWindowController")]) { + break; + } current = current.presentedViewController; } if ([current isKindOfClass:UINavigationController.class]) { @@ -48,6 +51,15 @@ UIViewController* currentVC() { return [delegate window].visibleViewController; } +BOOL isJITEnabled() { + if (getEntitlementValue(@"dynamic-codesigning")) { + return YES; + } + + int flags; + csops(getpid(), 0, &flags, sizeof(flags)); + return (flags & CS_DEBUGGED) != 0; +} NSMutableDictionary* parseJSONFromFile(NSString *path) { NSError *error; diff --git a/README.md b/README.md index c71a98d8..97d29076 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,13 @@ The [PojavLauncher Website](https://pojav.ml) has extensive documentation on how ### Without jailbreak (sideload as IPA) Note: This is experimental, although game works smoothly, you should not set Render distance too much. -1. Install [AltStore](https://altstore.io) +1. Install [AltStore](https://altstore.io). Others will also work. 2. Download an IPA build of PojavLauncher in the Actions tab. -3. Open the downloaded IPA in AltStore to install. -4. Launch PojavLauncher with JIT enabled. +3. Open the downloaded IPA in the sideload app to install. +4. For enabling JIT, choose one of these: + - Setup [JitStreamer](http://jitstreamer.com), then launch PojavLauncher. JIT will be automatically enabled on startup. This is the most convenient way. + - Launch PojavLauncher with `Enable JIT` option in AltStore. This requires the device to be plugged in the computer or have Wi-Fi syncing enabled. + - Setup and use others such as [Jitterbug](https://github.com/osy/Jitterbug). ### Procursus-bootstraps *Note: This is currently unavailable. Will be fixed soon! For the meantime, you can follow the same way as [below](#bingnerelucubratus-bootstraps)*. @@ -59,6 +62,7 @@ PojavLauncher is amazing, and surprisingly stable, and it wouldn't be this way w @LegacyGamerHD - Lead developer @zhouwei - Original Boardwalk code @Mathius-Boulay - Developer +@jkcoxson - JitStreamer author @Diatrus - PojavLauncher hosting on Procursus @Syjalo @pedrosouzabrasil