1
0
mirror of https://github.com/GeyserMC/PackConverter.git synced 2026-01-04 15:31:36 +00:00

Resolve some reviews, support asset downloading for when we need that

This commit is contained in:
Aurora
2025-07-16 15:10:01 +01:00
parent 7a259d886c
commit 317d38fbb2
3 changed files with 241 additions and 6 deletions

View File

@@ -118,6 +118,9 @@ public class FontTransformer implements TextureTransformer {
}
static {
// These mappings were mostly found by manually work and checking if the unicodes match correctly
// Some characters were found just by seeing they completely match between default8 (bedrock) and ascii (java)
// Manual stuff...
MAPPINGS.add(new FontMapping("accented", 0, 0));
MAPPINGS.add(new FontMapping("accented", 1, 0));

View File

@@ -26,6 +26,8 @@
package org.geysermc.pack.converter.util;
import com.google.gson.*;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.file.PathUtils;
import org.geysermc.pack.converter.converter.texture.transformer.type.OverlayTransformer;
@@ -37,13 +39,16 @@ import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.stream.Stream;
public final class VanillaPackProvider {
private static final String JAR_DOWNLOAD = "https://piston-data.mojang.com/v1/objects/%s/client.jar";
private static final String JAR_HASH = "a2db1ea98c37b2d00c83f6867fb8bb581a593e07";
private static final Gson GSON = new GsonBuilder()
.setPrettyPrinting().create();
private static final Map<String, Asset> ASSET_MAP = new HashMap<>();
private static final List<String> REQUIRED_ASSETS = List.of(); // While not used yet, it's possible we will need other assets as some point
/**
* Downloads the vanilla jar from Mojang's servers.
@@ -59,12 +64,56 @@ public final class VanillaPackProvider {
try {
// Download vanilla jar
log.info("Downloading vanilla jar...");
PathUtils.copyFile(new URL(String.format(JAR_DOWNLOAD, JAR_HASH)), path);
log.info("Fetching vanilla jar file download...");
// Get the version manifest from Mojang
VersionManifest versionManifest = GSON.fromJson(
WebUtils.getBody("https://launchermeta.mojang.com/mc/game/version_manifest.json"), VersionManifest.class);
// Get the url for the latest version of the games manifest
String latestInfoURL = "";
for (Version version : versionManifest.getVersions()) {
if (version.getId().equals("1.21.7")) { // TODO De-hardcode this
latestInfoURL = version.getUrl();
break;
}
}
// Make sure we definitely got a version
if (latestInfoURL.isEmpty()) {
throw new IOException("Unable to find a valid version!");
}
// Get the individual version manifest
VersionInfo versionInfo = GSON.fromJson(WebUtils.getBody(latestInfoURL), VersionInfo.class);
// Get the client jar for use when downloading the en_us locale
log.debug(GSON.toJson(versionInfo.getDownloads()));
VersionDownload clientJarInfo = versionInfo.getDownloads().get("client");
log.debug(GSON.toJson(clientJarInfo));
JsonObject assets = JsonParser.parseString(WebUtils.getBody(versionInfo.getAssetIndex().getUrl())).getAsJsonObject().get("objects").getAsJsonObject();
// Put each asset into an array for use later
for (Map.Entry<String, JsonElement> entry : assets.entrySet()) {
if (!REQUIRED_ASSETS.contains(entry.getKey())) {
// No need to cache this asset, we don't use it
continue;
}
Asset asset = GSON.fromJson(entry.getValue(), Asset.class);
ASSET_MAP.put(entry.getKey(), asset);
}
log.info("Vanilla jar file found! Downloading vanilla jar...");
PathUtils.copyFile(new URL(clientJarInfo.url), path);
log.info("Downloaded vanilla jar successfully!");
log.info("Removing unneeded assets from the vanilla jar...");
// Clean the jar
clean(path, log);
log.info("Removed unneeded assets from the vanilla jar!");
} catch (IOException e) {
log.error("Error downloading vanilla jar", e);
}
@@ -136,6 +185,94 @@ public final class VanillaPackProvider {
}
});
}
log.info("Applying assets...");
for (Map.Entry<String, Asset> asset : ASSET_MAP.entrySet()) {
String bytes2 = asset.getValue().hash.substring(0, 2);
PathUtils.copyFile(
new URL("https://resources.download.minecraft.net/%s/%s"
.formatted(bytes2, asset.getValue().hash)),
rootPath.resolve("assets/" + asset.getKey())
);
Files.write(
rootPath.resolve("assets/" + asset.getKey()),
IOUtils.toByteArray(builtinEntity)
);
}
});
}
@Getter
static class VersionManifest {
private LatestVersion latest;
private List<Version> versions;
}
@Getter
static class LatestVersion {
private String release;
private String snapshot;
}
@Getter
static class Version {
private String id;
private String type;
private String url;
private String time;
private String releaseTime;
}
@Getter
static class VersionInfo {
private String id;
private String type;
private String time;
private String releaseTime;
private AssetIndex assetIndex;
private Map<String, VersionDownload> downloads;
}
@Getter
static class VersionDownload {
private String sha1;
private int size;
private String url;
}
@Getter
static class AssetIndex {
private String id;
private String sha1;
private int size;
private int totalSize;
private String url;
}
@Getter
public static class Asset {
private String hash;
private int size;
}
}

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2025 GeyserMC. http://geysermc.org
*
* 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.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/PackConverter
*
*/
package org.geysermc.pack.converter.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;
public class WebUtils {
/**
* Makes a web request to the given URL and returns the body as a string
*
* @param reqURL URL to fetch
* @return body content or
* @throws IOException / a wrapped UnknownHostException for nicer errors.
*/
public static String getBody(String reqURL) throws IOException {
try {
URL url = new URL(reqURL);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", getUserAgent()); // Otherwise Java 8 fails on checking updates
con.setConnectTimeout(10000);
con.setReadTimeout(10000);
return connectionToString(con);
} catch (UnknownHostException e) {
throw new IllegalStateException("Unable to resolve requested url (%s)! Are you offline?".formatted(reqURL), e);
}
}
/**
* Get the string output from the passed {@link HttpURLConnection}
*
* @param con The connection to get the string from
* @return The body of the returned page
* @throws IOException If the request fails
*/
private static String connectionToString(HttpURLConnection con) throws IOException {
// Send the request (we dont use this but its required for getErrorStream() to work)
con.getResponseCode();
// Read the error message if there is one if not just read normally
InputStream inputStream = con.getErrorStream();
if (inputStream == null) {
inputStream = con.getInputStream();
}
StringBuilder content = new StringBuilder();
try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) {
String inputLine;
while ((inputLine = in.readLine()) != null) {
content.append(inputLine);
content.append("\n");
}
con.disconnect();
}
return content.toString();
}
public static String getUserAgent() {
return "Geyser-PackConverter/3.3.2-SNAPSHOT"; // TODO Pull this from buildscript, BuildConstants?
}
}