Beta 1.0 Release

This commit is contained in:
downthecrop 2023-08-01 20:33:48 -07:00
parent 920bcb7137
commit d37941e2cf
62 changed files with 235 additions and 1320 deletions

View file

@ -50,7 +50,7 @@
</intent-filter>
</activity>
<activity
android:name=".DummyLauncher"
android:name=".ScapeLauncher"
android:screenOrientation="sensorLandscape"
android:label="@string/app_short_name" />
<activity
@ -66,7 +66,7 @@
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout|keyboard|navigation|uiMode"
android:screenOrientation="sensorLandscape" />
<activity
android:name=".CustomControlsActivity"
android:name=".customcontrols.CustomControlsActivity"
android:configChanges="keyboardHidden|orientation|screenSize|keyboard|navigation"
android:exported="false"
android:screenOrientation="sensorLandscape">

View file

@ -1 +1 @@
1690859739558
1690945073108

File diff suppressed because one or more lines are too long

View file

@ -7,6 +7,8 @@ import android.util.*;
import android.view.*;
import java.util.*;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.utils.*;
public class AWTCanvasView extends TextureView implements TextureView.SurfaceTextureListener, Runnable {

View file

@ -24,7 +24,7 @@ public class FatalErrorActivity extends AppCompatActivity {
.setTitle(R.string.error_fatal)
.setMessage(errHeader + "\n\n" + stackTrace)
.setPositiveButton(android.R.string.ok, (p1, p2) -> finish())
.setNegativeButton(R.string.global_restart, (p1, p2) -> startActivity(new Intent(FatalErrorActivity.this, DummyLauncher.class)))
.setNegativeButton(R.string.global_restart, (p1, p2) -> startActivity(new Intent(FatalErrorActivity.this, ScapeLauncher.class)))
.setNeutralButton(android.R.string.copy, (p1, p2) -> {
ClipboardManager mgr = (ClipboardManager) FatalErrorActivity.this.getSystemService(CLIPBOARD_SERVICE);
mgr.setPrimaryClip(ClipData.newPlainText("error", stackTrace));

View file

@ -1,6 +1,5 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.MainActivity.touchCharInput;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.PREF_DISABLE_SWAP_HAND;
import static net.kdt.pojavlaunch.utils.MCOptionUtils.getMcScale;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
@ -36,7 +35,9 @@ import androidx.annotation.RequiresApi;
import net.kdt.pojavlaunch.customcontrols.ControlLayout;
import net.kdt.pojavlaunch.customcontrols.gamepad.Gamepad;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import net.kdt.pojavlaunch.utils.MathUtils;
@ -48,7 +49,7 @@ import fr.spse.gamepad_remapper.RemapperView;
/**
* Class dealing with showing minecraft surface and taking inputs to dispatch them to minecraft
*/
public class MinecraftGLSurface extends View implements GrabListener {
public class GLFWGLSurface extends View implements GrabListener {
/* Gamepad object for gamepad inputs, instantiated on need */
private Gamepad mGamepad = null;
@ -141,11 +142,11 @@ public class MinecraftGLSurface extends View implements GrabListener {
public MinecraftGLSurface(Context context) {
public GLFWGLSurface(Context context) {
this(context, null);
}
public MinecraftGLSurface(Context context, AttributeSet attributeSet) {
public GLFWGLSurface(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
setFocusable(true);
@ -225,7 +226,7 @@ public class MinecraftGLSurface extends View implements GrabListener {
super.onLongPress(e);
if(!isDragClicking) {
isDragClicking = true;
AWTInputBridge.sendKey((char)AWTInputEvent.VK_F5, AWTInputEvent.VK_F5);
AWTInputBridge.sendKey((char) AWTInputEvent.VK_F5, AWTInputEvent.VK_F5);
}
}

View file

@ -1,10 +0,0 @@
package net.kdt.pojavlaunch;
import androidx.annotation.Keep;
@Keep
public class JAssetInfo
{
public String hash;
public int size;
}

View file

@ -1,14 +0,0 @@
package net.kdt.pojavlaunch;
import androidx.annotation.Keep;
import com.google.gson.annotations.SerializedName;
import java.util.Map;
@Keep
public class JAssets {
@SerializedName("map_to_resources") public boolean mapToResources;
public Map<String, JAssetInfo> objects;
}

View file

@ -1,84 +0,0 @@
package net.kdt.pojavlaunch;
import androidx.annotation.Keep;
import java.util.*;
@Keep
@SuppressWarnings("unused") // all unused fields here are parts of JSON structures
public class JMinecraftVersionList {
public Map<String, String> latest;
public Version[] versions;
@Keep
public static class FileProperties {
public String id, sha1, url;
public long size;
}
@Keep
public static class Version extends FileProperties {
// Since 1.13, so it's one of ways to check
public Arguments arguments;
public AssetIndex assetIndex;
public String assets;
public String inheritsFrom;
public JavaVersionInfo javaVersion;
public LoggingConfig logging;
public String mainClass;
public String minecraftArguments;
public int minimumLauncherVersion;
public String releaseTime;
public String time;
public String type;
}
@Keep
public static class JavaVersionInfo {
public String component;
public int majorVersion;
}
@Keep
public static class LoggingConfig {
public LoggingClientConfig client;
@Keep
public static class LoggingClientConfig {
public String argument;
public FileProperties file;
public String type;
}
}
// Since 1.13
@Keep
public static class Arguments {
public Object[] game;
public Object[] jvm;
@Keep
public static class ArgValue {
public ArgRules[] rules;
public String value;
// TLauncher styled argument...
public String[] values;
@Keep
public static class ArgRules {
public String action;
public String features;
public ArgOS os;
@Keep
public static class ArgOS {
public String name;
public String version;
}
}
}
}
@Keep
public static class AssetIndex extends FileProperties {
public long totalSize;
}
}

View file

@ -1,56 +0,0 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.Architecture.archAsString;
import android.app.Activity;
import android.content.res.AssetManager;
import android.util.Log;
import net.kdt.pojavlaunch.multirt.MultiRTUtils;
import net.kdt.pojavlaunch.multirt.Runtime;
import java.io.IOException;
public class JRE17Util {
public static final String NEW_JRE_NAME = "Internal-17";
public static boolean checkInternalNewJre(AssetManager assetManager) {
String launcher_jre17_version;
String installed_jre17_version = MultiRTUtils.__internal__readBinpackVersion(NEW_JRE_NAME);
try {
launcher_jre17_version = Tools.read(assetManager.open("components/jre-new/version"));
}catch (IOException exc) {
//we don't have a runtime included!
return installed_jre17_version != null; //if we have one installed -> return true -> proceed (no updates but the current one should be functional)
//if we don't -> return false -> Cannot find compatible Java runtime
}
if(!launcher_jre17_version.equals(installed_jre17_version)) // this implicitly checks for null, so it will unpack the runtime even if we don't have one installed
return unpackJre17(assetManager, launcher_jre17_version);
else return true;
}
private static boolean unpackJre17(AssetManager assetManager, String rt_version) {
try {
MultiRTUtils.installRuntimeNamedBinpack(
assetManager.open("components/jre-new/universal.tar.xz"),
assetManager.open("components/jre-new/bin-" + archAsString(Tools.DEVICE_ARCHITECTURE) + ".tar.xz"),
"Internal-17", rt_version);
MultiRTUtils.postPrepare("Internal-17");
return true;
}catch (IOException e) {
Log.e("JRE17Auto", "Internal JRE unpack failed", e);
return false;
}
}
public static boolean isInternalNewJRE(String s_runtime) {
Runtime runtime = MultiRTUtils.read(s_runtime);
if(runtime == null) return false;
return NEW_JRE_NAME.equals(runtime.name);
}
private static void showRuntimeFail(Activity activity, JMinecraftVersionList.Version verInfo) {
Tools.dialogOnUiThread(activity, activity.getString(R.string.global_error),
activity.getString(R.string.multirt_nocompartiblert, verInfo.javaVersion.majorVersion));
}
}

View file

@ -4,7 +4,6 @@ import static net.kdt.pojavlaunch.MainActivity.fullyExit;
import android.annotation.SuppressLint;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
@ -13,7 +12,6 @@ import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
@ -35,13 +33,9 @@ import org.lwjgl.glfw.CallbackBridge;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class JavaGUILauncherActivity extends BaseActivity implements View.OnTouchListener {

View file

@ -38,6 +38,7 @@ import androidx.drawerlayout.widget.DrawerLayout;
import com.kdt.LoggerView;
import net.kdt.pojavlaunch.customcontrols.GyroControl;
import net.kdt.pojavlaunch.customcontrols.ControlButtonMenuListener;
import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
@ -47,6 +48,8 @@ import net.kdt.pojavlaunch.customcontrols.EditorExitable;
import net.kdt.pojavlaunch.customcontrols.keyboard.LwjglCharSender;
import net.kdt.pojavlaunch.customcontrols.keyboard.TouchCharInput;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.MCOptionUtils;
import org.lwjgl.glfw.CallbackBridge;
@ -61,7 +64,7 @@ public class MainActivity extends BaseActivity implements ControlButtonMenuListe
volatile public static boolean isInputStackCall;
public static TouchCharInput touchCharInput;
private MinecraftGLSurface minecraftGLView;
private GLFWGLSurface minecraftGLView;
private static Touchpad touchpad;
private LoggerView loggerView;
private DrawerLayout drawerLayout;

View file

@ -1,41 +1,20 @@
package net.kdt.pojavlaunch;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.kdt.mcgui.ProgressLayout;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
import net.kdt.pojavlaunch.prefs.screens.LauncherPreferenceFragment;
import net.kdt.pojavlaunch.progresskeeper.ProgressKeeper;
import net.kdt.pojavlaunch.services.ProgressServiceKeeper;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class ScapeLauncher extends BaseActivity {
public class DummyLauncher extends BaseActivity {
private FloatingActionButton fab;
private TextView settings;
private Button playHD;
private Button playSD;
private static final int FILE_SELECT_CODE_JSON = 0;
@ -47,7 +26,7 @@ public class DummyLauncher extends BaseActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dummy_launcher);
fab = findViewById(R.id.myFab);
settings = findViewById(R.id.settings);
playHD = findViewById(R.id.playHD);
playSD = findViewById(R.id.playSD);
mProgressLayout = findViewById(R.id.progress_layout);
@ -60,16 +39,16 @@ public class DummyLauncher extends BaseActivity {
playHD.setOnClickListener(view -> {
if(!runtimeReady()) return;
Intent intent = new Intent(DummyLauncher.this, MainActivity.class);
Intent intent = new Intent(ScapeLauncher.this, MainActivity.class);
startActivity(intent);
});
playSD.setOnClickListener(view -> {
if(!runtimeReady()) return;
Intent intent = new Intent(DummyLauncher.this, JavaGUILauncherActivity.class);
Intent intent = new Intent(ScapeLauncher.this, JavaGUILauncherActivity.class);
startActivity(intent);
});
fab.setOnClickListener(view -> showBottomDialog());
settings.setOnClickListener(view -> showBottomDialog());
}

View file

@ -64,7 +64,7 @@ public class TestStorageActivity extends Activity {
AsyncAssetManager.unpackComponents(this);
AsyncAssetManager.unpackSingleFiles(this);
Intent intent = new Intent(this, DummyLauncher.class);
Intent intent = new Intent(this, ScapeLauncher.class);
startActivity(intent);
finish();
}

View file

@ -20,13 +20,11 @@ import android.content.res.Configuration;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.DocumentsContract;
import android.provider.OpenableColumns;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
@ -36,11 +34,8 @@ import android.widget.EditText;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationManagerCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentTransaction;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@ -52,8 +47,6 @@ import net.kdt.pojavlaunch.multirt.Runtime;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.DownloadUtils;
import net.kdt.pojavlaunch.utils.JREUtils;
import net.kdt.pojavlaunch.utils.JSONUtils;
import net.kdt.pojavlaunch.utils.OldVersionsUtils;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.io.IOUtils;
@ -70,12 +63,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@ -475,37 +465,6 @@ public final class Tools {
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
act.startActivity(browserIntent);
}
private static boolean checkRules(JMinecraftVersionList.Arguments.ArgValue.ArgRules[] rules) {
if(rules == null) return true; // always allow
for (JMinecraftVersionList.Arguments.ArgValue.ArgRules rule : rules) {
if (rule.action.equals("allow") && rule.os != null && rule.os.name.equals("osx")) {
return false; //disallow
}
}
return true; // allow if none match
}
@SuppressWarnings({"unchecked", "rawtypes"})
// Prevent NullPointerException
private static void insertSafety(JMinecraftVersionList.Version targetVer, JMinecraftVersionList.Version fromVer, String... keyArr) {
for (String key : keyArr) {
Object value = null;
try {
Field fieldA = fromVer.getClass().getDeclaredField(key);
value = fieldA.get(fromVer);
if (((value instanceof String) && !((String) value).isEmpty()) || value != null) {
Field fieldB = targetVer.getClass().getDeclaredField(key);
fieldB.set(targetVer, value);
}
} catch (Throwable th) {
Log.w(Tools.APP_NAME, "Unable to insert " + key + "=" + value, th);
}
}
}
public static String read(InputStream is) throws IOException {
String readResult = IOUtils.toString(is, StandardCharsets.UTF_8);
is.close();

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch;
import static net.kdt.pojavlaunch.MinecraftGLSurface.FINGER_SCROLL_THRESHOLD;
import static net.kdt.pojavlaunch.GLFWGLSurface.FINGER_SCROLL_THRESHOLD;
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
import static net.kdt.pojavlaunch.prefs.LauncherPreferences.DEFAULT_PREF;
@ -20,6 +20,7 @@ import androidx.annotation.Nullable;
import androidx.core.content.res.ResourcesCompat;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import org.lwjgl.glfw.CallbackBridge;

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch.customcontrols;
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
import static net.kdt.pojavlaunch.utils.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
import android.util.ArrayMap;

View file

@ -21,7 +21,7 @@ import com.google.gson.JsonSyntaxException;
import com.kdt.pickafile.FileListView;
import com.kdt.pickafile.FileSelectedListener;
import net.kdt.pojavlaunch.MinecraftGLSurface;
import net.kdt.pojavlaunch.GLFWGLSurface;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.customcontrols.buttons.ControlButton;
@ -42,7 +42,7 @@ import java.util.List;
public class ControlLayout extends FrameLayout {
protected CustomControls mLayout;
/* Accessible when inside the game by ControlInterface implementations, cached for perf. */
private MinecraftGLSurface mGameSurface = null;
private GLFWGLSurface mGameSurface = null;
/* Cache to buttons for performance purposes */
private List<ControlInterface> mButtons;
@ -420,7 +420,7 @@ public class ControlLayout extends FrameLayout {
}
/** Cached getter for perf purposes */
public MinecraftGLSurface getGameSurface(){
public GLFWGLSurface getGameSurface(){
if(mGameSurface == null){
mGameSurface = findViewById(R.id.main_game_render_view);
}

View file

@ -6,6 +6,7 @@ import androidx.annotation.Keep;
import java.io.IOException;
import java.util.*;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
@Keep
public class CustomControls {

View file

@ -1,4 +1,4 @@
package net.kdt.pojavlaunch;
package net.kdt.pojavlaunch.customcontrols;
import android.content.Intent;
import android.net.Uri;
@ -10,6 +10,9 @@ import android.widget.ListView;
import androidx.drawerlayout.widget.DrawerLayout;
import net.kdt.pojavlaunch.BaseActivity;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.customcontrols.ControlData;
import net.kdt.pojavlaunch.customcontrols.ControlDrawerData;
import net.kdt.pojavlaunch.customcontrols.ControlLayout;

View file

@ -1,4 +1,4 @@
package net.kdt.pojavlaunch;
package net.kdt.pojavlaunch.customcontrols;
import android.app.Activity;
import android.content.Context;
@ -10,6 +10,7 @@ import android.view.OrientationEventListener;
import android.view.Surface;
import android.view.WindowManager;
import net.kdt.pojavlaunch.GrabListener;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import org.lwjgl.glfw.CallbackBridge;

View file

@ -2,7 +2,7 @@ package net.kdt.pojavlaunch.customcontrols;
import com.google.gson.JsonSyntaxException;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.Tools;
import org.json.JSONArray;

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch.customcontrols.buttons;
import static net.kdt.pojavlaunch.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
import static net.kdt.pojavlaunch.utils.LwjglGlfwKeycode.GLFW_KEY_UNKNOWN;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import static org.lwjgl.glfw.CallbackBridge.sendMouseButton;
@ -15,7 +15,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.MainActivity;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.customcontrols.ControlData;

View file

@ -19,13 +19,12 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.math.MathUtils;
import net.kdt.pojavlaunch.GrabListener;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;
import net.kdt.pojavlaunch.utils.MCOptionUtils;

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch.customcontrols.gamepad;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
public class GamepadMap {

View file

@ -29,7 +29,7 @@ import androidx.constraintlayout.widget.ConstraintLayout;
import com.kdt.DefocusableScrollView;
import net.kdt.pojavlaunch.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.utils.EfficientAndroidLWJGLKeycode;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.colorselector.ColorSelector;
import net.kdt.pojavlaunch.customcontrols.ControlData;

View file

@ -2,7 +2,7 @@ package net.kdt.pojavlaunch.customcontrols.keyboard;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import org.lwjgl.glfw.CallbackBridge;

View file

@ -15,8 +15,6 @@ import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.kdt.pojavlaunch.AWTInputBridge;
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.utils.KeyEncoder;

View file

@ -17,7 +17,7 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import net.kdt.pojavlaunch.Architecture;
import net.kdt.pojavlaunch.utils.Architecture;
import net.kdt.pojavlaunch.R;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.prefs.LauncherPreferences;

View file

@ -3,7 +3,7 @@ package net.kdt.pojavlaunch.prefs;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.P;
import static net.kdt.pojavlaunch.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.utils.Architecture.is32BitsDevice;
import android.app.Activity;
import android.content.*;

View file

@ -1,6 +1,6 @@
package net.kdt.pojavlaunch.prefs.screens;
import static net.kdt.pojavlaunch.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.utils.Architecture.is32BitsDevice;
import static net.kdt.pojavlaunch.Tools.getTotalDeviceMemory;
import android.os.Bundle;

View file

@ -1,7 +1,7 @@
package net.kdt.pojavlaunch.tasks;
import static net.kdt.pojavlaunch.Architecture.archAsString;
import static net.kdt.pojavlaunch.utils.Architecture.archAsString;
import static net.kdt.pojavlaunch.PojavApplication.sExecutorService;
import android.content.Context;
@ -68,7 +68,6 @@ public class AsyncAssetManager {
Tools.copyAssetFile(ctx, "options.txt", Tools.DIR_GAME_NEW, false);
Tools.copyAssetFile(ctx, "default.json", Tools.CTRLMAP_PATH, false);
Tools.copyAssetFile(ctx, "launcher_profiles.json", Tools.DIR_GAME_NEW, false);
Tools.copyAssetFile(ctx,"resolv.conf",Tools.DIR_DATA, false);
} catch (IOException e) {
Log.e("AsyncAssetManager", "Failed to unpack critical components !");
}
@ -86,13 +85,11 @@ public class AsyncAssetManager {
// we repack them to a single file here
unpackComponent(ctx, "lwjgl3", false);
unpackComponent(ctx, "security", true);
unpackComponent(ctx, "arc_dns_injector", true);
unpackComponent(ctx, "forge_installer", true);
Tools.copyAssetFile(ctx,"rt4.jar",Tools.DIR_DATA, true); // Change this to true for debugging
Tools.copyAssetFile(ctx,"rt4.jar",Tools.DIR_DATA, false); // Change this to true if you're working on client features.
Tools.copyAssetFile(ctx,"config.json",Tools.DIR_DATA, false);
// Unzip the plugins for use.
extractAllPlugins(ctx); // Can comment this out to keep the plugins saved, rewrites them ever time it launches...
extractAllPlugins(ctx);
} catch (IOException e) {
Log.e("AsyncAssetManager", "Failed o unpack components !",e );

View file

@ -1,4 +1,4 @@
package net.kdt.pojavlaunch;
package net.kdt.pojavlaunch.utils;
import android.os.Build;

View file

@ -1,4 +1,4 @@
package net.kdt.pojavlaunch;
package net.kdt.pojavlaunch.utils;
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;

View file

@ -1,7 +1,7 @@
package net.kdt.pojavlaunch.utils;
import static net.kdt.pojavlaunch.Architecture.ARCH_X86;
import static net.kdt.pojavlaunch.Architecture.is64BitsDevice;
import static net.kdt.pojavlaunch.utils.Architecture.ARCH_X86;
import static net.kdt.pojavlaunch.utils.Architecture.is64BitsDevice;
import static net.kdt.pojavlaunch.Tools.LOCAL_RENDERER;
import static net.kdt.pojavlaunch.Tools.NATIVE_LIB_DIR;
import static net.kdt.pojavlaunch.Tools.currentDisplayMetrics;
@ -308,10 +308,6 @@ public class JREUtils {
*/
public static List<String> getJavaArgs(Context ctx, String runtimeHome, String userArgumentsString) {
List<String> userArguments = parseJavaArguments(userArgumentsString);
String resolvFile;
resolvFile = new File(Tools.DIR_DATA,"resolv.conf").getAbsolutePath();
// TODO: MOVE THIS TO OUR NEW SETTINGS
LauncherPreferences.PREF_SCALE_FACTOR = 50;
ArrayList<String> overridableArguments = new ArrayList<>(Arrays.asList(
"-Djava.home=" + runtimeHome,
"-Djava.io.tmpdir=" + Tools.DIR_CACHE.getAbsolutePath(),
@ -319,27 +315,21 @@ public class JREUtils {
"-Duser.language=" + System.getProperty("user.language"),
"-Dos.name=Linux",
"-Dos.version=Android-" + Build.VERSION.RELEASE,
"-Dpojav.path.minecraft=" + Tools.DIR_GAME_NEW,
"-Dpojav.path.private.account=" + Tools.DIR_ACCOUNT_NEW,
"-Duser.timezone=" + TimeZone.getDefault().getID(),
//LWJGL 3 DEBUG FLAGS
"-Dorg.lwjgl.util.Debug=true",
"-Dorg.lwjgl.util.DebugFunctions=true",
"-Dorg.lwjgl.util.DebugLoader=true",
// GLFW Stub width height
"-Dglfwstub.windowWidth=" + Tools.getDisplayFriendlyRes(currentDisplayMetrics.widthPixels, LauncherPreferences.PREF_SCALE_FACTOR/100F),
"-Dglfwstub.windowHeight=" + Tools.getDisplayFriendlyRes(currentDisplayMetrics.heightPixels, LauncherPreferences.PREF_SCALE_FACTOR/100F),
"-Dglfwstub.initEgl=false",
"-Dext.net.resolvPath=" +resolvFile,
"-Dlog4j2.formatMsgNoLookups=true", //Log4j RCE mitigation
"-Dnet.minecraft.clientmodname=" + Tools.APP_NAME,
"-Dfml.earlyprogresswindow=false" //Forge 1.14+ workaround
//Log4j RCE mitigation
"-Dlog4j2.formatMsgNoLookups=true"
));
if(LauncherPreferences.PREF_ARC_CAPES) {
//overridableArguments.add("-javaagent:"+new File(Tools.DIR_DATA,"arc_dns_injector/arc_dns_injector.jar").getAbsolutePath()+"=23.95.137.176");
}
List<String> additionalArguments = new ArrayList<>();
for(String arg : overridableArguments) {
String strippedArg = arg.substring(0,arg.indexOf('='));

View file

@ -28,7 +28,7 @@
*
*************************************************************************/
package net.kdt.pojavlaunch;
package net.kdt.pojavlaunch.utils;
@SuppressWarnings("unused")
public class LwjglGlfwKeycode {

View file

@ -1,47 +0,0 @@
package net.kdt.pojavlaunch.utils;
import android.util.Log;
import net.kdt.pojavlaunch.JMinecraftVersionList;
import net.kdt.pojavlaunch.Tools;
import net.kdt.pojavlaunch.extra.ExtraConstants;
import net.kdt.pojavlaunch.extra.ExtraCore;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
/** Class here to help with various stuff to help run lower versions smoothly */
public class OldVersionsUtils {
/** Lower minecraft versions fare better with opengl 1
* @param version The version about to be launched
*/
public static void selectOpenGlVersion(JMinecraftVersionList.Version version){
// 1309989600 is 2011-07-07 2011-07-07T22:00:00+00:00
String creationDate = version.time;
if(!Tools.isValidString(creationDate)){
ExtraCore.setValue(ExtraConstants.OPEN_GL_VERSION, "2");
return;
}
try {
int tIndexOf = creationDate.indexOf('T');
if(tIndexOf != -1) creationDate = creationDate.substring(0, tIndexOf);
Date creationDateObj = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH).parse(creationDate);
if(creationDateObj == null) {
Log.e("GL_SELECT", "Failed to parse version date");
ExtraCore.setValue(ExtraConstants.OPEN_GL_VERSION, "2");
return;
}
String openGlVersion = creationDateObj.before(new Date(new GregorianCalendar(2011, 6, 8).getTimeInMillis())) ? "1" : "2";
Log.i("GL_SELECT", openGlVersion);
ExtraCore.setValue(ExtraConstants.OPEN_GL_VERSION, openGlVersion);
}catch (ParseException exception){
Log.e("GL_SELECT", exception.toString());
ExtraCore.setValue(ExtraConstants.OPEN_GL_VERSION, "2");
}
}
}

View file

@ -1,6 +1,8 @@
package org.lwjgl.glfw;
import net.kdt.pojavlaunch.*;
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
import android.content.*;
import android.view.Choreographer;
import java.util.ArrayList;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

View file

@ -22,7 +22,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<net.kdt.pojavlaunch.MinecraftGLSurface
<net.kdt.pojavlaunch.GLFWGLSurface
android:id="@+id/main_game_render_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"

View file

@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#231c09"
tools:context=".DummyLauncher">
tools:context=".ScapeLauncher">
<ImageView
android:id="@+id/imageView4"
@ -52,20 +52,34 @@
app:layout_constraintTop_toTopOf="@+id/imageView2"
app:layout_constraintVertical_bias="0.504" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/myFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/imageView2"
tools:srcCompat="@tools:sample/avatars" />
<com.kdt.mcgui.ProgressLayout
android:id="@+id/progress_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_width="733dp"
android:layout_height="39dp"
app:layout_constraintBottom_toBottomOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteX="-1dp" />
<TextView
android:id="@+id/scapebranding"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="62dp"
android:text="2009Scape - "
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/imageView2"
app:layout_constraintStart_toStartOf="@+id/imageView2" />
<TextView
android:id="@+id/settings"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="62dp"
android:text="Settings"
android:textAllCaps="false"
android:textColor="#B8A078"
app:layout_constraintBottom_toBottomOf="@+id/imageView2"
app:layout_constraintStart_toEndOf="@+id/scapebranding" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -62,7 +62,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/control_button"
android:text="RC"
android:text="MB2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/keyboard" />

View file

@ -10,7 +10,7 @@
android:summary="@string/preference_edit_controls_summary"
app2:icon="@drawable/ic_menu_custom_controls"
>
<intent android:targetPackage="@string/application_package" android:targetClass="net.kdt.pojavlaunch.CustomControlsActivity" android:action=".CustomControlsActivity"/>
<intent android:targetPackage="@string/application_package" android:targetClass="net.kdt.pojavlaunch.customcontrols.CustomControlsActivity" android:action=".CustomControlsActivity"/>
</Preference>
<PreferenceCategory

View file

@ -1 +0,0 @@
/build

View file

@ -1,17 +0,0 @@
plugins {
id 'java-library'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
jar {
manifest {
attributes("Manifest-Version": "1.0",
"PreMain-Class": "git.artdeell.arcdns.ArcDNSInjectorAgent")
}
File versionFile = file("../app_pojavlauncher/src/main/assets/components/arc_dns_injector/version")
versionFile.write(String.valueOf(new Date().getTime()))
destinationDirectory.set(file("../app_pojavlauncher/src/main/assets/components/arc_dns_injector/"))
}

View file

@ -1,22 +0,0 @@
package git.artdeell.arcdns;
public class ArcDNSInjectorAgent {
public static void premain(String args) {
System.out.println("Arc Capes DNS Injector");
System.out.println("Parts of Alibaba's DCM library were used, please read https://github.com/alibaba/java-dns-cache-manipulator/blob/main/README.md for more info");
String[] injectedIps = new String[]{args};
try {
CacheUtil_J9.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
} catch (Exception e) {
try {
CacheUtil_J8.setInetAddressCache("s.optifine.net", injectedIps, CacheUtilCommons.NEVER_EXPIRATION);
} catch (Exception e2) {
System.out.println("Failed to inject cache!");
e2.addSuppressed(e);
e2.printStackTrace();
return;
}
}
System.out.println("Added DNS cache entry: s.optifine.net/"+args);
}
}

View file

@ -1,315 +0,0 @@
package git.artdeell.arcdns;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class CacheUtilCommons {
public static final long NEVER_EXPIRATION = Long.MAX_VALUE;
static InetAddress[] toInetAddressArray(String host, String[] ips) throws UnknownHostException {
InetAddress[] addresses = new InetAddress[ips.length];
for (int i = 0; i < addresses.length; i++) {
addresses[i] = InetAddress.getByAddress(host, ip2ByteArray(ips[i]));
}
return addresses;
}
private static final String INVALID_IP_V6_ADDRESS = ": invalid IPv6 address";
private static final String INVALID_IP_ADDRESS = ": invalid IP address";
static byte[] ip2ByteArray(String ip) {
boolean ipv6Expected = false;
if (ip.charAt(0) == '[') {
// This is supposed to be an IPv6 literal
if (ip.length() > 2 && ip.charAt(ip.length() - 1) == ']') {
ip = ip.substring(1, ip.length() - 1);
ipv6Expected = true;
} else {
// This was supposed to be a IPv6 address, but it's not!
throw new IllegalArgumentException(ip + INVALID_IP_V6_ADDRESS);
}
}
if (Character.digit(ip.charAt(0), 16) != -1 || (ip.charAt(0) == ':')) {
// see if it is IPv4 address
byte[] address = textToNumericFormatV4(ip);
if (address != null) return address;
// see if it is IPv6 address
// Check if a numeric or string zone id is present
address = textToNumericFormatV6(ip);
if (address != null) return address;
if (ipv6Expected) {
throw new IllegalArgumentException(ip + INVALID_IP_V6_ADDRESS);
} else {
throw new IllegalArgumentException(ip + INVALID_IP_ADDRESS);
}
} else {
throw new IllegalArgumentException(ip + INVALID_IP_ADDRESS);
}
}
private static final int INADDR4SZ = 4;
private static final int INADDR16SZ = 16;
private static final int INT16SZ = 2;
/*
* Converts IPv4 address in its textual presentation form
* into its numeric binary form.
*
* @param src a String representing an IPv4 address in standard format
* @return a byte array representing the IPv4 numeric address
*/
@SuppressWarnings("fallthrough")
static byte[] textToNumericFormatV4(String src)
{
byte[] res = new byte[INADDR4SZ];
long tmpValue = 0;
int currByte = 0;
boolean newOctet = true;
int len = src.length();
if (len == 0 || len > 15) {
return null;
}
/*
* When only one part is given, the value is stored directly in
* the network address without any byte rearrangement.
*
* When a two part address is supplied, the last part is
* interpreted as a 24-bit quantity and placed in the right
* most three bytes of the network address. This makes the
* two part address format convenient for specifying Class A
* network addresses as net.host.
*
* When a three part address is specified, the last part is
* interpreted as a 16-bit quantity and placed in the right
* most two bytes of the network address. This makes the
* three part address format convenient for specifying
* Class B net- work addresses as 128.net.host.
*
* When four parts are specified, each is interpreted as a
* byte of data and assigned, from left to right, to the
* four bytes of an IPv4 address.
*
* We determine and parse the leading parts, if any, as single
* byte values in one pass directly into the resulting byte[],
* then the remainder is treated as a 8-to-32-bit entity and
* translated into the remaining bytes in the array.
*/
for (int i = 0; i < len; i++) {
char c = src.charAt(i);
if (c == '.') {
if (newOctet || tmpValue < 0 || tmpValue > 0xff || currByte == 3) {
return null;
}
res[currByte++] = (byte) (tmpValue & 0xff);
tmpValue = 0;
newOctet = true;
} else {
int digit = Character.digit(c, 10);
if (digit < 0) {
return null;
}
tmpValue *= 10;
tmpValue += digit;
newOctet = false;
}
}
if (newOctet || tmpValue < 0 || tmpValue >= (1L << ((4 - currByte) * 8))) {
return null;
}
switch (currByte) {
case 0:
res[0] = (byte) ((tmpValue >> 24) & 0xff);
case 1:
res[1] = (byte) ((tmpValue >> 16) & 0xff);
case 2:
res[2] = (byte) ((tmpValue >> 8) & 0xff);
case 3:
res[3] = (byte) ((tmpValue >> 0) & 0xff);
}
return res;
}
/*
* Convert IPv6 presentation level address to network order binary form.
* credit:
* Converted from C code from Solaris 8 (inet_pton)
*
* Any component of the string following a per-cent % is ignored.
*
* @param src a String representing an IPv6 address in textual format
* @return a byte array representing the IPv6 numeric address
*/
static byte[] textToNumericFormatV6(String src)
{
// Shortest valid string is "::", hence at least 2 chars
if (src.length() < 2) {
return null;
}
int colonp;
char ch;
boolean saw_xdigit;
int val;
char[] srcb = src.toCharArray();
byte[] dst = new byte[INADDR16SZ];
int srcb_length = srcb.length;
int pc = src.indexOf ('%');
if (pc == srcb_length -1) {
return null;
}
if (pc != -1) {
srcb_length = pc;
}
colonp = -1;
int i = 0, j = 0;
/* Leading :: requires some special handling. */
if (srcb[i] == ':')
if (srcb[++i] != ':')
return null;
int curtok = i;
saw_xdigit = false;
val = 0;
while (i < srcb_length) {
ch = srcb[i++];
int chval = Character.digit(ch, 16);
if (chval != -1) {
val <<= 4;
val |= chval;
if (val > 0xffff)
return null;
saw_xdigit = true;
continue;
}
if (ch == ':') {
curtok = i;
if (!saw_xdigit) {
if (colonp != -1)
return null;
colonp = j;
continue;
} else if (i == srcb_length) {
return null;
}
if (j + INT16SZ > INADDR16SZ)
return null;
dst[j++] = (byte) ((val >> 8) & 0xff);
dst[j++] = (byte) (val & 0xff);
saw_xdigit = false;
val = 0;
continue;
}
if (ch == '.' && ((j + INADDR4SZ) <= INADDR16SZ)) {
String ia4 = src.substring(curtok, srcb_length);
/* check this IPv4 address has 3 dots, ie. A.B.C.D */
int dot_count = 0, index=0;
while ((index = ia4.indexOf ('.', index)) != -1) {
dot_count ++;
index ++;
}
if (dot_count != 3) {
return null;
}
byte[] v4addr = textToNumericFormatV4(ia4);
if (v4addr == null) {
return null;
}
for (int k = 0; k < INADDR4SZ; k++) {
dst[j++] = v4addr[k];
}
saw_xdigit = false;
break; /* '\0' was seen by inet_pton4(). */
}
return null;
}
if (saw_xdigit) {
if (j + INT16SZ > INADDR16SZ)
return null;
dst[j++] = (byte) ((val >> 8) & 0xff);
dst[j++] = (byte) (val & 0xff);
}
if (colonp != -1) {
int n = j - colonp;
if (j == INADDR16SZ)
return null;
for (i = 1; i <= n; i++) {
dst[INADDR16SZ - i] = dst[colonp + n - i];
dst[colonp + n - i] = 0;
}
j = INADDR16SZ;
}
if (j != INADDR16SZ)
return null;
byte[] newdst = convertFromIPv4MappedAddress(dst);
if (newdst != null) {
return newdst;
} else {
return dst;
}
}
/*
* Convert IPv4-Mapped address to IPv4 address. Both input and
* returned value are in network order binary form.
*
* @param src a String representing an IPv4-Mapped address in textual format
* @return a byte array representing the IPv4 numeric address
*/
private static byte[] convertFromIPv4MappedAddress(byte[] addr) {
if (isIPv4MappedAddress(addr)) {
byte[] newAddr = new byte[INADDR4SZ];
System.arraycopy(addr, 12, newAddr, 0, INADDR4SZ);
return newAddr;
}
return null;
}
/**
* Utility routine to check if the InetAddress is an
* IPv4 mapped IPv6 address.
*
* @return a <code>boolean</code> indicating if the InetAddress is
* an IPv4 mapped IPv6 address; or false if address is IPv4 address.
*/
private static boolean isIPv4MappedAddress(byte[] addr) {
if (addr.length < INADDR16SZ) {
return false;
}
if ((addr[0] == 0x00) && (addr[1] == 0x00) &&
(addr[2] == 0x00) && (addr[3] == 0x00) &&
(addr[4] == 0x00) && (addr[5] == 0x00) &&
(addr[6] == 0x00) && (addr[7] == 0x00) &&
(addr[8] == 0x00) && (addr[9] == 0x00) &&
(addr[10] == (byte)0xff) &&
(addr[11] == (byte)0xff)) {
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Below source code is copied from commons-lang-3.12.0:
//
// https://github.com/apache/commons-lang/blob/rel/commons-lang-3.12.0/src/main/java/org/apache/commons/lang3/SystemUtils.java
//
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@SuppressWarnings({"CommentedOutCode", "SameParameterValue"})
private static String getSystemProperty(final String property) {
try {
return System.getProperty(property);
} catch (final SecurityException ex) {
// we are not allowed to look at this property
// System.err.println("Caught a SecurityException reading the system property '" + property
// + "'; the SystemUtils property value will default to null.");
return null;
}
}
}

View file

@ -1,153 +0,0 @@
package git.artdeell.arcdns;
import static git.artdeell.arcdns.CacheUtilCommons.NEVER_EXPIRATION;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Map;
public final class CacheUtil_J8 {
public static void setInetAddressCache(String host, String[] ips, long expireMillis)
throws UnknownHostException, IllegalAccessException, InstantiationException,
InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
host = host.toLowerCase();
long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.currentTimeMillis() + expireMillis;
Object entry = newCacheEntry(host, ips, expiration);
synchronized (getAddressCacheOfInetAddress()) {
getCache().put(host, entry);
getNegativeCache().remove(host);
}
}
private static Object newCacheEntry(String host, String[] ips, long expiration)
throws UnknownHostException, ClassNotFoundException, IllegalAccessException,
InvocationTargetException, InstantiationException {
// InetAddress.CacheEntry has only one constructor
return getConstructorOfInetAddress$CacheEntry().newInstance(CacheUtilCommons.toInetAddressArray(host, ips), expiration);
}
private static volatile Constructor<?> constructorOfInetAddress$CacheEntry = null;
private static Constructor<?> getConstructorOfInetAddress$CacheEntry() throws ClassNotFoundException {
if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
synchronized (CacheUtilCommons.class) {
// double check
if (constructorOfInetAddress$CacheEntry != null) return constructorOfInetAddress$CacheEntry;
final String className = "java.net.InetAddress$CacheEntry";
final Class<?> clazz = Class.forName(className);
// InetAddress.CacheEntry has only one constructor:
// - for jdk 6, constructor signature is CacheEntry(Object address, long expiration)
// - for jdk 7/8, constructor signature is CacheEntry(InetAddress[] addresses, long expiration)
//
// code in jdk 6:
// https://hg.openjdk.java.net/jdk6/jdk6/jdk/file/8deef18bb749/src/share/classes/java/net/InetAddress.java#l739
// code in jdk 7:
// https://hg.openjdk.java.net/jdk7u/jdk7u/jdk/file/4dd5e486620d/src/share/classes/java/net/InetAddress.java#l742
// code in jdk 8:
// https://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/45e4e636b757/src/share/classes/java/net/InetAddress.java#l748
final Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
constructor.setAccessible(true);
constructorOfInetAddress$CacheEntry = constructor;
return constructor;
}
}
public static void removeInetAddressCache(String host)
throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
host = host.toLowerCase();
synchronized (getAddressCacheOfInetAddress()) {
getCache().remove(host);
getNegativeCache().remove(host);
}
}
private static Map<String, Object> getCache()
throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
return getCacheOfInetAddress$Cache0(getAddressCacheOfInetAddress());
}
private static Map<String, Object> getNegativeCache()
throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
return getCacheOfInetAddress$Cache0(getNegativeCacheOfInetAddress());
}
private static volatile Field cacheMapFieldOfInetAddress$Cache = null;
@SuppressWarnings("unchecked")
private static Map<String, Object> getCacheOfInetAddress$Cache0(Object inetAddressCache)
throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
if (cacheMapFieldOfInetAddress$Cache == null) {
synchronized (CacheUtil_J8.class) {
if (cacheMapFieldOfInetAddress$Cache == null) { // double check
final Class<?> clazz = Class.forName("java.net.InetAddress$Cache");
final Field f = clazz.getDeclaredField("cache");
f.setAccessible(true);
cacheMapFieldOfInetAddress$Cache = f;
}
}
}
return (Map<String, Object>) cacheMapFieldOfInetAddress$Cache.get(inetAddressCache);
}
private static Object getAddressCacheOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return getAddressCacheAndNegativeCacheOfInetAddress0()[0];
}
private static Object getNegativeCacheOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return getAddressCacheAndNegativeCacheOfInetAddress0()[1];
}
private static volatile Object[] ADDRESS_CACHE_AND_NEGATIVE_CACHE = null;
private static Object[] getAddressCacheAndNegativeCacheOfInetAddress0()
throws NoSuchFieldException, IllegalAccessException {
if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
synchronized (CacheUtil_J8.class) {
// double check
if (ADDRESS_CACHE_AND_NEGATIVE_CACHE != null) return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
final Field cacheField = InetAddress.class.getDeclaredField("addressCache");
cacheField.setAccessible(true);
final Field negativeCacheField = InetAddress.class.getDeclaredField("negativeCache");
negativeCacheField.setAccessible(true);
ADDRESS_CACHE_AND_NEGATIVE_CACHE = new Object[]{
cacheField.get(InetAddress.class),
negativeCacheField.get(InetAddress.class)
};
return ADDRESS_CACHE_AND_NEGATIVE_CACHE;
}
}
private static boolean isDnsCacheEntryExpired(String host) {
return null == host || "0.0.0.0".equals(host);
}
public static void clearInetAddressCache()
throws NoSuchFieldException, IllegalAccessException, ClassNotFoundException {
synchronized (getAddressCacheOfInetAddress()) {
getCache().clear();
getNegativeCache().clear();
}
}
private CacheUtil_J8() {
}
}

View file

@ -1,145 +0,0 @@
package git.artdeell.arcdns;
import static git.artdeell.arcdns.CacheUtilCommons.NEVER_EXPIRATION;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentSkipListSet;
public class CacheUtil_J9 {
public static void setInetAddressCache(String host, String[] ips, long expireMillis)
throws UnknownHostException, IllegalAccessException, InstantiationException,
InvocationTargetException, ClassNotFoundException, NoSuchFieldException {
long expiration = expireMillis == NEVER_EXPIRATION ? NEVER_EXPIRATION : System.nanoTime() + expireMillis * 1_000_000;
Object cachedAddresses = newCachedAddresses(host, ips, expiration);
getCacheOfInetAddress().put(host, cachedAddresses);
getExpirySetOfInetAddress().add(cachedAddresses);
}
private static Object newCachedAddresses(String host, String[] ips, long expiration)
throws ClassNotFoundException, UnknownHostException, IllegalAccessException,
InvocationTargetException, InstantiationException {
// InetAddress.CachedAddresses has only one constructor
return getConstructorOfInetAddress$CachedAddresses().newInstance(host, CacheUtilCommons.toInetAddressArray(host, ips), expiration);
}
private static volatile Constructor<?> constructorOfInetAddress$CachedAddresses = null;
private static Constructor<?> getConstructorOfInetAddress$CachedAddresses() throws ClassNotFoundException {
if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
synchronized (CacheUtilCommons.class) {
// double check
if (constructorOfInetAddress$CachedAddresses != null) return constructorOfInetAddress$CachedAddresses;
final Class<?> clazz = Class.forName(inetAddress$CachedAddresses_ClassName);
// InetAddress.CacheEntry has only one constructor:
//
// - for jdk 9-jdk12, constructor signature is CachedAddresses(String host, InetAddress[] inetAddresses, long expiryTime)
// code in jdk 9:
// https://hg.openjdk.java.net/jdk9/jdk9/jdk/file/65464a307408/src/java.base/share/classes/java/net/InetAddress.java#l783
// code in jdk 11:
// https://hg.openjdk.java.net/jdk/jdk11/file/1ddf9a99e4ad/src/java.base/share/classes/java/net/InetAddress.java#l787
final Constructor<?> constructor = clazz.getDeclaredConstructors()[0];
constructor.setAccessible(true);
constructorOfInetAddress$CachedAddresses = constructor;
return constructor;
}
}
public static void removeInetAddressCache(String host) throws NoSuchFieldException, IllegalAccessException {
getCacheOfInetAddress().remove(host);
removeHostFromExpirySetOfInetAddress(host);
}
/**
* @see #getExpirySetOfInetAddress()
*/
private static void removeHostFromExpirySetOfInetAddress(String host)
throws NoSuchFieldException, IllegalAccessException {
for (Iterator<Object> iterator = getExpirySetOfInetAddress().iterator(); iterator.hasNext(); ) {
Object cachedAddresses = iterator.next();
if (getHostOfInetAddress$CacheAddress(cachedAddresses).equals(host)) {
iterator.remove();
}
}
}
private static volatile Field hostFieldOfInetAddress$CacheAddress = null;
private static String getHostOfInetAddress$CacheAddress(Object cachedAddresses)
throws NoSuchFieldException, IllegalAccessException {
if (hostFieldOfInetAddress$CacheAddress == null) {
synchronized (CacheUtil_J9.class) {
if (hostFieldOfInetAddress$CacheAddress == null) { // double check
final Field f = cachedAddresses.getClass().getDeclaredField("host");
f.setAccessible(true);
hostFieldOfInetAddress$CacheAddress = f;
}
}
}
return (String) hostFieldOfInetAddress$CacheAddress.get(cachedAddresses);
}
//////////////////////////////////////////////////////////////////////////////
// getters of static cache related fields of InetAddress
//////////////////////////////////////////////////////////////////////////////
@SuppressWarnings("unchecked")
private static ConcurrentMap<String, Object> getCacheOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return (ConcurrentMap<String, Object>) getCacheAndExpirySetOfInetAddress0()[0];
}
@SuppressWarnings("unchecked")
private static ConcurrentSkipListSet<Object> getExpirySetOfInetAddress()
throws NoSuchFieldException, IllegalAccessException {
return (ConcurrentSkipListSet<Object>) getCacheAndExpirySetOfInetAddress0()[1];
}
private static volatile Object[] ADDRESS_CACHE_AND_EXPIRY_SET = null;
private static Object[] getCacheAndExpirySetOfInetAddress0()
throws NoSuchFieldException, IllegalAccessException {
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
synchronized (CacheUtil_J9.class) {
if (ADDRESS_CACHE_AND_EXPIRY_SET != null) return ADDRESS_CACHE_AND_EXPIRY_SET;
final Field cacheField = InetAddress.class.getDeclaredField("cache");
cacheField.setAccessible(true);
final Field expirySetField = InetAddress.class.getDeclaredField("expirySet");
expirySetField.setAccessible(true);
ADDRESS_CACHE_AND_EXPIRY_SET = new Object[]{
cacheField.get(InetAddress.class),
expirySetField.get(InetAddress.class)
};
return ADDRESS_CACHE_AND_EXPIRY_SET;
}
}
//////////////////////////////////////////////////////////////////////////////
private static final String inetAddress$CachedAddresses_ClassName = "java.net.InetAddress$CachedAddresses";
public static void clearInetAddressCache() throws NoSuchFieldException, IllegalAccessException {
getCacheOfInetAddress().clear();
getExpirySetOfInetAddress().clear();
}
private CacheUtil_J9() {
}
}

View file

@ -1,42 +0,0 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View file

@ -1,25 +0,0 @@
plugins {
id 'java-library'
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
dependencies {
implementation 'org.json:json:20230618'
}
jar {
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
}
File versionFile = file("../app_pojavlauncher/src/main/assets/components/forge_installer/version")
versionFile.write(String.valueOf(new Date().getTime()))
manifest {
attributes("Manifest-Version": "1.0",
"PreMain-Class": "git.artdeell.installer_agent.Agent")
}
destinationDirectory.set(file("../app_pojavlauncher/src/main/assets/components/forge_installer/"))
}

View file

@ -1,136 +0,0 @@
package git.artdeell.installer_agent;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.WindowEvent;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import javax.swing.AbstractButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
public class Agent implements AWTEventListener {
private boolean forgeWindowHandled = false;
private final boolean suppressProfileCreation;
private final boolean optiFineInstallation;
private final Timer componentTimer = new Timer();
public Agent(boolean nps, boolean of) {
this.suppressProfileCreation = !nps;
this.optiFineInstallation = of;
}
@Override
public void eventDispatched(AWTEvent event) {
WindowEvent windowEvent = (WindowEvent) event;
Window window = windowEvent.getWindow();
if(windowEvent.getID() != WindowEvent.WINDOW_OPENED) return;
if(forgeWindowHandled && window instanceof JDialog) { // expecting a new dialog
handleDialog(window);
return;
}
if(!forgeWindowHandled) { // false at startup, so we will handle the first window as the Forge one
forgeWindowHandled = handleMainWindow(window);
checkComponentTimer();
}
}
public void checkComponentTimer() {
if(forgeWindowHandled) {
componentTimer.cancel();
componentTimer.purge();
return;
}
componentTimer.schedule(new ComponentTimeoutTask(), 30000);
}
public boolean handleMainWindow(Window window) {
List<Component> components = new ArrayList<>();
insertAllComponents(components, window, new MainWindowFilter());
AbstractButton okButton = null;
for(Component component : components) {
if(component instanceof AbstractButton) {
AbstractButton abstractButton = (AbstractButton) component;
abstractButton = optiFineInstallation ?
handleOptiFineButton(abstractButton) :
handleForgeButton(abstractButton);
if(abstractButton != null) okButton = abstractButton;
}
}
if(okButton == null) {
System.out.println("Failed to set all the UI components, wil try again in the next window");
return false;
}else{
ProfileFixer.storeProfile(optiFineInstallation ? "OptiFine" : "forge");
EventQueue.invokeLater(okButton::doClick); // do that after forge actually builds its window, otherwise we set the path too fast
return true;
}
}
public AbstractButton handleForgeButton(AbstractButton abstractButton) {
switch(abstractButton.getText()) {
case "OK":
return abstractButton; // return the button, so we can press it after processing other stuff
case "Install client":
abstractButton.doClick(); // It should be the default, but let's make sure
}
return null;
}
public AbstractButton handleOptiFineButton(AbstractButton abstractButton) {
if ("Install".equals(abstractButton.getText())) {
return abstractButton;
}
return null;
}
public void handleDialog(Window window) {
List<Component> components = new ArrayList<>();
insertAllComponents(components, window, new DialogFilter()); // ensure that it's a JOptionPane dialog
if(components.size() == 1) {
// another common trait of them - they only have one option pane in them,
// so we can discard the rest of the dialog structure
// also allows us to discard dialogs with progress bars which older installers use
JOptionPane optionPane = (JOptionPane) components.get(0);
if(optionPane.getMessageType() == JOptionPane.INFORMATION_MESSAGE) { // forge doesn't emit information messages for other reasons yet
System.out.println("The install was successful!");
ProfileFixer.reinsertProfile(optiFineInstallation ? "OptiFine" : "forge", suppressProfileCreation);
System.exit(0); // again, forge doesn't call exit for some reason, so we do that ourselves here
}
}
}
public void insertAllComponents(List<Component> components, Container parent, ComponentFilter filter) {
int componentCount = parent.getComponentCount();
for(int i = 0; i < componentCount; i++) {
Component component = parent.getComponent(i);
if(filter.checkComponent(component)) components.add(component);
if(component instanceof Container) {
insertAllComponents(components, (Container) component, filter);
}
}
}
public static void premain(String args, Instrumentation inst) {
boolean noProfileSuppression = false;
boolean optifine = false;
if(args != null ) {
noProfileSuppression = args.contains("NPS"); // No Profile Suppression
optifine = args.contains("OF"); // OptiFine
}
Agent agent = new Agent(noProfileSuppression, optifine);
Toolkit.getDefaultToolkit()
.addAWTEventListener(agent,
AWTEvent.WINDOW_EVENT_MASK);
}
}

View file

@ -1,7 +0,0 @@
package git.artdeell.installer_agent;
import java.awt.*;
public interface ComponentFilter {
boolean checkComponent(Component component);
}

View file

@ -1,11 +0,0 @@
package git.artdeell.installer_agent;
import java.util.TimerTask;
public class ComponentTimeoutTask extends TimerTask {
@Override
public void run() {
System.out.println("Initialization timed out!");
System.exit(17);
}
}

View file

@ -1,12 +0,0 @@
package git.artdeell.installer_agent;
import javax.swing.*;
import java.awt.*;
public class DialogFilter implements ComponentFilter{
@Override
public boolean checkComponent(Component component) {
return component instanceof JOptionPane
|| component instanceof JProgressBar;
}
}

View file

@ -1,13 +0,0 @@
package git.artdeell.installer_agent;
import javax.swing.*;
import java.awt.*;
public class MainWindowFilter implements ComponentFilter{
@Override
public boolean checkComponent(Component component) {
return component instanceof JRadioButton
|| component instanceof JTextField
|| component instanceof JButton;
}
}

View file

@ -1,59 +0,0 @@
package git.artdeell.installer_agent;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Random;
public class ProfileFixer {
private static final Random random = new Random();
private static final Path profilesPath = Paths.get(System.getProperty("user.home"), ".minecraft", "launcher_profiles.json");
private static JSONObject oldProfile = null;
public static void storeProfile(String profileName) {
try {
JSONObject minecraftProfiles = new JSONObject(
new String(Files.readAllBytes(profilesPath),
StandardCharsets.UTF_8)
);
JSONObject profilesArray = minecraftProfiles.getJSONObject("profiles");
oldProfile = profilesArray.optJSONObject(profileName, null);
}catch (IOException | JSONException e) {
System.out.println("Failed to store Forge profile: "+e);
}
}
private static String pickProfileName(String profileName) {
return profileName+random.nextInt();
}
public static void reinsertProfile(String profileName, boolean suppressProfileCreation) {
try {
JSONObject minecraftProfiles = new JSONObject(
new String(Files.readAllBytes(profilesPath),
StandardCharsets.UTF_8)
);
JSONObject profilesArray = minecraftProfiles.getJSONObject("profiles");
if(oldProfile != null) {
if(suppressProfileCreation) profilesArray.put("forge", oldProfile); // restore the old profile
else {
String name = pickProfileName(profileName);
while(profilesArray.has(name)) name = pickProfileName(profileName);
profilesArray.put(name, oldProfile); // restore the old profile under a new name
}
}else{
if(suppressProfileCreation) profilesArray.remove("forge"); // remove the new profile
// otherwise it wont be removed
}
minecraftProfiles.put("profiles", profilesArray);
Files.write(profilesPath, minecraftProfiles.toString().getBytes(StandardCharsets.UTF_8),
StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
}catch (IOException | JSONException e) {
System.out.println("Failed to restore old Forge profile: "+e);
}
}
}

View file

@ -18,5 +18,3 @@ rootProject.name='PojavLauncher'
include ':jre_lwjgl3glfw'
include ':app_pojavlauncher'
include ':arc_dns_injector'
include ':forge_installer'