From b544661e81bfe4358e41b001aef79579e1bbd324 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 11 Nov 2022 10:32:54 +0000 Subject: [PATCH 01/26] Experimental skin fix, inspired by craftycodie's Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 5 + .../pages/instance/InstanceSettingsPage.cpp | 7 + .../ui/pages/instance/InstanceSettingsPage.ui | 10 + libraries/launcher/CMakeLists.txt | 4 + .../org/prismlauncher/EntryPoint.java | 3 + .../launcher/org/prismlauncher/fix/Fix.java | 48 ++ .../launcher/org/prismlauncher/fix/Fixes.java | 56 +++ .../org/prismlauncher/fix/skins/SkinFix.java | 107 +++++ .../fix/skins/SkinFixUrlStreamHandler.java | 182 ++++++++ .../org/prismlauncher/utils/JsonParser.java | 433 ++++++++++++++++++ 10 files changed, 855 insertions(+) create mode 100644 libraries/launcher/org/prismlauncher/fix/Fix.java create mode 100644 libraries/launcher/org/prismlauncher/fix/Fixes.java create mode 100644 libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java create mode 100644 libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java create mode 100644 libraries/launcher/org/prismlauncher/utils/JsonParser.java diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 1d37224aa..91de955ad 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -192,6 +192,8 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); + m_settings->registerSetting("LegacySkinFix", true); + qDebug() << "Instance-type specific settings were loaded!"; setSpecificSettingsLoaded(true); @@ -661,6 +663,9 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "traits " + trait + "\n"; } + if (profile->getTraits().contains("legacySkins") && settings()->get("LegacySkinFix").toBool()) + launchScript += "fixes legacySkinFix\n"; + launchScript += "launcher " + getLauncher() + "\n"; // qDebug() << "Generated launch script:" << launchScript; diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index af2ba7c80..537271a2c 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -3,6 +3,7 @@ * PolyMC - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2022 TheKodeToad * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -275,6 +276,9 @@ void InstanceSettingsPage::applySettings() m_settings->reset("JoinServerOnLaunchAddress"); } + bool legacySkinFix = ui->legacySkinFix->isChecked(); + m_settings->set("LegacySkinFix", legacySkinFix); + // FIXME: This should probably be called by a signal instead m_instance->updateRuntimeContext(); } @@ -372,6 +376,9 @@ void InstanceSettingsPage::loadSettings() ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); + + ui->legacySkinFix->setChecked(m_settings->get("LegacySkinFix").toBool()); + ui->legacySkinFix->setVisible(m_instance->traits().contains("legacySkins")); } void InstanceSettingsPage::on_javaDetectBtn_clicked() diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index b064367d1..ca49cbbe5 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -608,6 +608,16 @@ + + + + Enables support for modern skins on old versions. + + + Enable legacy skin fix + + + diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index 55ed58756..1ad398ff5 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -15,6 +15,10 @@ set(SRC org/prismlauncher/launcher/impl/legacy/LegacyFrame.java org/prismlauncher/exception/ParameterNotFoundException.java org/prismlauncher/exception/ParseException.java + org/prismlauncher/fix/Fix.java + org/prismlauncher/fix/Fixes.java + org/prismlauncher/fix/skins/SkinFix.java + org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java org/prismlauncher/utils/logging/Level.java diff --git a/libraries/launcher/org/prismlauncher/EntryPoint.java b/libraries/launcher/org/prismlauncher/EntryPoint.java index 78804b3e8..88ecb48ce 100644 --- a/libraries/launcher/org/prismlauncher/EntryPoint.java +++ b/libraries/launcher/org/prismlauncher/EntryPoint.java @@ -59,6 +59,7 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import org.prismlauncher.exception.ParseException; +import org.prismlauncher.fix.Fixes; import org.prismlauncher.launcher.Launcher; import org.prismlauncher.launcher.impl.StandardLauncher; import org.prismlauncher.launcher.impl.legacy.LegacyLauncher; @@ -107,6 +108,8 @@ public final class EntryPoint { } try { + Fixes.apply(params); + Launcher launcher; String type = params.getString("launcher"); diff --git a/libraries/launcher/org/prismlauncher/fix/Fix.java b/libraries/launcher/org/prismlauncher/fix/Fix.java new file mode 100644 index 000000000..da578c24f --- /dev/null +++ b/libraries/launcher/org/prismlauncher/fix/Fix.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.fix; + +import org.prismlauncher.utils.Parameters; + +public interface Fix { + + String getName(); + + boolean isApplicable(Parameters parameters); + + void apply(); + +} diff --git a/libraries/launcher/org/prismlauncher/fix/Fixes.java b/libraries/launcher/org/prismlauncher/fix/Fixes.java new file mode 100644 index 000000000..ad472fea5 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/fix/Fixes.java @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.fix; + +import java.util.Collections; +import java.util.List; + +import org.prismlauncher.fix.skins.SkinFix; +import org.prismlauncher.utils.Parameters; + +public final class Fixes { + + private static final Fix[] FIXES = { new SkinFix() }; + + public static void apply(Parameters parameters) { + List fixes = parameters.getList("fixes", Collections.emptyList()); + + for (Fix fix : FIXES) + if (fixes.contains(fix.getName()) && fix.isApplicable(parameters)) + fix.apply(); + } + +} diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java new file mode 100644 index 000000000..8d0969a6d --- /dev/null +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.fix.skins; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; + +import org.prismlauncher.fix.Fix; +import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.logging.Log; + +public final class SkinFix implements Fix, URLStreamHandlerFactory { + + private static URLStreamHandler http; + private static MethodHandle openConnection; + private static MethodHandle openConnection2; + + static { + try { + Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); + getURLStreamHandler.setAccessible(true); + http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); + + Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); + openConnectionReflect.setAccessible(true); + openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); + + Method openConnectionReflect2 = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, + Proxy.class); + openConnectionReflect2.setAccessible(true); + openConnection2 = MethodHandles.lookup().unreflect(openConnectionReflect2); + } catch (Throwable e) { + Log.error("Could not perform URL reflection; skin fix will not be availble", e); + } + } + + static URLConnection openConnection(URL url) throws Throwable { + return (URLConnection) openConnection.invokeExact(http, url); + } + + static URLConnection openConnection(URL url, Proxy proxy) throws Throwable { + return (URLConnection) openConnection2.invokeExact(http, url, proxy); + } + + @Override + public String getName() { + return "legacySkinFix"; + } + + @Override + public boolean isApplicable(Parameters parameters) { + return http != null && openConnection != null; + } + + @Override + public void apply() { + URL.setURLStreamHandlerFactory(this); + } + + @Override + public URLStreamHandler createURLStreamHandler(String protocol) { + if ("http".equals(protocol)) + return new SkinFixUrlStreamHandler(); + + return null; + } + +} diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java new file mode 100644 index 000000000..71af341c5 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.fix.skins; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.Map; + +import javax.xml.bind.DatatypeConverter; + +import org.prismlauncher.utils.JsonParser; + +@SuppressWarnings("unchecked") +final class SkinFixUrlStreamHandler extends URLStreamHandler { + + private URL redirect(URL address) throws IOException { + String skinOwner = findSkinOwner(address); + + if (skinOwner != null) + return convertSkin(address, skinOwner); + + String capeOwner = findCapeOwner(address); + + if (capeOwner != null) + return convertCape(address, capeOwner); + + return address; + } + + @Override + protected URLConnection openConnection(URL address) throws IOException { + address = redirect(address); + + try { + return SkinFix.openConnection(address); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + @Override + protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { + address = redirect(address); + + try { + return SkinFix.openConnection(address, proxy); + } catch (RuntimeException | Error e) { + throw e; + } catch (Throwable e) { + throw new IllegalStateException(e); + } + } + + private URL convertSkin(URL defaultUrl, String owner) throws IOException { + Map textures = getTextures(owner); + + if (textures != null) { + textures = (Map) textures.get("SKIN"); + return new URL((String) textures.get("url")); + } + + return defaultUrl; + } + + private URL convertCape(URL defaultUrl, String owner) throws IOException { + Map textures = getTextures(owner); + + if (textures != null) { + textures = (Map) textures.get("CAPE"); + + if (textures == null) + return defaultUrl; + + return new URL((String) textures.get("url")); + } + + return defaultUrl; + } + + private static Map getTextures(String owner) throws IOException { + try (InputStream in = new URL("https://api.mojang.com/users/profiles/minecraft/" + owner).openStream()) { + Map map = (Map) JsonParser.parse(in); + String id = (String) map.get("id"); + + try (InputStream profileIn = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + id) + .openStream()) { + Map profile = (Map) JsonParser.parse(profileIn); + + for (Map property : (Iterable>) profile.get("properties")) { + if (property.get("name").equals("textures")) { + Map result = (Map) JsonParser + .parse(new String(DatatypeConverter.parseBase64Binary((String) property.get("value")))); + result = (Map) result.get("textures"); + return result; + } + } + + return null; + } + } + } + + private static String findSkinOwner(URL address) { + switch (address.getHost()) { + case "www.minecraft.net": + return stripPng(strip(address.getPath(), "/skin/")); + + case "s3.amazonaws.com": + case "skins.minecraft.net": + return stripPng(strip(address.getPath(), "/MinecraftSkins/")); + } + + return null; + } + + private static String findCapeOwner(URL address) { + switch (address.getHost()) { + case "www.minecraft.net": + return stripPng(strip(address.getQuery(), "user=")); + + case "s3.amazonaws.com": + case "skins.minecraft.net": + return stripPng(strip(address.getPath(), "/MinecraftCloaks/")); + } + + return null; + } + + private static String stripPng(String string) { + if (string != null && string.endsWith(".png")) + return string.substring(0, string.lastIndexOf('.')); + + return string; + } + + private static String strip(String string, String prefix) { + if (string != null && string.startsWith(prefix)) + return string.substring(prefix.length()); + + return null; + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/JsonParser.java b/libraries/launcher/org/prismlauncher/utils/JsonParser.java new file mode 100644 index 000000000..e1703972b --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/JsonParser.java @@ -0,0 +1,433 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * MIT License + * + * Copyright (c) 2022 TheKodeToad + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package org.prismlauncher.utils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Single-file JSON parser to allow for usage in versions without GSON. + */ +public final class JsonParser { + + private final Reader in; + private char[] buffer; + private int pos, length; + + public static Object parse(String in) throws JsonParseException, IOException { + return parse(new StringReader(in)); + } + + public static Object parse(InputStream in) throws JsonParseException, IOException { + return parse(new InputStreamReader(in, StandardCharsets.UTF_8)); + } + + public static Object parse(Reader in) throws JsonParseException, IOException { + return new JsonParser(in).readSingleValue(); + } + + private JsonParser(Reader in) throws IOException { + this.in = in; + pos = length = 0; + read(); + } + + private int character() { + if (length == -1) + return -1; + + return buffer[pos]; + } + + private int read() throws IOException { + if (length == -1) + return -1; + + if (buffer == null || pos++ == length - 1) { + pos = 0; + buffer = new char[8192]; + length = in.read(buffer); + } + + return character(); + } + + private void assertCharacter(char character) throws JsonParseException { + if (character() != character) + throw new JsonParseException("Expected '" + character + "' but got " + + (character() != -1 ? ("'" + (char) character() + "'") : "EOF")); + } + + private void assertNoEOF(String expected) throws JsonParseException { + if (character() == -1) + throw new JsonParseException("Expected " + expected + " but got EOF"); + } + + private void skipWhitespace() throws IOException { + while (isWhitespace()) + read(); + } + + private boolean isWhitespace() { + return character() == ' ' || character() == '\n' || character() == '\r' || character() == '\t'; + } + + private Object readSingleValue() throws IOException { + skipWhitespace(); + Object result = readValue(); + + if (!(result instanceof Double)) + read(); + + skipWhitespace(); + + if (character() != -1) + throw new JsonParseException("Found trailing non-whitespace characters"); + + return result; + } + + private Object readValue() throws IOException { + assertNoEOF("a value"); + + int character = character(); + + switch (character) { + case '{': + return readObject(); + + case '[': + return readArray(); + + case '"': + return readString(); + + case 't': + case 'f': + // probably boolean + Boolean bool = readBoolean(); + if (bool != null) + return bool; + + break; + + case 'n': + // probably null + if (readNull()) + return null; + + break; + } + + if (character == '-' || isDigit()) + // probably a number + return readNumber(); + + throw new JsonParseException("Expected a JSON value but got '" + (char) character + "'"); + } + + private Map readObject() throws IOException { + assertCharacter('{'); + Map obj = new HashMap<>(); + boolean comma = false; + + read(); + skipWhitespace(); + + while (character() != '}') { + if (comma) { + assertCharacter(','); + read(); + skipWhitespace(); + } + + String key = readString(); + read(); + skipWhitespace(); + assertCharacter(':'); + read(); + skipWhitespace(); + + Object value = readValue(); + obj.put(key, value); + + if (!(value instanceof Double)) + read(); + + skipWhitespace(); + comma = true; + } + + return obj; + } + + private List readArray() throws IOException { + assertCharacter('['); + List array = new ArrayList<>(); + boolean comma = false; + + read(); + skipWhitespace(); + + while (character() != ']') { + if (comma) { + assertCharacter(','); + read(); + skipWhitespace(); + } + + Object value = readValue(); + array.add(value); + + if (!(value instanceof Double)) + read(); + + skipWhitespace(); + comma = true; + } + + return array; + } + + private String readString() throws IOException { + assertCharacter('"'); + + StringBuilder result = new StringBuilder(); + + while (read() != '"') { + int character = character(); + + if (character >= '\u0000' && character <= '\u001F') + throw new JsonParseException("Found unescaped control character within string"); + + switch (character) { + case -1: + throw new JsonParseException("Expected '\"' but got EOF"); + + case 0x7F: + if (read() == '"') { + return result.toString(); + } + continue; + + case '\\': + int seq = read(); + + switch (seq) { + case -1: + throw new JsonParseException("Expected an escape sequence but got EOF"); + + case '\\': + break; + + case '/': + case '\"': + character = seq; + break; + + case 'b': + character = '\b'; + break; + + case 'f': + character = '\f'; + break; + + case 'n': + character = '\n'; + break; + + case 'r': + character = '\r'; + break; + + case 't': + character = '\t'; + break; + + case 'u': + // char array to allow allocation in advance. + char[] digits = new char[4]; + + for (int index = 0; index < digits.length; index++) { + character = read(); + if (index == 0 && character() == '-') { + throw new JsonParseException("Hex sequence may not be negative"); + } else if (character() == -1) { + throw new JsonParseException("Expected a hex sequence but got EOF"); + } + digits[index] = (char) character; + } + + String digitsString = new String(digits); + + try { + character = Integer.parseInt(digitsString, 16); + } catch (NumberFormatException e) { + throw new JsonParseException("Could not parse hex sequence \"" + digitsString + "\""); + } + + break; + default: + throw new JsonParseException("Invalid escape sequence: \\" + (char) seq); + } + break; + } + + result.append((char) character); + } + + return result.toString(); + } + + private boolean isDigit() { + return character() >= '0' && character() <= '9'; + } + + private Double readNumber() throws IOException { + StringBuilder result = new StringBuilder(); + + if (character() == '-') { + result.append((char) character()); + read(); + } + + if (character() == '0') { + result.append((char) character()); + read(); + if (isDigit()) + throw new JsonParseException("Found superfluous leading zero"); + } else if (!isDigit()) + throw new JsonParseException("Expected digits"); + + while (character() != -1 && isDigit()) { + result.append((char) character()); + read(); + } + + if (character() == '.') { + result.append('.'); + + read(); + assertNoEOF("digits"); + + if (!isDigit()) + throw new JsonParseException("Expected digits after decimal point"); + + while (character() != -1 && isDigit()) { + result.append((char) character()); + read(); + } + } + + if (character() == 'e' || character() == 'E') { + result.append('E'); + + read(); + assertNoEOF("digits"); + + if (character() == '+' || character() == '-') { + result.append((char) character()); + read(); + } + + if (!(character() == '+' || character() == '-' || isDigit())) + throw new JsonParseException("Expected exponent digits"); + + while (character() != -1 && isDigit()) { + result.append((char) character()); + read(); + } + } + + String resultStr = result.toString(); + + try { + return Double.parseDouble(resultStr); + } catch (NumberFormatException e) { + throw new JsonParseException("Failed to parse number '" + resultStr + "'"); + } + } + + private Boolean readBoolean() throws IOException { + if (character() == 't') { + if (read() == 'r' && read() == 'u' && read() == 'e') { + return true; + } + } else if (character() == 'f') { + if (read() == 'a' && read() == 'l' && read() == 's' && read() == 'e') { + return false; + } + } + return null; + } + + private boolean readNull() throws IOException { + return character() == 'n' && read() == 'u' && read() == 'l' && read() == 'l'; + } + + public class JsonParseException extends IOException { + + private static final long serialVersionUID = 1L; + + public JsonParseException(String message) { + super(message); + } + + } + +} \ No newline at end of file From 8a81aaaa0a0ead0a5398b4f3b4e967a3e78b6792 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 12 Nov 2022 12:55:31 +0000 Subject: [PATCH 02/26] Add separate util class Signed-off-by: TheKodeToad --- libraries/launcher/CMakeLists.txt | 3 +- .../launcher/org/prismlauncher/fix/Fix.java | 17 ++- ...nFixUrlStreamHandler.java => Handler.java} | 21 +-- .../org/prismlauncher/fix/skins/SkinFix.java | 73 +++++------ .../org/prismlauncher/utils/UrlUtils.java | 121 ++++++++++++++++++ 5 files changed, 177 insertions(+), 58 deletions(-) rename libraries/launcher/org/prismlauncher/fix/skins/{SkinFixUrlStreamHandler.java => Handler.java} (91%) create mode 100644 libraries/launcher/org/prismlauncher/utils/UrlUtils.java diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index 1ad398ff5..d022d2532 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -18,9 +18,10 @@ set(SRC org/prismlauncher/fix/Fix.java org/prismlauncher/fix/Fixes.java org/prismlauncher/fix/skins/SkinFix.java - org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java + org/prismlauncher/fix/skins/Handler.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java + org/prismlauncher/utils/UrlUtils.java org/prismlauncher/utils/logging/Level.java org/prismlauncher/utils/logging/Log.java net/minecraft/Launcher.java diff --git a/libraries/launcher/org/prismlauncher/fix/Fix.java b/libraries/launcher/org/prismlauncher/fix/Fix.java index da578c24f..3ecd2e90a 100644 --- a/libraries/launcher/org/prismlauncher/fix/Fix.java +++ b/libraries/launcher/org/prismlauncher/fix/Fix.java @@ -39,10 +39,25 @@ import org.prismlauncher.utils.Parameters; public interface Fix { + /** + * Gets the name of the fix. If the name isn't passed into the program, the fix + * won't run. + * + * @return The name + */ String getName(); - boolean isApplicable(Parameters parameters); + /** + * Determines whether the fix will be run. This is additional to the name check. + * + * @param params The parameters + * @return true to proceed to applying the fix + */ + boolean isApplicable(Parameters params); + /** + * Applies the fix. + */ void apply(); } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java similarity index 91% rename from libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java rename to libraries/launcher/org/prismlauncher/fix/skins/Handler.java index 71af341c5..26a3d205e 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFixUrlStreamHandler.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java @@ -46,9 +46,10 @@ import java.util.Map; import javax.xml.bind.DatatypeConverter; import org.prismlauncher.utils.JsonParser; +import org.prismlauncher.utils.UrlUtils; @SuppressWarnings("unchecked") -final class SkinFixUrlStreamHandler extends URLStreamHandler { +final class Handler extends URLStreamHandler { private URL redirect(URL address) throws IOException { String skinOwner = findSkinOwner(address); @@ -67,27 +68,13 @@ final class SkinFixUrlStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL address) throws IOException { address = redirect(address); - - try { - return SkinFix.openConnection(address); - } catch (RuntimeException | Error e) { - throw e; - } catch (Throwable e) { - throw new IllegalStateException(e); - } + return UrlUtils.openHttpConnection(address); } @Override protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { address = redirect(address); - - try { - return SkinFix.openConnection(address, proxy); - } catch (RuntimeException | Error e) { - throw e; - } catch (Throwable e) { - throw new IllegalStateException(e); - } + return UrlUtils.openHttpConnection(address, proxy); } private URL convertSkin(URL defaultUrl, String owner) throws IOException { diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index 8d0969a6d..80cf5323e 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -35,60 +35,55 @@ package org.prismlauncher.fix.skins; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Method; -import java.net.Proxy; import java.net.URL; -import java.net.URLConnection; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import org.prismlauncher.fix.Fix; import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.UrlUtils; import org.prismlauncher.utils.logging.Log; +/** + * Fixes skins by redirecting to other URLs. + * + * @see {@link Handler} + * @see {@link UrlUtils} + */ public final class SkinFix implements Fix, URLStreamHandlerFactory { - private static URLStreamHandler http; - private static MethodHandle openConnection; - private static MethodHandle openConnection2; - - static { - try { - Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); - getURLStreamHandler.setAccessible(true); - http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); - - Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); - openConnectionReflect.setAccessible(true); - openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); - - Method openConnectionReflect2 = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, - Proxy.class); - openConnectionReflect2.setAccessible(true); - openConnection2 = MethodHandles.lookup().unreflect(openConnectionReflect2); - } catch (Throwable e) { - Log.error("Could not perform URL reflection; skin fix will not be availble", e); - } - } - - static URLConnection openConnection(URL url) throws Throwable { - return (URLConnection) openConnection.invokeExact(http, url); - } - - static URLConnection openConnection(URL url, Proxy proxy) throws Throwable { - return (URLConnection) openConnection2.invokeExact(http, url, proxy); - } - @Override public String getName() { return "legacySkinFix"; } @Override - public boolean isApplicable(Parameters parameters) { - return http != null && openConnection != null; + public boolean isApplicable(Parameters params) { + if (!isSupported()) { + Log.warning("Using Java 8 will probably fix this"); + Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + return false; + } + + return true; + } + + private boolean isSupported() { + // check for DatatypeConverter first + // most users will just be annoyed by the big stacktrace + try { + Class.forName("javax.xml.bind.DatatypeConverter"); + } catch (ClassNotFoundException e) { + Log.warning("Cannot find DatatypeConverter - required for skin fix"); + return false; + } + + if (!UrlUtils.isSupported()) { + Log.warning("Cannot access the necessary Java internals for skin fix"); + return false; + } + + return true; } @Override @@ -99,7 +94,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { @Override public URLStreamHandler createURLStreamHandler(String protocol) { if ("http".equals(protocol)) - return new SkinFixUrlStreamHandler(); + return new Handler(); return null; } diff --git a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java new file mode 100644 index 000000000..c73c7600b --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils; + +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Method; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +import org.prismlauncher.utils.logging.Log; + +/** + * A utility class for URLs which uses reflection to access hidden methods. + * Unfortunately not supported on newer Java versions. + */ +public class UrlUtils { + + private static URLStreamHandler http; + private static MethodHandle openConnection; + private static MethodHandle openConnectionProxied; + + static { + try { + // invoke URL.getURLStreamHandler to obtain some of the default handlers before + // they are overridden + Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); + getURLStreamHandler.setAccessible(true); + http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); + + // reflection is required due to not having access + // unreflect is used due to the potential frequency of calls + Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); + openConnectionReflect.setAccessible(true); + openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); + + // a second method which takes in a proxy is required for a fully-functional + // URLStreamHandler + Method openConnectionReflectProxied = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, + Proxy.class); + openConnectionReflectProxied.setAccessible(true); + openConnectionProxied = MethodHandles.lookup().unreflect(openConnectionReflectProxied); + } catch (Throwable e) { + Log.error("URL reflection failed - some features may not work", e); + } + } + + /** + * Determines whether all the features of this class are available. + * + * @return true if all features can be used + */ + public static boolean isSupported() { + return http != null && openConnection != null && openConnectionProxied != null; + } + + public static URLConnection openHttpConnection(URL url) throws IOException { + return openConnection(http, url); + } + + public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { + return openConnection(http, url, proxy); + } + + public static URLConnection openConnection(URLStreamHandler handler, URL url) throws IOException { + try { + return (URLConnection) openConnection.invokeExact(handler, url); + } catch (IOException | Error | RuntimeException e) { + throw e; // rethrow if possible + } catch (Throwable e) { + throw new Error(e); // otherwise, wrap in Error + } + } + + public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { + try { + return (URLConnection) openConnectionProxied.invokeExact(handler, url, proxy); + } catch (IOException | Error | RuntimeException e) { + throw e; + } catch (Throwable e) { + throw new Error(e); + } + } + +} From 7534eaf006e030f2f446a3c793090d7640fb2361 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 12 Nov 2022 14:48:42 +0000 Subject: [PATCH 03/26] Only use DatatypeConverter as a fallback Signed-off-by: TheKodeToad --- libraries/launcher/CMakeLists.txt | 2 + .../org/prismlauncher/fix/skins/Handler.java | 5 +- .../org/prismlauncher/fix/skins/SkinFix.java | 21 +------ .../org/prismlauncher/utils/Base64.java | 59 +++++++++++++++++++ .../org/prismlauncher/utils/JsonParser.java | 2 +- .../org/prismlauncher/utils/UrlUtils.java | 2 +- 6 files changed, 67 insertions(+), 24 deletions(-) create mode 100644 libraries/launcher/org/prismlauncher/utils/Base64.java diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index d022d2532..acc276218 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -19,6 +19,8 @@ set(SRC org/prismlauncher/fix/Fixes.java org/prismlauncher/fix/skins/SkinFix.java org/prismlauncher/fix/skins/Handler.java + org/prismlauncher/utils/Base64.java + org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java org/prismlauncher/utils/UrlUtils.java diff --git a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java index 26a3d205e..2bffeae96 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java @@ -43,8 +43,7 @@ import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.Map; -import javax.xml.bind.DatatypeConverter; - +import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.JsonParser; import org.prismlauncher.utils.UrlUtils; @@ -115,7 +114,7 @@ final class Handler extends URLStreamHandler { for (Map property : (Iterable>) profile.get("properties")) { if (property.get("name").equals("textures")) { Map result = (Map) JsonParser - .parse(new String(DatatypeConverter.parseBase64Binary((String) property.get("value")))); + .parse(new String(Base64.decode((String) property.get("value")))); result = (Map) result.get("textures"); return result; } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index 80cf5323e..f5a9e0df4 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -59,27 +59,10 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { @Override public boolean isApplicable(Parameters params) { - if (!isSupported()) { - Log.warning("Using Java 8 will probably fix this"); - Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); - return false; - } - - return true; - } - - private boolean isSupported() { - // check for DatatypeConverter first - // most users will just be annoyed by the big stacktrace - try { - Class.forName("javax.xml.bind.DatatypeConverter"); - } catch (ClassNotFoundException e) { - Log.warning("Cannot find DatatypeConverter - required for skin fix"); - return false; - } - if (!UrlUtils.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); + Log.warning("Using an older Java version will probably fix this"); + Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); return false; } diff --git a/libraries/launcher/org/prismlauncher/utils/Base64.java b/libraries/launcher/org/prismlauncher/utils/Base64.java new file mode 100644 index 000000000..20a189f46 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/Base64.java @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils; + +import java.nio.charset.StandardCharsets; + +import javax.xml.bind.DatatypeConverter; + +public final class Base64 { + + private static boolean legacy; + + public static byte[] decode(String input) { + if (!legacy) { + try { + return java.util.Base64.getDecoder().decode(input.getBytes(StandardCharsets.UTF_8)); + } catch (NoClassDefFoundError e) { + legacy = true; + } + } + + // support for Java versions < 8 + return DatatypeConverter.parseBase64Binary(input); + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/JsonParser.java b/libraries/launcher/org/prismlauncher/utils/JsonParser.java index e1703972b..d1803c896 100644 --- a/libraries/launcher/org/prismlauncher/utils/JsonParser.java +++ b/libraries/launcher/org/prismlauncher/utils/JsonParser.java @@ -420,7 +420,7 @@ public final class JsonParser { return character() == 'n' && read() == 'u' && read() == 'l' && read() == 'l'; } - public class JsonParseException extends IOException { + public static class JsonParseException extends IOException { private static final long serialVersionUID = 1L; diff --git a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java index c73c7600b..362feb4e3 100644 --- a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java @@ -50,7 +50,7 @@ import org.prismlauncher.utils.logging.Log; * A utility class for URLs which uses reflection to access hidden methods. * Unfortunately not supported on newer Java versions. */ -public class UrlUtils { +public final class UrlUtils { private static URLStreamHandler http; private static MethodHandle openConnection; From cfeadf858edd05e11db67d7d3d217ed25a00537b Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 12 Nov 2022 15:12:55 +0000 Subject: [PATCH 04/26] Add workaround to warning Signed-off-by: TheKodeToad --- libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index f5a9e0df4..927c10142 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -61,7 +61,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { public boolean isApplicable(Parameters params) { if (!UrlUtils.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); - Log.warning("Using an older Java version will probably fix this"); + Log.warning("Try adding '--add-opens java.base/java.net=ALL-UNNAMED' to your Java arguments"); Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); return false; } From ead59c0246639837bbdbfcc6a0ca443a1ab06d6c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 20 Nov 2022 09:16:30 +0000 Subject: [PATCH 05/26] Improve the skin fix code - Spoof 404 instead of keeping original URL. - Move JsonParseException to the package. - Pass proxy as null to reduce code duplication. Signed-off-by: TheKodeToad --- libraries/launcher/CMakeLists.txt | 3 +- .../exception/JsonParseException.java | 48 ++++++++++++++ .../launcher/org/prismlauncher/fix/Fixes.java | 6 +- .../org/prismlauncher/fix/skins/Handler.java | 60 +++++++---------- .../org/prismlauncher/fix/skins/SkinFix.java | 2 +- .../org/prismlauncher/utils/JsonParser.java | 12 +--- .../utils/url/NullConnection.java | 66 +++++++++++++++++++ .../utils/{ => url}/UrlUtils.java | 35 ++-------- 8 files changed, 153 insertions(+), 79 deletions(-) create mode 100644 libraries/launcher/org/prismlauncher/exception/JsonParseException.java create mode 100644 libraries/launcher/org/prismlauncher/utils/url/NullConnection.java rename libraries/launcher/org/prismlauncher/utils/{ => url}/UrlUtils.java (74%) diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index acc276218..65a8241eb 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -23,7 +23,8 @@ set(SRC org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java - org/prismlauncher/utils/UrlUtils.java + org/prismlauncher/utils/url/NullConnection.java + org/prismlauncher/utils/url/UrlUtils.java org/prismlauncher/utils/logging/Level.java org/prismlauncher/utils/logging/Log.java net/minecraft/Launcher.java diff --git a/libraries/launcher/org/prismlauncher/exception/JsonParseException.java b/libraries/launcher/org/prismlauncher/exception/JsonParseException.java new file mode 100644 index 000000000..5983eb883 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/exception/JsonParseException.java @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.exception; + +import java.io.IOException; + +public class JsonParseException extends IOException { + + private static final long serialVersionUID = 1L; + + public JsonParseException(String message) { + super(message); + } + +} \ No newline at end of file diff --git a/libraries/launcher/org/prismlauncher/fix/Fixes.java b/libraries/launcher/org/prismlauncher/fix/Fixes.java index ad472fea5..e099b653c 100644 --- a/libraries/launcher/org/prismlauncher/fix/Fixes.java +++ b/libraries/launcher/org/prismlauncher/fix/Fixes.java @@ -45,11 +45,11 @@ public final class Fixes { private static final Fix[] FIXES = { new SkinFix() }; - public static void apply(Parameters parameters) { - List fixes = parameters.getList("fixes", Collections.emptyList()); + public static void apply(Parameters params) { + List fixes = params.getList("fixes", Collections.emptyList()); for (Fix fix : FIXES) - if (fixes.contains(fix.getName()) && fix.isApplicable(parameters)) + if (fixes.contains(fix.getName()) && fix.isApplicable(params)) fix.apply(); } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java index 2bffeae96..0f5b556f8 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java @@ -45,61 +45,51 @@ import java.util.Map; import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.JsonParser; -import org.prismlauncher.utils.UrlUtils; +import org.prismlauncher.utils.url.NullConnection; +import org.prismlauncher.utils.url.UrlUtils; @SuppressWarnings("unchecked") final class Handler extends URLStreamHandler { private URL redirect(URL address) throws IOException { String skinOwner = findSkinOwner(address); - if (skinOwner != null) - return convertSkin(address, skinOwner); + return convert(skinOwner, "SKIN"); String capeOwner = findCapeOwner(address); - if (capeOwner != null) - return convertCape(address, capeOwner); + return convert(capeOwner, "CAPE"); return address; } @Override protected URLConnection openConnection(URL address) throws IOException { - address = redirect(address); - return UrlUtils.openHttpConnection(address); + return openConnection(address, null); } @Override protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { address = redirect(address); + + if (address == null) + return NullConnection.INSTANCE; + return UrlUtils.openHttpConnection(address, proxy); } - private URL convertSkin(URL defaultUrl, String owner) throws IOException { + private URL convert(String owner, String name) throws IOException { Map textures = getTextures(owner); if (textures != null) { - textures = (Map) textures.get("SKIN"); - return new URL((String) textures.get("url")); - } - - return defaultUrl; - } - - private URL convertCape(URL defaultUrl, String owner) throws IOException { - Map textures = getTextures(owner); - - if (textures != null) { - textures = (Map) textures.get("CAPE"); - + textures = (Map) textures.get(name); if (textures == null) - return defaultUrl; + return null; return new URL((String) textures.get("url")); } - return defaultUrl; + return null; } private static Map getTextures(String owner) throws IOException { @@ -116,6 +106,7 @@ final class Handler extends URLStreamHandler { Map result = (Map) JsonParser .parse(new String(Base64.decode((String) property.get("value")))); result = (Map) result.get("textures"); + return result; } } @@ -128,11 +119,11 @@ final class Handler extends URLStreamHandler { private static String findSkinOwner(URL address) { switch (address.getHost()) { case "www.minecraft.net": - return stripPng(strip(address.getPath(), "/skin/")); + return stripIfPrefixed(address.getPath(), "/skin/"); case "s3.amazonaws.com": case "skins.minecraft.net": - return stripPng(strip(address.getPath(), "/MinecraftSkins/")); + return stripIfPrefixed(address.getPath(), "/MinecraftSkins/"); } return null; @@ -141,26 +132,25 @@ final class Handler extends URLStreamHandler { private static String findCapeOwner(URL address) { switch (address.getHost()) { case "www.minecraft.net": - return stripPng(strip(address.getQuery(), "user=")); + return stripIfPrefixed(address.getQuery(), "user="); case "s3.amazonaws.com": case "skins.minecraft.net": - return stripPng(strip(address.getPath(), "/MinecraftCloaks/")); + return stripIfPrefixed(address.getPath(), "/MinecraftCloaks/"); } return null; } - private static String stripPng(String string) { - if (string != null && string.endsWith(".png")) - return string.substring(0, string.lastIndexOf('.')); + private static String stripIfPrefixed(String string, String prefix) { + if (string != null && string.startsWith(prefix)) { + string = string.substring(prefix.length()); - return string; - } + if (string.endsWith(".png")) + string = string.substring(0, string.lastIndexOf('.')); - private static String strip(String string, String prefix) { - if (string != null && string.startsWith(prefix)) - return string.substring(prefix.length()); + return string; + } return null; } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index 927c10142..e26dfb6f1 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -41,8 +41,8 @@ import java.net.URLStreamHandlerFactory; import org.prismlauncher.fix.Fix; import org.prismlauncher.utils.Parameters; -import org.prismlauncher.utils.UrlUtils; import org.prismlauncher.utils.logging.Log; +import org.prismlauncher.utils.url.UrlUtils; /** * Fixes skins by redirecting to other URLs. diff --git a/libraries/launcher/org/prismlauncher/utils/JsonParser.java b/libraries/launcher/org/prismlauncher/utils/JsonParser.java index d1803c896..378e58235 100644 --- a/libraries/launcher/org/prismlauncher/utils/JsonParser.java +++ b/libraries/launcher/org/prismlauncher/utils/JsonParser.java @@ -59,6 +59,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.prismlauncher.exception.JsonParseException; + /** * Single-file JSON parser to allow for usage in versions without GSON. */ @@ -420,14 +422,4 @@ public final class JsonParser { return character() == 'n' && read() == 'u' && read() == 'l' && read() == 'l'; } - public static class JsonParseException extends IOException { - - private static final long serialVersionUID = 1L; - - public JsonParseException(String message) { - super(message); - } - - } - } \ No newline at end of file diff --git a/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java b/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java new file mode 100644 index 000000000..628488e8d --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils.url; + +import java.io.IOException; +import java.net.HttpURLConnection; + +/** + * Spoof 404 response from server to avoid unnecessary requests. + */ +public final class NullConnection extends HttpURLConnection { + + public static final NullConnection INSTANCE = new NullConnection(); + + public NullConnection() { + super(null); + } + + @Override + public void connect() throws IOException { + responseCode = 404; + } + + @Override + public void disconnect() { + } + + @Override + public boolean usingProxy() { + return false; + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java similarity index 74% rename from libraries/launcher/org/prismlauncher/utils/UrlUtils.java rename to libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java index 362feb4e3..751f833fd 100644 --- a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils; +package org.prismlauncher.utils.url; import java.io.IOException; import java.lang.invoke.MethodHandle; @@ -54,7 +54,6 @@ public final class UrlUtils { private static URLStreamHandler http; private static MethodHandle openConnection; - private static MethodHandle openConnectionProxied; static { try { @@ -64,18 +63,10 @@ public final class UrlUtils { getURLStreamHandler.setAccessible(true); http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); - // reflection is required due to not having access - // unreflect is used due to the potential frequency of calls - Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class); + Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, + Proxy.class); openConnectionReflect.setAccessible(true); openConnection = MethodHandles.lookup().unreflect(openConnectionReflect); - - // a second method which takes in a proxy is required for a fully-functional - // URLStreamHandler - Method openConnectionReflectProxied = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, - Proxy.class); - openConnectionReflectProxied.setAccessible(true); - openConnectionProxied = MethodHandles.lookup().unreflect(openConnectionReflectProxied); } catch (Throwable e) { Log.error("URL reflection failed - some features may not work", e); } @@ -87,20 +78,16 @@ public final class UrlUtils { * @return true if all features can be used */ public static boolean isSupported() { - return http != null && openConnection != null && openConnectionProxied != null; - } - - public static URLConnection openHttpConnection(URL url) throws IOException { - return openConnection(http, url); + return http != null && openConnection != null; } public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { return openConnection(http, url, proxy); } - public static URLConnection openConnection(URLStreamHandler handler, URL url) throws IOException { + public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { try { - return (URLConnection) openConnection.invokeExact(handler, url); + return (URLConnection) openConnection.invokeExact(handler, url, proxy); } catch (IOException | Error | RuntimeException e) { throw e; // rethrow if possible } catch (Throwable e) { @@ -108,14 +95,4 @@ public final class UrlUtils { } } - public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { - try { - return (URLConnection) openConnectionProxied.invokeExact(handler, url, proxy); - } catch (IOException | Error | RuntimeException e) { - throw e; - } catch (Throwable e) { - throw new Error(e); - } - } - } From bfa5fe1598a6a60045fe01e589cc5f67cfe35f5a Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 20 Nov 2022 09:55:30 +0000 Subject: [PATCH 06/26] Better skin fix error handling Signed-off-by: TheKodeToad --- libraries/launcher/org/prismlauncher/fix/Fixes.java | 13 ++++++++++--- .../org/prismlauncher/fix/skins/SkinFix.java | 8 +++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/libraries/launcher/org/prismlauncher/fix/Fixes.java b/libraries/launcher/org/prismlauncher/fix/Fixes.java index e099b653c..e85bcfd42 100644 --- a/libraries/launcher/org/prismlauncher/fix/Fixes.java +++ b/libraries/launcher/org/prismlauncher/fix/Fixes.java @@ -40,6 +40,7 @@ import java.util.List; import org.prismlauncher.fix.skins.SkinFix; import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.logging.Log; public final class Fixes { @@ -48,9 +49,15 @@ public final class Fixes { public static void apply(Parameters params) { List fixes = params.getList("fixes", Collections.emptyList()); - for (Fix fix : FIXES) - if (fixes.contains(fix.getName()) && fix.isApplicable(params)) - fix.apply(); + for (Fix fix : FIXES) { + if (fixes.contains(fix.getName()) && fix.isApplicable(params)) { + try { + fix.apply(); + } catch (Throwable e) { + Log.error("Could not apply " + fix.getName(), e); + } + } + } } } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index e26dfb6f1..ab978dc58 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -71,7 +71,13 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { @Override public void apply() { - URL.setURLStreamHandlerFactory(this); + try { + URL.setURLStreamHandlerFactory(this); + } catch (Error e) { + Log.warning("Cannot apply skin fix"); + Log.warning("URLStreamHandlerFactory is already set"); + Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + } } @Override From 8a6776731af94e768831440f27d3e9e8e81ab7bf Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Tue, 22 Nov 2022 16:56:58 +0000 Subject: [PATCH 07/26] Use reflection to access DatatypeConverter Signed-off-by: TheKodeToad --- .../org/prismlauncher/fix/skins/SkinFix.java | 3 +- .../org/prismlauncher/utils/Base64.java | 53 +++++++++++++++---- .../org/prismlauncher/utils/url/UrlUtils.java | 6 +++ 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index ab978dc58..66b5fda62 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -40,6 +40,7 @@ import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import org.prismlauncher.fix.Fix; +import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.logging.Log; import org.prismlauncher.utils.url.UrlUtils; @@ -59,7 +60,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { @Override public boolean isApplicable(Parameters params) { - if (!UrlUtils.isSupported()) { + if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); Log.warning("Try adding '--add-opens java.base/java.net=ALL-UNNAMED' to your Java arguments"); Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); diff --git a/libraries/launcher/org/prismlauncher/utils/Base64.java b/libraries/launcher/org/prismlauncher/utils/Base64.java index 20a189f46..508df872d 100644 --- a/libraries/launcher/org/prismlauncher/utils/Base64.java +++ b/libraries/launcher/org/prismlauncher/utils/Base64.java @@ -35,25 +35,60 @@ package org.prismlauncher.utils; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.nio.charset.StandardCharsets; -import javax.xml.bind.DatatypeConverter; +import org.prismlauncher.utils.logging.Log; +/** + * Uses Base64 with Java 8 or later, otherwise DatatypeConverter. In the latter + * case, reflection is used to allow using newer compilers. + */ public final class Base64 { - private static boolean legacy; + private static boolean supported = true; + private static MethodHandle legacy; - public static byte[] decode(String input) { - if (!legacy) { + static { + try { + Class.forName("java.util.Base64"); + } catch (ClassNotFoundException e) { try { - return java.util.Base64.getDecoder().decode(input.getBytes(StandardCharsets.UTF_8)); - } catch (NoClassDefFoundError e) { - legacy = true; + Class datatypeConverter = Class.forName("javax.xml.bind.DatatypeConverter"); + legacy = MethodHandles.lookup().findStatic(datatypeConverter, "parseBase64Binary", + MethodType.methodType(byte[].class, String.class)); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e1) { + Log.error("Base64 not supported", e1); + supported = false; } } + } - // support for Java versions < 8 - return DatatypeConverter.parseBase64Binary(input); + /** + * Determines whether base64 is supported. + * + * @return true if base64 can be parsed + */ + public static boolean isSupported() { + return supported; + } + + public static byte[] decode(String input) { + if (!isSupported()) + throw new UnsupportedOperationException(); + + if (legacy == null) + return java.util.Base64.getDecoder().decode(input.getBytes(StandardCharsets.UTF_8)); + + try { + return (byte[]) legacy.invokeExact(input); + } catch (Error | RuntimeException e) { + throw e; + } catch (Throwable e) { + throw new Error(e); + } } } diff --git a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java index 751f833fd..05912d005 100644 --- a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java @@ -82,10 +82,16 @@ public final class UrlUtils { } public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { + if (http == null) + throw new UnsupportedOperationException(); + return openConnection(http, url, proxy); } public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { + if (openConnection == null) + throw new UnsupportedOperationException(); + try { return (URLConnection) openConnection.invokeExact(handler, url, proxy); } catch (IOException | Error | RuntimeException e) { From 87bcefd08ac5023a6b406bc6c909ddff7d6ca1bf Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Thu, 15 Dec 2022 15:28:17 +0000 Subject: [PATCH 08/26] Automatically add add-opens if Java version >= 9 Signed-off-by: TheKodeToad --- launcher/java/JavaVersion.cpp | 10 +++++----- launcher/java/JavaVersion.h | 2 ++ launcher/minecraft/MinecraftInstance.cpp | 10 +++++----- .../launcher/org/prismlauncher/fix/skins/SkinFix.java | 3 +-- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/launcher/java/JavaVersion.cpp b/launcher/java/JavaVersion.cpp index 0e4fc1d3c..cfb12fbf3 100644 --- a/launcher/java/JavaVersion.cpp +++ b/launcher/java/JavaVersion.cpp @@ -50,11 +50,11 @@ QString JavaVersion::toString() bool JavaVersion::requiresPermGen() { - if(m_parseable) - { - return m_major < 8; - } - return true; + return !m_parseable || m_major < 8; +} + +bool JavaVersion::isModular() { + return m_parseable && m_major >= 9; } bool JavaVersion::operator<(const JavaVersion &rhs) diff --git a/launcher/java/JavaVersion.h b/launcher/java/JavaVersion.h index 9bbf06425..0551214ad 100644 --- a/launcher/java/JavaVersion.h +++ b/launcher/java/JavaVersion.h @@ -25,6 +25,8 @@ public: bool requiresPermGen(); + bool isModular(); + QString toString(); int major() diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 91de955ad..4434936f0 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -440,15 +440,15 @@ QStringList MinecraftInstance::javaArguments() args << "-Duser.language=en"; + if (javaVersion.isModular() && traits().contains("legacySkins") && settings()->get("LegacySkinFix").toBool()) + args << "--add-opens" << "java.base/java.net=ALL-UNNAMED"; + return args; } -QString MinecraftInstance::getLauncher() -{ - auto profile = m_components->getProfile(); - +QString MinecraftInstance::getLauncher() { // use legacy launcher if the traits are set - if (profile->getTraits().contains("legacyLaunch") || profile->getTraits().contains("alphaLaunch")) + if (traits().contains("legacyLaunch") || traits().contains("alphaLaunch")) return "legacy"; return "standard"; diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index 66b5fda62..19b15605a 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -62,8 +62,7 @@ public final class SkinFix implements Fix, URLStreamHandlerFactory { public boolean isApplicable(Parameters params) { if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); - Log.warning("Try adding '--add-opens java.base/java.net=ALL-UNNAMED' to your Java arguments"); - Log.warning("Alternatively, turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); return false; } From 94067f34cf8a42c735c264ca30740bfec6f5af3a Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Wed, 21 Dec 2022 18:13:41 +0000 Subject: [PATCH 09/26] Try to make some of the suggested changes Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 6 +- libraries/launcher/CMakeLists.txt | 3 +- .../org/prismlauncher/fix/skins/Handler.java | 7 +- .../org/prismlauncher/fix/skins/SkinFix.java | 2 +- .../utils/{url => }/UrlUtils.java | 14 ++-- .../utils/url/NullConnection.java | 66 ------------------- 6 files changed, 14 insertions(+), 84 deletions(-) rename libraries/launcher/org/prismlauncher/utils/{url => }/UrlUtils.java (91%) delete mode 100644 libraries/launcher/org/prismlauncher/utils/url/NullConnection.java diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 4434936f0..378af0e10 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -192,7 +192,7 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); - m_settings->registerSetting("LegacySkinFix", true); + m_settings->registerSetting("LegacySkinFix", true); qDebug() << "Instance-type specific settings were loaded!"; @@ -441,7 +441,9 @@ QStringList MinecraftInstance::javaArguments() args << "-Duser.language=en"; if (javaVersion.isModular() && traits().contains("legacySkins") && settings()->get("LegacySkinFix").toBool()) - args << "--add-opens" << "java.base/java.net=ALL-UNNAMED"; + // allow reflective access to java.net - required by the skin fix + args << "--add-opens" + << "java.base/java.net=ALL-UNNAMED"; return args; } diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index 65a8241eb..acc276218 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -23,8 +23,7 @@ set(SRC org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java - org/prismlauncher/utils/url/NullConnection.java - org/prismlauncher/utils/url/UrlUtils.java + org/prismlauncher/utils/UrlUtils.java org/prismlauncher/utils/logging/Level.java org/prismlauncher/utils/logging/Log.java net/minecraft/Launcher.java diff --git a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java index 0f5b556f8..fa306ed44 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/Handler.java @@ -45,8 +45,7 @@ import java.util.Map; import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.JsonParser; -import org.prismlauncher.utils.url.NullConnection; -import org.prismlauncher.utils.url.UrlUtils; +import org.prismlauncher.utils.UrlUtils; @SuppressWarnings("unchecked") final class Handler extends URLStreamHandler { @@ -71,10 +70,6 @@ final class Handler extends URLStreamHandler { @Override protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { address = redirect(address); - - if (address == null) - return NullConnection.INSTANCE; - return UrlUtils.openHttpConnection(address, proxy); } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java index 19b15605a..3dd747376 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java @@ -42,8 +42,8 @@ import java.net.URLStreamHandlerFactory; import org.prismlauncher.fix.Fix; import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.UrlUtils; import org.prismlauncher.utils.logging.Log; -import org.prismlauncher.utils.url.UrlUtils; /** * Fixes skins by redirecting to other URLs. diff --git a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java similarity index 91% rename from libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java rename to libraries/launcher/org/prismlauncher/utils/UrlUtils.java index 05912d005..1ab0eb918 100644 --- a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/UrlUtils.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils.url; +package org.prismlauncher.utils; import java.io.IOException; import java.lang.invoke.MethodHandle; @@ -47,8 +47,8 @@ import java.net.URLStreamHandler; import org.prismlauncher.utils.logging.Log; /** - * A utility class for URLs which uses reflection to access hidden methods. - * Unfortunately not supported on newer Java versions. + * A utility class for URLs which uses reflection to access constructors for + * internal classes. */ public final class UrlUtils { @@ -57,12 +57,12 @@ public final class UrlUtils { static { try { - // invoke URL.getURLStreamHandler to obtain some of the default handlers before - // they are overridden + // we first obtain the stock URLStreamHandler for http as we overwrite it later Method getURLStreamHandler = URL.class.getDeclaredMethod("getURLStreamHandler", String.class); getURLStreamHandler.setAccessible(true); http = (URLStreamHandler) getURLStreamHandler.invoke(null, "http"); + // we next find the openConnection method Method openConnectionReflect = URLStreamHandler.class.getDeclaredMethod("openConnection", URL.class, Proxy.class); openConnectionReflect.setAccessible(true); @@ -97,8 +97,8 @@ public final class UrlUtils { } catch (IOException | Error | RuntimeException e) { throw e; // rethrow if possible } catch (Throwable e) { - throw new Error(e); // otherwise, wrap in Error + throw new AssertionError(e); // oh dear! this isn't meant to happen } } -} +} \ No newline at end of file diff --git a/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java b/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java deleted file mode 100644 index 628488e8d..000000000 --- a/libraries/launcher/org/prismlauncher/utils/url/NullConnection.java +++ /dev/null @@ -1,66 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 TheKodeToad - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Linking this library statically or dynamically with other modules is - * making a combined work based on this library. Thus, the terms and - * conditions of the GNU General Public License cover the whole - * combination. - * - * As a special exception, the copyright holders of this library give - * you permission to link this library with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also meet, - * for each linked independent module, the terms and conditions of the - * license of that module. An independent module is a module which is - * not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the - * library, but you are not obliged to do so. If you do not wish to do - * so, delete this exception statement from your version. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.prismlauncher.utils.url; - -import java.io.IOException; -import java.net.HttpURLConnection; - -/** - * Spoof 404 response from server to avoid unnecessary requests. - */ -public final class NullConnection extends HttpURLConnection { - - public static final NullConnection INSTANCE = new NullConnection(); - - public NullConnection() { - super(null); - } - - @Override - public void connect() throws IOException { - responseCode = 404; - } - - @Override - public void disconnect() { - } - - @Override - public boolean usingProxy() { - return false; - } - -} From 884bd8549537cb67a9e59c83ab4ca761491ff27b Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 23 Dec 2022 09:35:29 +0000 Subject: [PATCH 10/26] Skin fix -> online fixes Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 8 +-- .../pages/instance/InstanceSettingsPage.cpp | 8 +-- .../ui/pages/instance/InstanceSettingsPage.ui | 6 +- libraries/launcher/CMakeLists.txt | 6 +- .../launcher/org/prismlauncher/fix/Fixes.java | 21 +------ .../fix/{Fix.java => online/Handler.java} | 38 ++++++------ .../SkinFix.java => online/OnlineFixes.java} | 26 ++------- .../Handler.java => online/SkinFix.java} | 58 ++----------------- 8 files changed, 44 insertions(+), 127 deletions(-) rename libraries/launcher/org/prismlauncher/fix/{Fix.java => online/Handler.java} (73%) rename libraries/launcher/org/prismlauncher/fix/{skins/SkinFix.java => online/OnlineFixes.java} (82%) rename libraries/launcher/org/prismlauncher/fix/{skins/Handler.java => online/SkinFix.java} (56%) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 378af0e10..ec916f26f 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -192,7 +192,7 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerSetting("JoinServerOnLaunch", false); m_settings->registerSetting("JoinServerOnLaunchAddress", ""); - m_settings->registerSetting("LegacySkinFix", true); + m_settings->registerSetting("OnlineFixes", true); qDebug() << "Instance-type specific settings were loaded!"; @@ -440,7 +440,7 @@ QStringList MinecraftInstance::javaArguments() args << "-Duser.language=en"; - if (javaVersion.isModular() && traits().contains("legacySkins") && settings()->get("LegacySkinFix").toBool()) + if (javaVersion.isModular() && traits().contains("legacyServices") && settings()->get("OnlineFixes").toBool()) // allow reflective access to java.net - required by the skin fix args << "--add-opens" << "java.base/java.net=ALL-UNNAMED"; @@ -665,8 +665,8 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "traits " + trait + "\n"; } - if (profile->getTraits().contains("legacySkins") && settings()->get("LegacySkinFix").toBool()) - launchScript += "fixes legacySkinFix\n"; + if (profile->getTraits().contains("legacyServices") && settings()->get("OnlineFixes").toBool()) + launchScript += "onlineFixes true\n"; launchScript += "launcher " + getLauncher() + "\n"; diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 537271a2c..23299b1dc 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -276,8 +276,8 @@ void InstanceSettingsPage::applySettings() m_settings->reset("JoinServerOnLaunchAddress"); } - bool legacySkinFix = ui->legacySkinFix->isChecked(); - m_settings->set("LegacySkinFix", legacySkinFix); + bool onlineFixes = ui->onlineFixes->isChecked(); + m_settings->set("OnlineFixes", onlineFixes); // FIXME: This should probably be called by a signal instead m_instance->updateRuntimeContext(); @@ -377,8 +377,8 @@ void InstanceSettingsPage::loadSettings() ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); - ui->legacySkinFix->setChecked(m_settings->get("LegacySkinFix").toBool()); - ui->legacySkinFix->setVisible(m_instance->traits().contains("legacySkins")); + ui->onlineFixes->setChecked(m_settings->get("OnlineFixes").toBool()); + ui->onlineFixes->setVisible(m_instance->traits().contains("legacyServices")); } void InstanceSettingsPage::on_javaDetectBtn_clicked() diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index ca49cbbe5..7b42b8397 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -609,12 +609,12 @@ - + - Enables support for modern skins on old versions. + <html><head/><body><p>Fixes usages of old online services which are no longer operating by emulating them or redirecting to their modern counterparts.</p><p>This currently only allows modern skins to be used.</p></body></html> - Enable legacy skin fix + Enable online fixes diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index acc276218..71996ae33 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -15,10 +15,10 @@ set(SRC org/prismlauncher/launcher/impl/legacy/LegacyFrame.java org/prismlauncher/exception/ParameterNotFoundException.java org/prismlauncher/exception/ParseException.java - org/prismlauncher/fix/Fix.java org/prismlauncher/fix/Fixes.java - org/prismlauncher/fix/skins/SkinFix.java - org/prismlauncher/fix/skins/Handler.java + org/prismlauncher/fix/online/OnlineFixes.java + org/prismlauncher/fix/online/SkinFix.java + org/prismlauncher/fix/online/Handler.java org/prismlauncher/utils/Base64.java org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java diff --git a/libraries/launcher/org/prismlauncher/fix/Fixes.java b/libraries/launcher/org/prismlauncher/fix/Fixes.java index e85bcfd42..429964ad9 100644 --- a/libraries/launcher/org/prismlauncher/fix/Fixes.java +++ b/libraries/launcher/org/prismlauncher/fix/Fixes.java @@ -35,29 +35,14 @@ package org.prismlauncher.fix; -import java.util.Collections; -import java.util.List; - -import org.prismlauncher.fix.skins.SkinFix; +import org.prismlauncher.fix.online.OnlineFixes; import org.prismlauncher.utils.Parameters; -import org.prismlauncher.utils.logging.Log; public final class Fixes { - private static final Fix[] FIXES = { new SkinFix() }; - public static void apply(Parameters params) { - List fixes = params.getList("fixes", Collections.emptyList()); - - for (Fix fix : FIXES) { - if (fixes.contains(fix.getName()) && fix.isApplicable(params)) { - try { - fix.apply(); - } catch (Throwable e) { - Log.error("Could not apply " + fix.getName(), e); - } - } - } + if ("true".equalsIgnoreCase(params.getString("onlineFixes", null))) + OnlineFixes.apply(); } } diff --git a/libraries/launcher/org/prismlauncher/fix/Fix.java b/libraries/launcher/org/prismlauncher/fix/online/Handler.java similarity index 73% rename from libraries/launcher/org/prismlauncher/fix/Fix.java rename to libraries/launcher/org/prismlauncher/fix/online/Handler.java index 3ecd2e90a..b5b4de28e 100644 --- a/libraries/launcher/org/prismlauncher/fix/Fix.java +++ b/libraries/launcher/org/prismlauncher/fix/online/Handler.java @@ -33,31 +33,27 @@ * along with this program. If not, see . */ -package org.prismlauncher.fix; +package org.prismlauncher.fix.online; -import org.prismlauncher.utils.Parameters; +import java.io.IOException; +import java.net.Proxy; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; -public interface Fix { +import org.prismlauncher.utils.UrlUtils; - /** - * Gets the name of the fix. If the name isn't passed into the program, the fix - * won't run. - * - * @return The name - */ - String getName(); +final class Handler extends URLStreamHandler { - /** - * Determines whether the fix will be run. This is additional to the name check. - * - * @param params The parameters - * @return true to proceed to applying the fix - */ - boolean isApplicable(Parameters params); + @Override + protected URLConnection openConnection(URL address) throws IOException { + return openConnection(address, null); + } - /** - * Applies the fix. - */ - void apply(); + @Override + protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { + address = SkinFix.redirect(address); + return UrlUtils.openHttpConnection(address, proxy); + } } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java similarity index 82% rename from libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java rename to libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java index 3dd747376..c344a8e73 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java @@ -33,15 +33,13 @@ * along with this program. If not, see . */ -package org.prismlauncher.fix.skins; +package org.prismlauncher.fix.online; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; -import org.prismlauncher.fix.Fix; import org.prismlauncher.utils.Base64; -import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.UrlUtils; import org.prismlauncher.utils.logging.Log; @@ -51,31 +49,19 @@ import org.prismlauncher.utils.logging.Log; * @see {@link Handler} * @see {@link UrlUtils} */ -public final class SkinFix implements Fix, URLStreamHandlerFactory { +public final class OnlineFixes implements URLStreamHandlerFactory { - @Override - public String getName() { - return "legacySkinFix"; - } - - @Override - public boolean isApplicable(Parameters params) { + public static void apply() { if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); - return false; + return; } - return true; - } - - @Override - public void apply() { try { - URL.setURLStreamHandlerFactory(this); + URL.setURLStreamHandlerFactory(new OnlineFixes()); } catch (Error e) { - Log.warning("Cannot apply skin fix"); - Log.warning("URLStreamHandlerFactory is already set"); + Log.warning("Cannot apply skin fix: URLStreamHandlerFactory is already set"); Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); } } diff --git a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java b/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java similarity index 56% rename from libraries/launcher/org/prismlauncher/fix/skins/Handler.java rename to libraries/launcher/org/prismlauncher/fix/online/SkinFix.java index fa306ed44..f1e480776 100644 --- a/libraries/launcher/org/prismlauncher/fix/skins/Handler.java +++ b/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java @@ -1,56 +1,17 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 TheKodeToad - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Linking this library statically or dynamically with other modules is - * making a combined work based on this library. Thus, the terms and - * conditions of the GNU General Public License cover the whole - * combination. - * - * As a special exception, the copyright holders of this library give - * you permission to link this library with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also meet, - * for each linked independent module, the terms and conditions of the - * license of that module. An independent module is a module which is - * not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the - * library, but you are not obliged to do so. If you do not wish to do - * so, delete this exception statement from your version. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.prismlauncher.fix.skins; +package org.prismlauncher.fix.online; import java.io.IOException; import java.io.InputStream; -import java.net.Proxy; import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; import java.util.Map; import org.prismlauncher.utils.Base64; import org.prismlauncher.utils.JsonParser; -import org.prismlauncher.utils.UrlUtils; @SuppressWarnings("unchecked") -final class Handler extends URLStreamHandler { +final class SkinFix { - private URL redirect(URL address) throws IOException { + static URL redirect(URL address) throws IOException { String skinOwner = findSkinOwner(address); if (skinOwner != null) return convert(skinOwner, "SKIN"); @@ -62,18 +23,7 @@ final class Handler extends URLStreamHandler { return address; } - @Override - protected URLConnection openConnection(URL address) throws IOException { - return openConnection(address, null); - } - - @Override - protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { - address = redirect(address); - return UrlUtils.openHttpConnection(address, proxy); - } - - private URL convert(String owner, String name) throws IOException { + private static URL convert(String owner, String name) throws IOException { Map textures = getTextures(owner); if (textures != null) { From 5c96b1c6289d0f31b073153668140e84066e87f2 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 25 Dec 2022 09:45:42 +0000 Subject: [PATCH 11/26] Remove MIT license from JsonParser I don't mind, and it's my code. Signed-off-by: TheKodeToad --- .../org/prismlauncher/utils/JsonParser.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/libraries/launcher/org/prismlauncher/utils/JsonParser.java b/libraries/launcher/org/prismlauncher/utils/JsonParser.java index 378e58235..5f10e9a7b 100644 --- a/libraries/launcher/org/prismlauncher/utils/JsonParser.java +++ b/libraries/launcher/org/prismlauncher/utils/JsonParser.java @@ -31,19 +31,6 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . - * - * This file incorporates work covered by the following copyright and - * permission notice: - * - * MIT License - * - * Copyright (c) 2022 TheKodeToad - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package org.prismlauncher.utils; @@ -422,4 +409,4 @@ public final class JsonParser { return character() == 'n' && read() == 'u' && read() == 'l' && read() == 'l'; } -} \ No newline at end of file +} From cb32711077af62b527abdc4af5aabce44f4e5d21 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 25 Dec 2022 11:40:49 +0000 Subject: [PATCH 12/26] Slim skin fix - thanks to @craftycodie and @DelofJ ! Signed-off-by: TheKodeToad --- libraries/launcher/CMakeLists.txt | 5 +- .../org/prismlauncher/fix/online/Handler.java | 12 ++- .../prismlauncher/fix/online/OnlineFixes.java | 2 +- .../org/prismlauncher/fix/online/SkinFix.java | 94 +++++++++------- .../prismlauncher/utils/api/MojangApi.java | 101 ++++++++++++++++++ .../org/prismlauncher/utils/api/Texture.java | 61 +++++++++++ .../utils/url/CustomUrlConnection.java | 79 ++++++++++++++ .../utils/{ => url}/UrlUtils.java | 12 ++- 8 files changed, 322 insertions(+), 44 deletions(-) create mode 100644 libraries/launcher/org/prismlauncher/utils/api/MojangApi.java create mode 100644 libraries/launcher/org/prismlauncher/utils/api/Texture.java create mode 100644 libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java rename libraries/launcher/org/prismlauncher/utils/{ => url}/UrlUtils.java (89%) diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index 71996ae33..bf8f0baa2 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -23,9 +23,12 @@ set(SRC org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java - org/prismlauncher/utils/UrlUtils.java + org/prismlauncher/utils/api/MojangApi.java + org/prismlauncher/utils/api/Texture.java org/prismlauncher/utils/logging/Level.java org/prismlauncher/utils/logging/Log.java + org/prismlauncher/utils/url/UrlUtils.java + org/prismlauncher/utils/url/CustomUrlConnection.java net/minecraft/Launcher.java ) add_jar(NewLaunch ${SRC}) diff --git a/libraries/launcher/org/prismlauncher/fix/online/Handler.java b/libraries/launcher/org/prismlauncher/fix/online/Handler.java index b5b4de28e..618683119 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/Handler.java +++ b/libraries/launcher/org/prismlauncher/fix/online/Handler.java @@ -41,7 +41,7 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import org.prismlauncher.utils.UrlUtils; +import org.prismlauncher.utils.url.UrlUtils; final class Handler extends URLStreamHandler { @@ -52,8 +52,14 @@ final class Handler extends URLStreamHandler { @Override protected URLConnection openConnection(URL address, Proxy proxy) throws IOException { - address = SkinFix.redirect(address); - return UrlUtils.openHttpConnection(address, proxy); + URLConnection result; + + // try skin fix + result = SkinFix.openConnection(address, proxy); + if (result != null) + return result; + + return UrlUtils.openConnection(address, proxy); } } diff --git a/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java b/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java index c344a8e73..5f9ff1014 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java +++ b/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java @@ -40,8 +40,8 @@ import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; import org.prismlauncher.utils.Base64; -import org.prismlauncher.utils.UrlUtils; import org.prismlauncher.utils.logging.Log; +import org.prismlauncher.utils.url.UrlUtils; /** * Fixes skins by redirecting to other URLs. diff --git a/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java b/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java index f1e480776..b05e1f208 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java +++ b/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java @@ -1,63 +1,85 @@ package org.prismlauncher.fix.online; +import java.awt.AlphaComposite; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.Proxy; import java.net.URL; -import java.util.Map; +import java.net.URLConnection; -import org.prismlauncher.utils.Base64; -import org.prismlauncher.utils.JsonParser; +import javax.imageio.ImageIO; + +import org.prismlauncher.utils.api.MojangApi; +import org.prismlauncher.utils.api.Texture; +import org.prismlauncher.utils.url.CustomUrlConnection; +import org.prismlauncher.utils.url.UrlUtils; -@SuppressWarnings("unchecked") final class SkinFix { - static URL redirect(URL address) throws IOException { + static URLConnection openConnection(URL address, Proxy proxy) throws IOException { String skinOwner = findSkinOwner(address); if (skinOwner != null) - return convert(skinOwner, "SKIN"); + // we need to correct the skin + return getSkinConnection(skinOwner, proxy); String capeOwner = findCapeOwner(address); - if (capeOwner != null) - return convert(capeOwner, "CAPE"); - - return address; - } - - private static URL convert(String owner, String name) throws IOException { - Map textures = getTextures(owner); - - if (textures != null) { - textures = (Map) textures.get(name); - if (textures == null) + if (capeOwner != null) { + // since we do not need to process the image, open a direct connection bypassing Handler + Texture texture = MojangApi.getTexture(MojangApi.getUuid(capeOwner), "CAPE"); + if (texture == null) return null; - return new URL((String) textures.get("url")); + return UrlUtils.openConnection(texture.getUrl(), proxy); } return null; } - private static Map getTextures(String owner) throws IOException { - try (InputStream in = new URL("https://api.mojang.com/users/profiles/minecraft/" + owner).openStream()) { - Map map = (Map) JsonParser.parse(in); - String id = (String) map.get("id"); + private static URLConnection getSkinConnection(String owner, Proxy proxy) throws IOException { + Texture texture = MojangApi.getTexture(MojangApi.getUuid(owner), "SKIN"); + if (texture == null) + return null; - try (InputStream profileIn = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + id) - .openStream()) { - Map profile = (Map) JsonParser.parse(profileIn); + URLConnection connection = UrlUtils.openConnection(texture.getUrl(), proxy); + try (InputStream in = connection.getInputStream()) { + // thank you craftycodie! + // this is heavily based on + // https://github.com/Mojang/LegacyLauncher/pull/33/files#diff-b61023785a9260651ca0a223573ea9acb5be5eec478bff626dafb7abe13ffebaR99 + BufferedImage image = ImageIO.read(in); + Graphics2D graphics = image.createGraphics(); + graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); - for (Map property : (Iterable>) profile.get("properties")) { - if (property.get("name").equals("textures")) { - Map result = (Map) JsonParser - .parse(new String(Base64.decode((String) property.get("value")))); - result = (Map) result.get("textures"); + BufferedImage subimage; - return result; - } - } - - return null; + if (image.getHeight() > 32) { + // flatten second layers + subimage = image.getSubimage(0, 32, 56, 16); + graphics.drawImage(subimage, 0, 16, null); } + + if (texture.isSlim()) { + // convert slim to wide + subimage = image.getSubimage(45, 16, 9, 16); + graphics.drawImage(subimage, 46, 16, null); + + subimage = image.getSubimage(49, 16, 2, 4); + graphics.drawImage(subimage, 50, 16, null); + + subimage = image.getSubimage(53, 20, 2, 12); + graphics.drawImage(subimage, 54, 20, null); + } + + graphics.dispose(); + + // crop the image + ByteArrayOutputStream out = new ByteArrayOutputStream(); + image = image.getSubimage(0, 0, 64, 32); + ImageIO.write(image, "png", out); + + return new CustomUrlConnection(out.toByteArray()); } } diff --git a/libraries/launcher/org/prismlauncher/utils/api/MojangApi.java b/libraries/launcher/org/prismlauncher/utils/api/MojangApi.java new file mode 100644 index 000000000..dc2794107 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/api/MojangApi.java @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils.api; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; + +import org.prismlauncher.utils.Base64; +import org.prismlauncher.utils.JsonParser; + +/** + * Basic access to Mojang's Minecraft API. + */ +@SuppressWarnings("unchecked") +public final class MojangApi { + + public static String getUuid(String username) throws IOException { + try (InputStream in = new URL("https://api.mojang.com/users/profiles/minecraft/" + username).openStream()) { + Map map = (Map) JsonParser.parse(in); + return (String) map.get("id"); + } + } + + public static Texture getTexture(String player, String name) throws IOException { + Map map = getTextures(player); + + if (map != null) { + map = (Map) map.get(name); + if (map == null) + return null; + + URL url = new URL((String) map.get("url")); + boolean slim = false; + + if (name.equals("SKIN")) { + map = (Map) map.get("metadata"); + if (map != null && "slim".equals(map.get("model"))) + slim = true; + } + + return new Texture(url, slim); + } + + return null; + } + + public static Map getTextures(String player) throws IOException { + try (InputStream profileIn = new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + player) + .openStream()) { + Map profile = (Map) JsonParser.parse(profileIn); + + for (Map property : (Iterable>) profile.get("properties")) { + if (property.get("name").equals("textures")) { + Map result = (Map) JsonParser + .parse(new String(Base64.decode((String) property.get("value")))); + result = (Map) result.get("textures"); + + return result; + } + } + + return null; + } + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/api/Texture.java b/libraries/launcher/org/prismlauncher/utils/api/Texture.java new file mode 100644 index 000000000..1b5c2204e --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/api/Texture.java @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils.api; + +import java.net.URL; + +/** + * Represents a texture from the Mojang API. + */ +public final class Texture { + + private final URL url; + private final boolean slim; + + public Texture(URL url, boolean slim) { + this.url = url; + this.slim = slim; + } + + public URL getUrl() { + return url; + } + + public boolean isSlim() { + return slim; + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java b/libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java new file mode 100644 index 000000000..8bc0cff11 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils.url; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; + +public class CustomUrlConnection extends HttpURLConnection { + + private InputStream in; + + public CustomUrlConnection(byte[] data) { + this(new ByteArrayInputStream(data)); + } + + public CustomUrlConnection(InputStream in) { + super(null); + this.in = in; + } + + @Override + public void connect() throws IOException { + responseCode = 200; + } + + @Override + public void disconnect() { + try { + in.close(); + } catch (IOException e) { + } + } + + @Override + public InputStream getInputStream() throws IOException { + return in; + } + + @Override + public boolean usingProxy() { + return false; + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java similarity index 89% rename from libraries/launcher/org/prismlauncher/utils/UrlUtils.java rename to libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java index 1ab0eb918..69ebbd50b 100644 --- a/libraries/launcher/org/prismlauncher/utils/UrlUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils; +package org.prismlauncher.utils.url; import java.io.IOException; import java.lang.invoke.MethodHandle; @@ -81,11 +81,17 @@ public final class UrlUtils { return http != null && openConnection != null; } - public static URLConnection openHttpConnection(URL url, Proxy proxy) throws IOException { + public static URLConnection openConnection(URL url, Proxy proxy) throws IOException { if (http == null) throw new UnsupportedOperationException(); - return openConnection(http, url, proxy); + if (url.getProtocol().equals("http")) + return openConnection(http, url, proxy); + + // fall back to Java's default method + // at this point, this should not cause a StackOverflowError unless we've missed + // a protocol out from the if statements + return url.openConnection(); } public static URLConnection openConnection(URLStreamHandler handler, URL url, Proxy proxy) throws IOException { From 17317ea308d3523a4ead9c926e8f2213d7ea53ea Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 6 Jan 2023 09:21:09 +0000 Subject: [PATCH 13/26] Move legacy support classes to another jar Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 12 +++- launcher/minecraft/MinecraftInstance.h | 1 + .../minecraft/launch/LauncherPartLaunch.cpp | 16 +++++ libraries/launcher/CMakeLists.txt | 34 +++++++---- .../{ => legacy}/net/minecraft/Launcher.java | 0 .../prismlauncher}/legacy/LegacyFrame.java | 4 +- .../prismlauncher}/legacy/LegacyLauncher.java | 49 ++++++++++++--- .../org/prismlauncher/legacy/LegacyProxy.java | 17 ++++++ .../legacy}/fix/online/Handler.java | 4 +- .../legacy}/fix/online/OnlineFixes.java | 12 ++-- .../legacy}/fix/online/SkinFix.java | 8 +-- .../prismlauncher/legacy}/utils/Base64.java | 2 +- .../legacy/utils}/JsonParseException.java | 2 +- .../legacy}/utils/JsonParser.java | 4 +- .../legacy}/utils/api/MojangApi.java | 5 +- .../legacy}/utils/api/Texture.java | 2 +- .../utils/url/CustomUrlConnection.java | 2 +- .../legacy}/utils/url/UrlUtils.java | 2 +- .../org/prismlauncher/EntryPoint.java | 7 +-- .../launcher/org/prismlauncher/fix/Fixes.java | 48 --------------- .../org/prismlauncher/legacy/LegacyProxy.java | 17 ++++++ .../prismlauncher/utils/ReflectionUtils.java | 61 ------------------- .../org/prismlauncher/utils/logging/Log.java | 2 +- 23 files changed, 150 insertions(+), 161 deletions(-) rename libraries/launcher/{ => legacy}/net/minecraft/Launcher.java (100%) rename libraries/launcher/{org/prismlauncher/launcher/impl => legacy/org/prismlauncher}/legacy/LegacyFrame.java (98%) rename libraries/launcher/{org/prismlauncher/launcher/impl => legacy/org/prismlauncher}/legacy/LegacyLauncher.java (76%) create mode 100644 libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/fix/online/Handler.java (96%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/fix/online/OnlineFixes.java (89%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/fix/online/SkinFix.java (94%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/Base64.java (98%) rename libraries/launcher/{org/prismlauncher/exception => legacy/org/prismlauncher/legacy/utils}/JsonParseException.java (97%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/JsonParser.java (99%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/api/MojangApi.java (96%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/api/Texture.java (97%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/url/CustomUrlConnection.java (98%) rename libraries/launcher/{org/prismlauncher => legacy/org/prismlauncher/legacy}/utils/url/UrlUtils.java (98%) delete mode 100644 libraries/launcher/org/prismlauncher/fix/Fixes.java create mode 100644 libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index ec916f26f..9aa2db0be 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -440,7 +440,7 @@ QStringList MinecraftInstance::javaArguments() args << "-Duser.language=en"; - if (javaVersion.isModular() && traits().contains("legacyServices") && settings()->get("OnlineFixes").toBool()) + if (javaVersion.isModular() && shouldApplyOnlineFixes()) // allow reflective access to java.net - required by the skin fix args << "--add-opens" << "java.base/java.net=ALL-UNNAMED"; @@ -448,7 +448,8 @@ QStringList MinecraftInstance::javaArguments() return args; } -QString MinecraftInstance::getLauncher() { +QString MinecraftInstance::getLauncher() +{ // use legacy launcher if the traits are set if (traits().contains("legacyLaunch") || traits().contains("alphaLaunch")) return "legacy"; @@ -456,6 +457,11 @@ QString MinecraftInstance::getLauncher() { return "standard"; } +bool MinecraftInstance::shouldApplyOnlineFixes() +{ + return traits().contains("legacyServices") && settings()->get("OnlineFixes").toBool(); +} + QMap MinecraftInstance::getVariables() { QMap out; @@ -665,7 +671,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "traits " + trait + "\n"; } - if (profile->getTraits().contains("legacyServices") && settings()->get("OnlineFixes").toBool()) + if (shouldApplyOnlineFixes()) launchScript += "onlineFixes true\n"; launchScript += "launcher " + getLauncher() + "\n"; diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index 1bbd7b832..9826bfd9e 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -132,6 +132,7 @@ public: /// get arguments passed to java QStringList javaArguments(); QString getLauncher(); + bool shouldApplyOnlineFixes(); /// get variables for launch command variable substitution/environment QMap getVariables() override; diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index 1d8d70833..71280cb8d 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -107,6 +107,19 @@ void LauncherPartLaunch::executeTask() auto instance = m_parent->instance(); std::shared_ptr minecraftInstance = std::dynamic_pointer_cast(instance); + QString legacyJarPath; + if (minecraftInstance->getLauncher() == "legacy" || minecraftInstance->shouldApplyOnlineFixes()) + { + legacyJarPath = APPLICATION->getJarPath("NewLaunchLegacy.jar"); + if (legacyJarPath.isEmpty()) + { + const char *reason = QT_TR_NOOP("Legacy launcher library could not be found. Please check your installation."); + emit logLine(tr(reason), MessageLevel::Fatal); + emitFailed(tr(reason)); + return; + } + } + m_launchScript = minecraftInstance->createLaunchScript(m_session, m_serverToJoin); QStringList args = minecraftInstance->javaArguments(); QString allArgs = args.join(", "); @@ -122,6 +135,9 @@ void LauncherPartLaunch::executeTask() auto classPath = minecraftInstance->getClassPath(); classPath.prepend(jarPath); + if (!legacyJarPath.isEmpty()) + classPath.prepend(legacyJarPath); + auto natPath = minecraftInstance->getNativePath(); #ifdef Q_OS_WIN if (!fitsInLocal8bit(natPath)) diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index bf8f0baa2..d835dc9a3 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -11,25 +11,33 @@ set(SRC org/prismlauncher/launcher/Launcher.java org/prismlauncher/launcher/impl/AbstractLauncher.java org/prismlauncher/launcher/impl/StandardLauncher.java - org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java - org/prismlauncher/launcher/impl/legacy/LegacyFrame.java org/prismlauncher/exception/ParameterNotFoundException.java org/prismlauncher/exception/ParseException.java - org/prismlauncher/fix/Fixes.java - org/prismlauncher/fix/online/OnlineFixes.java - org/prismlauncher/fix/online/SkinFix.java - org/prismlauncher/fix/online/Handler.java - org/prismlauncher/utils/Base64.java - org/prismlauncher/utils/JsonParser.java org/prismlauncher/utils/Parameters.java org/prismlauncher/utils/ReflectionUtils.java - org/prismlauncher/utils/api/MojangApi.java - org/prismlauncher/utils/api/Texture.java org/prismlauncher/utils/logging/Level.java org/prismlauncher/utils/logging/Log.java - org/prismlauncher/utils/url/UrlUtils.java - org/prismlauncher/utils/url/CustomUrlConnection.java - net/minecraft/Launcher.java + org/prismlauncher/legacy/LegacyProxy.java ) + +set(LEGACY_SRC + legacy/org/prismlauncher/legacy/LegacyFrame.java + legacy/org/prismlauncher/legacy/LegacyLauncher.java + legacy/org/prismlauncher/legacy/fix/online/Handler.java + legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java + legacy/org/prismlauncher/legacy/fix/online/SkinFix.java + legacy/org/prismlauncher/legacy/utils/Base64.java + legacy/org/prismlauncher/legacy/utils/JsonParseException.java + legacy/org/prismlauncher/legacy/utils/JsonParser.java + legacy/org/prismlauncher/legacy/utils/api/MojangApi.java + legacy/org/prismlauncher/legacy/utils/api/Texture.java + legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java + legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java + legacy/net/minecraft/Launcher.java + legacy/org/prismlauncher/legacy/LegacyProxy.java +) + add_jar(NewLaunch ${SRC}) +add_jar(NewLaunchLegacy ${LEGACY_SRC} INCLUDE_JARS NewLaunch) install_jar(NewLaunch "${JARS_DEST_DIR}") +install_jar(NewLaunchLegacy "${JARS_DEST_DIR}") diff --git a/libraries/launcher/net/minecraft/Launcher.java b/libraries/launcher/legacy/net/minecraft/Launcher.java similarity index 100% rename from libraries/launcher/net/minecraft/Launcher.java rename to libraries/launcher/legacy/net/minecraft/Launcher.java diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java similarity index 98% rename from libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java index c215e7fe0..553b07eb1 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java @@ -52,7 +52,7 @@ * limitations under the License. */ -package org.prismlauncher.launcher.impl.legacy; +package org.prismlauncher.legacy; import java.applet.Applet; import java.awt.Dimension; @@ -74,7 +74,7 @@ import org.prismlauncher.utils.logging.Log; import net.minecraft.Launcher; -public final class LegacyFrame extends JFrame { +final class LegacyFrame extends JFrame { private static final long serialVersionUID = 1L; diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java similarity index 76% rename from libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java index d349177b2..dae737224 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java @@ -53,11 +53,15 @@ * limitations under the License. */ -package org.prismlauncher.launcher.impl.legacy; +package org.prismlauncher.legacy; +import java.applet.Applet; import java.io.File; import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.Collections; import java.util.List; @@ -69,7 +73,7 @@ import org.prismlauncher.utils.logging.Log; /** * Used to launch old versions that support applets. */ -public final class LegacyLauncher extends AbstractLauncher { +final class LegacyLauncher extends AbstractLauncher { private final String user, session; private final String title; @@ -94,11 +98,9 @@ public final class LegacyLauncher extends AbstractLauncher { @Override public void launch() throws Throwable { Class main = ClassLoader.getSystemClassLoader().loadClass(mainClassName); - Field gameDirField = ReflectionUtils.findMinecraftGameDirField(main); + Field gameDirField = findMinecraftGameDirField(main); - if (gameDirField == null) - Log.warning("Could not find Minecraft folder field"); - else { + if (gameDirField != null) { gameDirField.setAccessible(true); gameDirField.set(null, new File(gameDir)); } @@ -107,7 +109,7 @@ public final class LegacyLauncher extends AbstractLauncher { System.setProperty("minecraft.applet.TargetDirectory", gameDir); try { - LegacyFrame window = new LegacyFrame(title, ReflectionUtils.createAppletClass(appletClass)); + LegacyFrame window = new LegacyFrame(title, createAppletClass(appletClass)); window.start(user, session, width, height, maximize, serverAddress, serverPort, gameArgs.contains("--demo")); @@ -123,4 +125,37 @@ public final class LegacyLauncher extends AbstractLauncher { method.invokeExact(gameArgs.toArray(new String[0])); } + private static Applet createAppletClass(String clazz) throws Throwable { + Class appletClass = ClassLoader.getSystemClassLoader().loadClass(clazz); + + MethodHandle appletConstructor = MethodHandles.lookup().findConstructor(appletClass, MethodType.methodType(void.class)); + return (Applet) appletConstructor.invoke(); + } + + private static Field findMinecraftGameDirField(Class clazz) { + Log.debug("Resolving minecraft game directory field"); + + // search for private static File + for (Field field : clazz.getDeclaredFields()) { + if (field.getType() != File.class) { + continue; + } + + int fieldModifiers = field.getModifiers(); + + if (!Modifier.isStatic(fieldModifiers)) + continue; + + if (!Modifier.isPrivate(fieldModifiers)) + continue; + + if (Modifier.isFinal(fieldModifiers)) + continue; + + return field; + } + + return null; + } + } diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java new file mode 100644 index 000000000..f2e65087f --- /dev/null +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java @@ -0,0 +1,17 @@ +package org.prismlauncher.legacy; + +import org.prismlauncher.launcher.Launcher; +import org.prismlauncher.legacy.fix.online.OnlineFixes; +import org.prismlauncher.utils.Parameters; + +public final class LegacyProxy { + + public static Launcher createLauncher(Parameters params) { + return new LegacyLauncher(params); + } + + public static void applyOnlineFixes(Parameters parameters) { + OnlineFixes.apply(parameters); + } + +} diff --git a/libraries/launcher/org/prismlauncher/fix/online/Handler.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java similarity index 96% rename from libraries/launcher/org/prismlauncher/fix/online/Handler.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java index 618683119..02a325e37 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/Handler.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/Handler.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.fix.online; +package org.prismlauncher.legacy.fix.online; import java.io.IOException; import java.net.Proxy; @@ -41,7 +41,7 @@ import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; -import org.prismlauncher.utils.url.UrlUtils; +import org.prismlauncher.legacy.utils.url.UrlUtils; final class Handler extends URLStreamHandler { diff --git a/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java similarity index 89% rename from libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java index 5f9ff1014..d4e4c27d5 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/OnlineFixes.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java @@ -33,15 +33,16 @@ * along with this program. If not, see . */ -package org.prismlauncher.fix.online; +package org.prismlauncher.legacy.fix.online; import java.net.URL; import java.net.URLStreamHandler; import java.net.URLStreamHandlerFactory; -import org.prismlauncher.utils.Base64; +import org.prismlauncher.legacy.utils.Base64; +import org.prismlauncher.legacy.utils.url.UrlUtils; +import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.logging.Log; -import org.prismlauncher.utils.url.UrlUtils; /** * Fixes skins by redirecting to other URLs. @@ -51,7 +52,10 @@ import org.prismlauncher.utils.url.UrlUtils; */ public final class OnlineFixes implements URLStreamHandlerFactory { - public static void apply() { + public static void apply(Parameters params) { + if (!"true".equals(params.getString("onlineFixes", null))) + return; + if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); diff --git a/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java similarity index 94% rename from libraries/launcher/org/prismlauncher/fix/online/SkinFix.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java index b05e1f208..1c4888312 100644 --- a/libraries/launcher/org/prismlauncher/fix/online/SkinFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java @@ -1,4 +1,4 @@ -package org.prismlauncher.fix.online; +package org.prismlauncher.legacy.fix.online; import java.awt.AlphaComposite; import java.awt.Graphics2D; @@ -12,10 +12,8 @@ import java.net.URLConnection; import javax.imageio.ImageIO; -import org.prismlauncher.utils.api.MojangApi; -import org.prismlauncher.utils.api.Texture; -import org.prismlauncher.utils.url.CustomUrlConnection; -import org.prismlauncher.utils.url.UrlUtils; +import org.prismlauncher.legacy.utils.api.*; +import org.prismlauncher.legacy.utils.url.*; final class SkinFix { diff --git a/libraries/launcher/org/prismlauncher/utils/Base64.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/Base64.java similarity index 98% rename from libraries/launcher/org/prismlauncher/utils/Base64.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/Base64.java index 508df872d..3f7852e74 100644 --- a/libraries/launcher/org/prismlauncher/utils/Base64.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/Base64.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils; +package org.prismlauncher.legacy.utils; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; diff --git a/libraries/launcher/org/prismlauncher/exception/JsonParseException.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java similarity index 97% rename from libraries/launcher/org/prismlauncher/exception/JsonParseException.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java index 5983eb883..6ba8d10b6 100644 --- a/libraries/launcher/org/prismlauncher/exception/JsonParseException.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.exception; +package org.prismlauncher.legacy.utils; import java.io.IOException; diff --git a/libraries/launcher/org/prismlauncher/utils/JsonParser.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java similarity index 99% rename from libraries/launcher/org/prismlauncher/utils/JsonParser.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java index 5f10e9a7b..4339f98e6 100644 --- a/libraries/launcher/org/prismlauncher/utils/JsonParser.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils; +package org.prismlauncher.legacy.utils; import java.io.IOException; import java.io.InputStream; @@ -46,8 +46,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.prismlauncher.exception.JsonParseException; - /** * Single-file JSON parser to allow for usage in versions without GSON. */ diff --git a/libraries/launcher/org/prismlauncher/utils/api/MojangApi.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java similarity index 96% rename from libraries/launcher/org/prismlauncher/utils/api/MojangApi.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java index dc2794107..6159a4e72 100644 --- a/libraries/launcher/org/prismlauncher/utils/api/MojangApi.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java @@ -33,15 +33,14 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils.api; +package org.prismlauncher.legacy.utils.api; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Map; -import org.prismlauncher.utils.Base64; -import org.prismlauncher.utils.JsonParser; +import org.prismlauncher.legacy.utils.*; /** * Basic access to Mojang's Minecraft API. diff --git a/libraries/launcher/org/prismlauncher/utils/api/Texture.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/Texture.java similarity index 97% rename from libraries/launcher/org/prismlauncher/utils/api/Texture.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/Texture.java index 1b5c2204e..838a2758e 100644 --- a/libraries/launcher/org/prismlauncher/utils/api/Texture.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/Texture.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils.api; +package org.prismlauncher.legacy.utils.api; import java.net.URL; diff --git a/libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java similarity index 98% rename from libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java index 8bc0cff11..36ac235f3 100644 --- a/libraries/launcher/org/prismlauncher/utils/url/CustomUrlConnection.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils.url; +package org.prismlauncher.legacy.utils.url; import java.io.ByteArrayInputStream; import java.io.IOException; diff --git a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java similarity index 98% rename from libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java index 69ebbd50b..85c35eb17 100644 --- a/libraries/launcher/org/prismlauncher/utils/url/UrlUtils.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.utils.url; +package org.prismlauncher.legacy.utils.url; import java.io.IOException; import java.lang.invoke.MethodHandle; diff --git a/libraries/launcher/org/prismlauncher/EntryPoint.java b/libraries/launcher/org/prismlauncher/EntryPoint.java index 88ecb48ce..a2d9a5f78 100644 --- a/libraries/launcher/org/prismlauncher/EntryPoint.java +++ b/libraries/launcher/org/prismlauncher/EntryPoint.java @@ -59,10 +59,9 @@ import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import org.prismlauncher.exception.ParseException; -import org.prismlauncher.fix.Fixes; import org.prismlauncher.launcher.Launcher; import org.prismlauncher.launcher.impl.StandardLauncher; -import org.prismlauncher.launcher.impl.legacy.LegacyLauncher; +import org.prismlauncher.legacy.LegacyProxy; import org.prismlauncher.utils.Parameters; import org.prismlauncher.utils.logging.Log; @@ -108,7 +107,7 @@ public final class EntryPoint { } try { - Fixes.apply(params); + LegacyProxy.applyOnlineFixes(params); Launcher launcher; String type = params.getString("launcher"); @@ -119,7 +118,7 @@ public final class EntryPoint { break; case "legacy": - launcher = new LegacyLauncher(params); + launcher = LegacyProxy.createLauncher(params); break; default: diff --git a/libraries/launcher/org/prismlauncher/fix/Fixes.java b/libraries/launcher/org/prismlauncher/fix/Fixes.java deleted file mode 100644 index 429964ad9..000000000 --- a/libraries/launcher/org/prismlauncher/fix/Fixes.java +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -/* - * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 TheKodeToad - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Linking this library statically or dynamically with other modules is - * making a combined work based on this library. Thus, the terms and - * conditions of the GNU General Public License cover the whole - * combination. - * - * As a special exception, the copyright holders of this library give - * you permission to link this library with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also meet, - * for each linked independent module, the terms and conditions of the - * license of that module. An independent module is a module which is - * not derived from or based on this library. If you modify this - * library, you may extend this exception to your version of the - * library, but you are not obliged to do so. If you do not wish to do - * so, delete this exception statement from your version. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.prismlauncher.fix; - -import org.prismlauncher.fix.online.OnlineFixes; -import org.prismlauncher.utils.Parameters; - -public final class Fixes { - - public static void apply(Parameters params) { - if ("true".equalsIgnoreCase(params.getString("onlineFixes", null))) - OnlineFixes.apply(); - } - -} diff --git a/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java b/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java new file mode 100644 index 000000000..9b96d7179 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java @@ -0,0 +1,17 @@ +package org.prismlauncher.legacy; + +import org.prismlauncher.launcher.Launcher; +import org.prismlauncher.utils.Parameters; + +// used as a fallback if NewLaunchLegacy is not on the classpath +// if it is, this class will be replaced +public final class LegacyProxy { + + public static Launcher createLauncher(Parameters params) { + throw new AssertionError("NewLaunchLegacy is not loaded"); + } + + public static void applyOnlineFixes(Parameters params) { + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java index dd212ef93..1925bf049 100644 --- a/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java +++ b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java @@ -54,76 +54,15 @@ package org.prismlauncher.utils; -import java.applet.Applet; -import java.io.File; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -import org.prismlauncher.utils.logging.Log; public final class ReflectionUtils { private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final ClassLoader LOADER = ClassLoader.getSystemClassLoader(); - /** - * Construct a Java applet by its class name. - * - * @param clazz The class name - * @return The applet instance - * @throws Throwable - */ - public static Applet createAppletClass(String clazz) throws Throwable { - Class appletClass = LOADER.loadClass(clazz); - - MethodHandle appletConstructor = LOOKUP.findConstructor(appletClass, MethodType.methodType(void.class)); - return (Applet) appletConstructor.invoke(); - } - - /** - * Best guess of the game directory field within net.minecraft.client.Minecraft. - * Designed for legacy versions - newer versions do not use a static field. - * - * @param clazz The class - * @return The first field matching criteria - */ - public static Field findMinecraftGameDirField(Class clazz) { - Log.debug("Resolving minecraft game directory field"); - - // search for private static File - for (Field field : clazz.getDeclaredFields()) { - if (field.getType() != File.class) { - continue; - } - - int fieldModifiers = field.getModifiers(); - - if (!Modifier.isStatic(fieldModifiers)) { - Log.debug("Rejecting field " + field.getName() + " because it is not static"); - continue; - } - - if (!Modifier.isPrivate(fieldModifiers)) { - Log.debug("Rejecting field " + field.getName() + " because it is not private"); - continue; - } - - if (Modifier.isFinal(fieldModifiers)) { - Log.debug("Rejecting field " + field.getName() + " because it is final"); - continue; - } - - Log.debug("Identified field " + field.getName() + " to match conditions for game directory field"); - - return field; - } - - return null; - } - /** * Gets the main method within a class. * diff --git a/libraries/launcher/org/prismlauncher/utils/logging/Log.java b/libraries/launcher/org/prismlauncher/utils/logging/Log.java index e3aa538b2..0c5dc3009 100644 --- a/libraries/launcher/org/prismlauncher/utils/logging/Log.java +++ b/libraries/launcher/org/prismlauncher/utils/logging/Log.java @@ -45,7 +45,7 @@ import java.io.PrintStream; public final class Log { // original before possibly overridden by MC - private static final PrintStream OUT = new PrintStream(System.out), ERR = new PrintStream(System.err); + private static final PrintStream OUT = new PrintStream(System.out), ERR = new PrintStream(System.err); private static final boolean DEBUG = Boolean.getBoolean("org.prismlauncher.debug"); public static void launcher(String message) { From be7f81421ab98b439a4b285dd47bd293b61dc860 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 6 Jan 2023 10:45:59 +0000 Subject: [PATCH 14/26] Finishing touches Signed-off-by: TheKodeToad --- .../launcher/legacy/net/minecraft/Launcher.java | 5 ++--- .../org/prismlauncher/legacy/LegacyFrame.java | 2 +- .../prismlauncher/legacy/LegacyLauncher.java | 14 ++++++-------- .../org/prismlauncher/legacy/LegacyProxy.java | 1 + .../legacy/fix/online/OnlineFixes.java | 8 ++++---- .../legacy/fix/online/SkinFix.java | 15 +++++++++------ .../prismlauncher/legacy/utils/JsonParser.java | 17 +++++++++-------- .../legacy/utils/api/MojangApi.java | 11 ++++++----- 8 files changed, 38 insertions(+), 35 deletions(-) diff --git a/libraries/launcher/legacy/net/minecraft/Launcher.java b/libraries/launcher/legacy/net/minecraft/Launcher.java index 646e2e3ea..4c7fcb6ee 100644 --- a/libraries/launcher/legacy/net/minecraft/Launcher.java +++ b/libraries/launcher/legacy/net/minecraft/Launcher.java @@ -93,12 +93,11 @@ public final class Launcher extends Applet implements AppletStub { try { if (documentBase == null) { - if (applet.getClass().getPackage().getName().startsWith("com.mojang.")) { + if (applet.getClass().getPackage().getName().startsWith("com.mojang")) // Special case only for Classic versions documentBase = new URL("http://www.minecraft.net:80/game/"); - } else { + else documentBase = new URL("http://www.minecraft.net/game/"); - } } } catch (MalformedURLException e) { throw new AssertionError(e); diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java index 553b07eb1..49a126e7f 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyFrame.java @@ -131,7 +131,7 @@ final class LegacyFrame extends JFrame { launcher.setParameter("username", user); launcher.setParameter("sessionid", session); - launcher.setParameter("stand-alone", true); // Show the quit button. TODO: why won't this work? + launcher.setParameter("stand-alone", true); // Show the quit button. This often doesn't seem to work. launcher.setParameter("haspaid", true); // Some old versions need this for world saves to work. launcher.setParameter("demo", demo); launcher.setParameter("fullscreen", false); diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java index dae737224..f84b971cb 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java @@ -71,7 +71,7 @@ import org.prismlauncher.utils.ReflectionUtils; import org.prismlauncher.utils.logging.Log; /** - * Used to launch old versions that support applets. + * Used to launch old versions which support applets. */ final class LegacyLauncher extends AbstractLauncher { @@ -119,8 +119,8 @@ final class LegacyLauncher extends AbstractLauncher { } } - // find and invoke the main method, this time without size parameters - // in all versions that support applets, these are ignored + // find and invoke the main method, this time without size parameters - in all + // versions that support applets, these are ignored MethodHandle method = ReflectionUtils.findMainMethod(main); method.invokeExact(gameArgs.toArray(new String[0])); } @@ -128,18 +128,16 @@ final class LegacyLauncher extends AbstractLauncher { private static Applet createAppletClass(String clazz) throws Throwable { Class appletClass = ClassLoader.getSystemClassLoader().loadClass(clazz); - MethodHandle appletConstructor = MethodHandles.lookup().findConstructor(appletClass, MethodType.methodType(void.class)); + MethodHandle appletConstructor = MethodHandles.lookup().findConstructor(appletClass, + MethodType.methodType(void.class)); return (Applet) appletConstructor.invoke(); } private static Field findMinecraftGameDirField(Class clazz) { - Log.debug("Resolving minecraft game directory field"); - // search for private static File for (Field field : clazz.getDeclaredFields()) { - if (field.getType() != File.class) { + if (field.getType() != File.class) continue; - } int fieldModifiers = field.getModifiers(); diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java index f2e65087f..11c9d6692 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java @@ -4,6 +4,7 @@ import org.prismlauncher.launcher.Launcher; import org.prismlauncher.legacy.fix.online.OnlineFixes; import org.prismlauncher.utils.Parameters; +// implementation of LegacyProxy public final class LegacyProxy { public static Launcher createLauncher(Parameters params) { diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java index d4e4c27d5..56849cdd9 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java @@ -62,12 +62,12 @@ public final class OnlineFixes implements URLStreamHandlerFactory { return; } - try { + try { URL.setURLStreamHandlerFactory(new OnlineFixes()); - } catch (Error e) { + } catch (Error e) { Log.warning("Cannot apply skin fix: URLStreamHandlerFactory is already set"); - Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); - } + Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + } } @Override diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java index 1c4888312..7cfd297aa 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java @@ -12,8 +12,10 @@ import java.net.URLConnection; import javax.imageio.ImageIO; -import org.prismlauncher.legacy.utils.api.*; -import org.prismlauncher.legacy.utils.url.*; +import org.prismlauncher.legacy.utils.api.MojangApi; +import org.prismlauncher.legacy.utils.api.Texture; +import org.prismlauncher.legacy.utils.url.CustomUrlConnection; +import org.prismlauncher.legacy.utils.url.UrlUtils; final class SkinFix { @@ -25,7 +27,8 @@ final class SkinFix { String capeOwner = findCapeOwner(address); if (capeOwner != null) { - // since we do not need to process the image, open a direct connection bypassing Handler + // since we do not need to process the image, open a direct connection bypassing + // Handler Texture texture = MojangApi.getTexture(MojangApi.getUuid(capeOwner), "CAPE"); if (texture == null) return null; @@ -45,7 +48,7 @@ final class SkinFix { try (InputStream in = connection.getInputStream()) { // thank you craftycodie! // this is heavily based on - // https://github.com/Mojang/LegacyLauncher/pull/33/files#diff-b61023785a9260651ca0a223573ea9acb5be5eec478bff626dafb7abe13ffebaR99 + // https://github.com/craftycodie/MineOnline/blob/4f4f86f9d051e0a6fd7ff0b95b2a05f7437683d7/src/main/java/gg/codie/mineonline/gui/textures/TextureHelper.java#L17 BufferedImage image = ImageIO.read(in); Graphics2D graphics = image.createGraphics(); graphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); @@ -59,7 +62,7 @@ final class SkinFix { } if (texture.isSlim()) { - // convert slim to wide + // convert slim to classic subimage = image.getSubimage(45, 16, 9, 16); graphics.drawImage(subimage, 46, 16, null); @@ -72,7 +75,7 @@ final class SkinFix { graphics.dispose(); - // crop the image + // crop the image - old versions disregard all secondary layers besides the hat ByteArrayOutputStream out = new ByteArrayOutputStream(); image = image.getSubimage(0, 0, 64, 32); ImageIO.write(image, "png", out); diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java index 4339f98e6..73258fd09 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java @@ -47,7 +47,8 @@ import java.util.List; import java.util.Map; /** - * Single-file JSON parser to allow for usage in versions without GSON. + * A lightweight portable JSON parser used instead of GSON since it is not + * available in a lot of versions. */ public final class JsonParser { @@ -55,15 +56,15 @@ public final class JsonParser { private char[] buffer; private int pos, length; - public static Object parse(String in) throws JsonParseException, IOException { + public static Object parse(String in) throws IOException { return parse(new StringReader(in)); } - public static Object parse(InputStream in) throws JsonParseException, IOException { + public static Object parse(InputStream in) throws IOException { return parse(new InputStreamReader(in, StandardCharsets.UTF_8)); } - public static Object parse(Reader in) throws JsonParseException, IOException { + public static Object parse(Reader in) throws IOException { return new JsonParser(in).readSingleValue(); } @@ -336,6 +337,7 @@ public final class JsonParser { if (character() == '0') { result.append((char) character()); read(); + if (isDigit()) throw new JsonParseException("Found superfluous leading zero"); } else if (!isDigit()) @@ -395,11 +397,10 @@ public final class JsonParser { if (read() == 'r' && read() == 'u' && read() == 'e') { return true; } - } else if (character() == 'f') { - if (read() == 'a' && read() == 'l' && read() == 's' && read() == 'e') { - return false; - } + } else if (character() == 'f' && read() == 'a' && read() == 'l' && read() == 's' && read() == 'e') { + return false; } + return null; } diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java index 6159a4e72..e15ebe7f5 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java @@ -40,10 +40,11 @@ import java.io.InputStream; import java.net.URL; import java.util.Map; -import org.prismlauncher.legacy.utils.*; +import org.prismlauncher.legacy.utils.Base64; +import org.prismlauncher.legacy.utils.JsonParser; /** - * Basic access to Mojang's Minecraft API. + * Basic wrapper for Mojang's Minecraft API. */ @SuppressWarnings("unchecked") public final class MojangApi { @@ -55,18 +56,18 @@ public final class MojangApi { } } - public static Texture getTexture(String player, String name) throws IOException { + public static Texture getTexture(String player, String id) throws IOException { Map map = getTextures(player); if (map != null) { - map = (Map) map.get(name); + map = (Map) map.get(id); if (map == null) return null; URL url = new URL((String) map.get("url")); boolean slim = false; - if (name.equals("SKIN")) { + if (id.equals("SKIN")) { map = (Map) map.get("metadata"); if (map != null && "slim".equals(map.get("model"))) slim = true; From 52b3a54e4bdbe0be48429ae3744fa6a0cb2fa8f2 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 8 Jan 2023 15:36:36 +0000 Subject: [PATCH 15/26] Fix cloaks conflicting with join server endpoint Signed-off-by: TheKodeToad --- .../legacy/org/prismlauncher/legacy/fix/online/SkinFix.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java index 7cfd297aa..1d23c6d14 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java @@ -100,6 +100,9 @@ final class SkinFix { private static String findCapeOwner(URL address) { switch (address.getHost()) { case "www.minecraft.net": + if (!address.getPath().equals("/cloak/get.jsp")) + return null; + return stripIfPrefixed(address.getQuery(), "user="); case "s3.amazonaws.com": From d4b346b7ae7201af3c67d7450ac7144eb486638c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Mon, 9 Jan 2023 10:48:46 +0000 Subject: [PATCH 16/26] Fix oversights Signed-off-by: TheKodeToad --- libraries/launcher/CMakeLists.txt | 4 +- .../org/prismlauncher/legacy/LegacyProxy.java | 52 +++++++++++++++++++ .../legacy/fix/online/SkinFix.java | 52 +++++++++++++++++++ .../legacy/utils/api/MojangApi.java | 2 +- .../utils/{ => json}/JsonParseException.java | 4 +- .../legacy/utils/{ => json}/JsonParser.java | 2 +- .../legacy/utils/url/CustomUrlConnection.java | 4 +- .../org/prismlauncher/legacy/LegacyProxy.java | 52 +++++++++++++++++++ 8 files changed, 164 insertions(+), 8 deletions(-) rename libraries/launcher/legacy/org/prismlauncher/legacy/utils/{ => json}/JsonParseException.java (94%) rename libraries/launcher/legacy/org/prismlauncher/legacy/utils/{ => json}/JsonParser.java (99%) diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index d835dc9a3..7bf160760 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -27,10 +27,10 @@ set(LEGACY_SRC legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java legacy/org/prismlauncher/legacy/fix/online/SkinFix.java legacy/org/prismlauncher/legacy/utils/Base64.java - legacy/org/prismlauncher/legacy/utils/JsonParseException.java - legacy/org/prismlauncher/legacy/utils/JsonParser.java legacy/org/prismlauncher/legacy/utils/api/MojangApi.java legacy/org/prismlauncher/legacy/utils/api/Texture.java + legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java + legacy/org/prismlauncher/legacy/utils/json/JsonParser.java legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java legacy/net/minecraft/Launcher.java diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java index 11c9d6692..34460db10 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyProxy.java @@ -1,3 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.prismlauncher.legacy; import org.prismlauncher.launcher.Launcher; diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java index 1d23c6d14..37dd125a5 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/SkinFix.java @@ -1,3 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2023 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.prismlauncher.legacy.fix.online; import java.awt.AlphaComposite; diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java index e15ebe7f5..e774ee3e1 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/api/MojangApi.java @@ -41,7 +41,7 @@ import java.net.URL; import java.util.Map; import org.prismlauncher.legacy.utils.Base64; -import org.prismlauncher.legacy.utils.JsonParser; +import org.prismlauncher.legacy.utils.json.JsonParser; /** * Basic wrapper for Mojang's Minecraft API. diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java similarity index 94% rename from libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java index 6ba8d10b6..222427016 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParseException.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java @@ -33,11 +33,11 @@ * along with this program. If not, see . */ -package org.prismlauncher.legacy.utils; +package org.prismlauncher.legacy.utils.json; import java.io.IOException; -public class JsonParseException extends IOException { +public final class JsonParseException extends IOException { private static final long serialVersionUID = 1L; diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParser.java similarity index 99% rename from libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java rename to libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParser.java index 73258fd09..db2efc6cd 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/JsonParser.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParser.java @@ -33,7 +33,7 @@ * along with this program. If not, see . */ -package org.prismlauncher.legacy.utils; +package org.prismlauncher.legacy.utils.json; import java.io.IOException; import java.io.InputStream; diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java index 36ac235f3..8a8e3416c 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/CustomUrlConnection.java @@ -40,9 +40,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -public class CustomUrlConnection extends HttpURLConnection { +public final class CustomUrlConnection extends HttpURLConnection { - private InputStream in; + private final InputStream in; public CustomUrlConnection(byte[] data) { this(new ByteArrayInputStream(data)); diff --git a/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java b/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java index 9b96d7179..ec9a1fcc9 100644 --- a/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java +++ b/libraries/launcher/org/prismlauncher/legacy/LegacyProxy.java @@ -1,3 +1,55 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.prismlauncher.legacy; import org.prismlauncher.launcher.Launcher; From bb62c62a03df0431cbc8cad983f0b176a5640264 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 19 Feb 2023 11:37:59 +0000 Subject: [PATCH 17/26] Fix cmark again :facepalm: Signed-off-by: TheKodeToad --- libraries/cmark | 1 + 1 file changed, 1 insertion(+) create mode 160000 libraries/cmark diff --git a/libraries/cmark b/libraries/cmark new file mode 160000 index 000000000..5ba25ff40 --- /dev/null +++ b/libraries/cmark @@ -0,0 +1 @@ +Subproject commit 5ba25ff40eba44c811f79ab6a792baf945b8307c From 6a5e9a59dff7601907f354ff7585dddf1c35206c Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 19 Feb 2023 12:00:18 +0000 Subject: [PATCH 18/26] Fix screwed up ui file Signed-off-by: TheKodeToad --- launcher/ui/pages/instance/InstanceSettingsPage.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 6a73a84c0..f16802c0a 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -648,6 +648,9 @@ + + + <html><head/><body><p>Fixes usages of old online services which are no longer operating by emulating them or redirecting to their modern counterparts.</p><p>This currently only allows modern skins to be used.</p></body></html> From 83c526459886f5d8a2498443cafe5b6823cea2eb Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 10 Mar 2023 11:04:09 +0000 Subject: [PATCH 19/26] Stupidly small skinfixfix as requested by DioEgizio Signed-off-by: TheKodeToad --- .../org/prismlauncher/legacy/utils/json/JsonParseException.java | 2 +- .../legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java index 222427016..bb35cb165 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/json/JsonParseException.java @@ -45,4 +45,4 @@ public final class JsonParseException extends IOException { super(message); } -} \ No newline at end of file +} diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java index 85c35eb17..de9358b16 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/utils/url/UrlUtils.java @@ -107,4 +107,4 @@ public final class UrlUtils { } } -} \ No newline at end of file +} From dfc2b9c76ac0dfeae55759665033539df3f27c2f Mon Sep 17 00:00:00 2001 From: Kode Date: Fri, 21 Apr 2023 20:49:47 +0100 Subject: [PATCH 20/26] thanks flowln! :P Signed-off-by: Kode --- .../org/prismlauncher/legacy/fix/online/OnlineFixes.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java index 56849cdd9..cf35b75d7 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/fix/online/OnlineFixes.java @@ -58,7 +58,7 @@ public final class OnlineFixes implements URLStreamHandlerFactory { if (!UrlUtils.isSupported() || !Base64.isSupported()) { Log.warning("Cannot access the necessary Java internals for skin fix"); - Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + Log.warning("Turning off online fixes in the settings will silence the warnings"); return; } @@ -66,7 +66,7 @@ public final class OnlineFixes implements URLStreamHandlerFactory { URL.setURLStreamHandlerFactory(new OnlineFixes()); } catch (Error e) { Log.warning("Cannot apply skin fix: URLStreamHandlerFactory is already set"); - Log.warning("Turning off legacy skin fix in Settings > Miscellaneous will silence the warnings"); + Log.warning("Turning off online fixes in the settings will silence the warnings"); } } From d48dd7eb6a43351ed181637dae4687163f92ce92 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 4 Aug 2023 16:00:02 +0100 Subject: [PATCH 21/26] Use override-based setting for online fixes Signed-off-by: TheKodeToad --- launcher/Application.cpp | 3 ++ launcher/minecraft/MinecraftInstance.cpp | 6 ++- launcher/ui/pages/global/MinecraftPage.cpp | 5 +++ launcher/ui/pages/global/MinecraftPage.ui | 21 ++++++++- .../pages/instance/InstanceSettingsPage.cpp | 11 +++-- .../ui/pages/instance/InstanceSettingsPage.ui | 43 +++++++++++++------ 6 files changed, 69 insertions(+), 20 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index d6c135de7..bbea34c76 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -614,6 +614,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) // Mod loader settings m_settings->registerSetting("DisableQuiltBeacon", false); + // Legacy settings + m_settings->registerSetting("OnlineFixes", true); + // Native library workarounds m_settings->registerSetting("UseNativeOpenAL", false); m_settings->registerSetting("UseNativeGLFW", false); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index e0e4cdcf0..b4b0b4aa3 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -191,6 +191,10 @@ void MinecraftInstance::loadSpecificSettings() auto modLoaderSettings = m_settings->registerSetting("OverrideModLoaderSettings", false); m_settings->registerOverride(global_settings->getSetting("DisableQuiltBeacon"), modLoaderSettings); + // Legacy-related options + auto legacySettings = m_settings->registerSetting("OverrideLegacySettings", true); + m_settings->registerOverride(global_settings->getSetting("OnlineFixes"), legacySettings); + m_settings->set("InstanceType", "OneSix"); } @@ -202,8 +206,6 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerSetting("UseAccountForInstance", false); m_settings->registerSetting("InstanceAccountId", ""); - m_settings->registerSetting("OnlineFixes", true); - qDebug() << "Instance-type specific settings were loaded!"; setSpecificSettingsLoaded(true); diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp index 954823564..cdab4feb6 100644 --- a/launcher/ui/pages/global/MinecraftPage.cpp +++ b/launcher/ui/pages/global/MinecraftPage.cpp @@ -103,6 +103,9 @@ void MinecraftPage::applySettings() // Mod loader settings s->set("DisableQuiltBeacon", ui->disableQuiltBeaconCheckBox->isChecked()); + + // Legacy settings + s->set("OnlineFixes", ui->onlineFixes->isChecked()); } void MinecraftPage::loadSettings() @@ -143,6 +146,8 @@ void MinecraftPage::loadSettings() ui->quitAfterGameStopCheck->setChecked(s->get("QuitAfterGameStop").toBool()); ui->disableQuiltBeaconCheckBox->setChecked(s->get("DisableQuiltBeacon").toBool()); + + ui->onlineFixes->setChecked(s->get("OnlineFixes").toBool()); } void MinecraftPage::retranslate() diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index a3188dccb..cd0f4fafd 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -198,11 +198,30 @@ + + Disable Quilt loader's beacon for counting monthly active users + Disable Quilt Loader Beacon + + + + + + + + + Legacy settings + + + + - Disable Quilt loader's beacon for counting monthly active users + <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> + + + Enable online fixes diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index 4d3cd16dd..7b019282b 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -290,8 +290,13 @@ void InstanceSettingsPage::applySettings() m_settings->reset("DisableQuiltBeacon"); } - bool onlineFixes = ui->onlineFixes->isChecked(); - m_settings->set("OnlineFixes", onlineFixes); + bool overrideLegacySettings = ui->legacySettingsGroupBox->isChecked(); + m_settings->set("OverrideLegacySettings", overrideLegacySettings); + if (overrideLegacySettings) { + m_settings->set("OnlineFixes", ui->onlineFixes->isChecked()); + } else { + m_settings->reset("OnlineFixes"); + } // FIXME: This should probably be called by a signal instead m_instance->updateRuntimeContext(); @@ -398,8 +403,8 @@ void InstanceSettingsPage::loadSettings() ui->modLoaderSettingsGroupBox->setChecked(m_settings->get("OverrideModLoaderSettings").toBool()); ui->disableQuiltBeaconCheckBox->setChecked(m_settings->get("DisableQuiltBeacon").toBool()); + ui->legacySettingsGroupBox->setChecked(m_settings->get("OverrideLegacySettings").toBool()); ui->onlineFixes->setChecked(m_settings->get("OnlineFixes").toBool()); - ui->onlineFixes->setVisible(m_instance->traits().contains("legacyServices")); } void InstanceSettingsPage::on_javaDetectBtn_clicked() diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 9018659aa..4548b2e72 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -543,23 +543,48 @@ + + Mod loader settings + true false - - Mod loader settings - + + Disable Quilt loader's beacon for counting monthly active users + Disable Quilt Loader Beacon + + + + + + + + + Legacy settings + + + true + + + false + + + + - Disable Quilt loader's beacon for counting monthly active users + <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> + + + Enable online fixes @@ -668,16 +693,6 @@ - - - - <html><head/><body><p>Fixes usages of old online services which are no longer operating by emulating them or redirecting to their modern counterparts.</p><p>This currently only allows modern skins to be used.</p></body></html> - - - Enable online fixes - - - From 347228a24613f5ec7ce63341a929a8a88bb2a6b4 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 2 Sep 2023 22:29:26 +0100 Subject: [PATCH 22/26] Legacy settings override default -> false Signed-off-by: TheKodeToad --- launcher/minecraft/MinecraftInstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index bc8d2db58..52416fe15 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -185,7 +185,7 @@ void MinecraftInstance::loadSpecificSettings() m_settings->registerOverride(global_settings->getSetting("QuitAfterGameStop"), miscellaneousOverride); // Legacy-related options - auto legacySettings = m_settings->registerSetting("OverrideLegacySettings", true); + auto legacySettings = m_settings->registerSetting("OverrideLegacySettings", false); m_settings->registerOverride(global_settings->getSetting("OnlineFixes"), legacySettings); m_settings->set("InstanceType", "OneSix"); From 19b5a5e00badad2630e2e4ae431d792a06bfe6b6 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sat, 2 Sep 2023 22:38:14 +0100 Subject: [PATCH 23/26] Remove final conflict - kept by mistake Signed-off-by: TheKodeToad --- .../legacy/org/prismlauncher/legacy/LegacyLauncher.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java index 90244e1ae..02f77e039 100644 --- a/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java +++ b/libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java @@ -122,7 +122,6 @@ final class LegacyLauncher extends AbstractLauncher { MethodHandle method = ReflectionUtils.findMainMethod(main); method.invokeExact(gameArgs.toArray(new String[0])); } -<<<<<<< HEAD:libraries/launcher/legacy/org/prismlauncher/legacy/LegacyLauncher.java private static Applet createAppletClass(String clazz) throws Throwable { Class appletClass = ClassLoader.getSystemClassLoader().loadClass(clazz); @@ -153,7 +152,4 @@ final class LegacyLauncher extends AbstractLauncher { return null; } - -======= ->>>>>>> upstream/develop:libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java } From d49f81d132f57089361dd7f8af0e0ef1781028e0 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Fri, 6 Oct 2023 11:27:04 +0100 Subject: [PATCH 24/26] Drop leftover mod loader settings I messed up the merge. Signed-off-by: TheKodeToad --- launcher/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 6209acf76..e5bbf2f30 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -579,9 +579,6 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("IgnoreJavaCompatibility", false); m_settings->registerSetting("IgnoreJavaWizard", false); - // Mod loader settings - m_settings->registerSetting("DisableQuiltBeacon", false); - // Legacy settings m_settings->registerSetting("OnlineFixes", true); From 7112d04df58e3cdf1e149157fe133f76c888da5e Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 15 Oct 2023 14:11:08 +0100 Subject: [PATCH 25/26] Mark setting as optional Signed-off-by: TheKodeToad --- launcher/Application.cpp | 2 +- launcher/ui/pages/global/MinecraftPage.ui | 4 ++-- launcher/ui/pages/instance/InstanceSettingsPage.ui | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/launcher/Application.cpp b/launcher/Application.cpp index e5bbf2f30..73f594d17 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -580,7 +580,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_settings->registerSetting("IgnoreJavaWizard", false); // Legacy settings - m_settings->registerSetting("OnlineFixes", true); + m_settings->registerSetting("OnlineFixes", false); // Native library workarounds m_settings->registerSetting("UseNativeOpenAL", false); diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index 79785fc92..2a3c0d96d 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -138,7 +138,7 @@ - + Show time spent playing in hours @@ -209,7 +209,7 @@ <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> - Enable online fixes + Enable online fixes (experimental) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index f4f4c5a9d..20992df6d 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -39,7 +39,7 @@ QTabWidget::Rounded - 0 + 5 @@ -601,7 +601,7 @@ <html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>This currently allows modern skins to be used.</p></body></html> - Enable online fixes + Enable online fixes (experimental) From 6fb7a98901784ecb1052db2aa8e0dca1b3f0d920 Mon Sep 17 00:00:00 2001 From: TheKodeToad Date: Sun, 15 Oct 2023 14:45:05 +0100 Subject: [PATCH 26/26] =?UTF-8?q?Fix=20small=20mistake=20=F0=9F=98=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: TheKodeToad --- launcher/ui/pages/instance/InstanceSettingsPage.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index 20992df6d..8defaccb3 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -39,7 +39,7 @@ QTabWidget::Rounded - 5 + 0