mirror of
https://github.com/2009scape/2009Scape-mobile.git
synced 2025-12-10 10:20:32 -07:00
Beta 1.0 Release
This commit is contained in:
parent
920bcb7137
commit
d37941e2cf
62 changed files with 235 additions and 1320 deletions
|
|
@ -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">
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
1690859739480
|
||||
Binary file not shown.
|
|
@ -1 +0,0 @@
|
|||
1690859739525
|
||||
|
|
@ -1 +1 @@
|
|||
1690859739558
|
||||
1690945073108
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
package net.kdt.pojavlaunch;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
@Keep
|
||||
public class JAssetInfo
|
||||
{
|
||||
public String hash;
|
||||
public int size;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package net.kdt.pojavlaunch.customcontrols.gamepad;
|
||||
|
||||
import net.kdt.pojavlaunch.LwjglGlfwKeycode;
|
||||
import net.kdt.pojavlaunch.utils.LwjglGlfwKeycode;
|
||||
|
||||
public class GamepadMap {
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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.*;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package net.kdt.pojavlaunch;
|
||||
package net.kdt.pojavlaunch.utils;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.kdt.pojavlaunch;
|
||||
package net.kdt.pojavlaunch.utils;
|
||||
|
||||
import static org.lwjgl.glfw.CallbackBridge.sendKeyPress;
|
||||
|
||||
|
|
@ -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('='));
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
*************************************************************************/
|
||||
|
||||
package net.kdt.pojavlaunch;
|
||||
package net.kdt.pojavlaunch.utils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class LwjglGlfwKeycode {
|
||||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 |
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
1
arc_dns_injector/.gitignore
vendored
1
arc_dns_injector/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
/build
|
||||
|
|
@ -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/"))
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
42
forge_installer/.gitignore
vendored
42
forge_installer/.gitignore
vendored
|
|
@ -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
|
||||
|
|
@ -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/"))
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package git.artdeell.installer_agent;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public interface ComponentFilter {
|
||||
boolean checkComponent(Component component);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,5 +18,3 @@ rootProject.name='PojavLauncher'
|
|||
include ':jre_lwjgl3glfw'
|
||||
include ':app_pojavlauncher'
|
||||
|
||||
include ':arc_dns_injector'
|
||||
include ':forge_installer'
|
||||
Loading…
Add table
Add a link
Reference in a new issue