Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ java {
targetCompatibility = JavaVersion.VERSION_1_8
}

tasks.withType<JavaCompile> {
options.encoding = "UTF-8"
}

tasks.shadowJar {
manifest {
attributes(
Expand Down
95 changes: 83 additions & 12 deletions src/main/java/i18nupdatemod/I18nUpdateMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@
import i18nupdatemod.entity.GameAssetDetail;
import i18nupdatemod.util.FileUtil;
import i18nupdatemod.util.Log;
import org.jetbrains.annotations.NotNull;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand All @@ -27,12 +30,22 @@ public class I18nUpdateMod {

public static final Gson GSON = new Gson();

public static void init(Path minecraftPath, String minecraftVersion, String loader) {
public static void init(Path minecraftPath, String minecraftVersion, String loader, @NotNull HashSet<String> modDomainsSet) {
long startTime = System.nanoTime();
try (InputStream is = I18nUpdateMod.class.getResourceAsStream("/i18nMetaData.json")) {
MOD_VERSION = GSON.fromJson(new InputStreamReader(is), JsonObject.class).get("version").getAsString();
} catch (Exception e) {
Log.warning("Error getting version: " + e);
}

//Log.debug("modList from loader:" + modDomainsSet);
if ("Forge".equals(loader)) {
modDomainsSet = getModDomainsFromModsFolder(minecraftPath, minecraftVersion, loader);
//Log.debug("modList from mods folder: " + modDomainsSet);

}
modDomainsSet.remove("i18nupdatemod");

Log.info(String.format("I18nUpdate Mod %s is loaded in %s with %s", MOD_VERSION, minecraftVersion, loader));
Log.debug(String.format("Minecraft path: %s", minecraftPath));
String localStorage = getLocalStoragePos(minecraftPath);
Expand Down Expand Up @@ -61,28 +74,26 @@ public static void init(Path minecraftPath, String minecraftVersion, String load

//Update resource pack
List<ResourcePack> languagePacks = new ArrayList<>();
boolean convertNotNeed = assets.downloads.size() == 1 && assets.downloads.get(0).targetVersion.equals(minecraftVersion);
String applyFileName = assets.downloads.get(0).fileName;
for (GameAssetDetail.AssetDownloadDetail it : assets.downloads) {
FileUtil.setTemporaryDirPath(Paths.get(localStorage, "." + MOD_ID, it.targetVersion));
ResourcePack languagePack = new ResourcePack(it.fileName, convertNotNeed);
ResourcePack languagePack = new ResourcePack(it.fileName);
languagePack.checkUpdate(it.fileUrl, it.md5Url);
languagePacks.add(languagePack);
}

//Convert resourcepack
if (!convertNotNeed) {
FileUtil.setTemporaryDirPath(Paths.get(localStorage, "." + MOD_ID, minecraftVersion));
applyFileName = assets.covertFileName;
ResourcePackConverter converter = new ResourcePackConverter(languagePacks, applyFileName);
converter.convert(assets.covertPackFormat, getResourcePackDescription(assets.downloads));
}
FileUtil.setTemporaryDirPath(Paths.get(localStorage, "." + MOD_ID, minecraftVersion));
String applyFileName = assets.covertFileName;
ResourcePackConverter converter = new ResourcePackConverter(languagePacks, applyFileName);
converter.convert(assets.covertPackFormat, getResourcePackDescription(assets.downloads), modDomainsSet);

//Apply resource pack
GameConfig config = new GameConfig(minecraftPath.resolve("options.txt"));
config.addResourcePack("Minecraft-Mod-Language-Modpack",
(minecraftMajorVersion <= 12 ? "" : "file/") + applyFileName);
config.writeToFile();
long endTime = System.nanoTime();
Log.info(String.format("I18nUpdateMod finished in %.2f ms", (endTime - startTime) / 1000000.0));
} catch (Exception e) {
Log.warning(String.format("Failed to update resource pack: %s", e));
// e.printStackTrace();
Expand Down Expand Up @@ -121,4 +132,64 @@ public static String getLocalStoragePos(Path minecraftPath) {
Objects::nonNull
).findFirst().orElse(xdgDataHome);
}

private static HashSet<String> getModDomainsFromModsFolder(Path minecraftPath, String minecraftVersion, String loader) {
HashSet<String> modDomainSet = new HashSet<>();
Path modsPath = minecraftPath.resolve("mods");
String[] modsNamesList = modsPath.toFile().list((dir, name) -> name.endsWith(".jar"));
if (modsNamesList != null) {
for (String name : modsNamesList) {
modDomainSet.addAll(getModDomainFromJar(modsPath.resolve(name).toFile()));
}
}
return modDomainSet;
}

private static HashSet<String> getModDomainFromJar(File modPath) {
Log.debug(String.format("Get mod domain from %s", modPath));
HashSet<String> modList = new HashSet<>();
try (FileInputStream fis = new FileInputStream(modPath)) {
modList.addAll(getModDomainFromStream(fis, modPath.getName()));
} catch (Exception e) {
Log.warning(String.format("Failed to read jar %s: %s", modPath, e));
}
return modList;
}

private static HashSet<String> getModDomainFromStream(InputStream input, String sourceName) throws IOException {
HashSet<String> modList = new HashSet<>();
try (JarInputStream jis = new JarInputStream(input)) {
JarEntry entry;
byte[] buffer = new byte[8192];
while ((entry = jis.getNextJarEntry()) != null) {
String path = entry.getName();

// 匹配 assets/<domain>/
if (path.startsWith("assets/")) {
String[] parts = path.split("/");
if (parts.length >= 2) {
modList.add(parts[1]);
}
} else if (path.endsWith(".jar")) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int bytesRead;
while ((bytesRead = jis.read(buffer)) != -1) {
baos.write(buffer, 0, bytesRead);
}

byte[] innerJarBytes = baos.toByteArray();
try (ByteArrayInputStream innerStream = new ByteArrayInputStream(innerJarBytes)) {
modList.addAll(getModDomainFromStream(innerStream, path));
}
} catch (Exception innerEx) {
Log.warning(String.format("Failed to parse nested jar %s inside %s: %s", path, sourceName, innerEx));
}
}
}
}
return modList;
}


}
8 changes: 3 additions & 5 deletions src/main/java/i18nupdatemod/core/ResourcePack.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,15 @@ public class ResourcePack {
private final String filename;
private final Path filePath;
private final Path tmpFilePath;
private final boolean saveToGame;
private String remoteMd5;

public ResourcePack(String filename, boolean saveToGame) {
public ResourcePack(String filename) {
//If target version is not current version, not save
this.saveToGame = saveToGame;
this.filename = filename;
this.filePath = FileUtil.getResourcePackPath(filename);
this.tmpFilePath = FileUtil.getTemporaryPath(filename);
try {
FileUtil.syncTmpFile(filePath, tmpFilePath, saveToGame);
FileUtil.syncTmpFile(filePath, tmpFilePath);
} catch (Exception e) {
Log.warning(
String.format("Error while sync temp file %s <-> %s: %s", filePath, tmpFilePath, e));
Expand Down Expand Up @@ -89,7 +87,7 @@ private void downloadFull(String fileUrl, String md5Url) throws IOException {
if (!Files.exists(tmpFilePath)) {
throw new FileNotFoundException("Tmp file not found.");
}
FileUtil.syncTmpFile(filePath, tmpFilePath, saveToGame);
FileUtil.syncTmpFile(filePath, tmpFilePath);
}

public Path getTmpFilePath() {
Expand Down
16 changes: 10 additions & 6 deletions src/main/java/i18nupdatemod/core/ResourcePackConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,28 @@ public ResourcePackConverter(List<ResourcePack> resourcePack, String filename) {
this.tmpFilePath = FileUtil.getTemporaryPath(filename);
}

public void convert(int packFormat, String description) throws Exception {
public void convert(int packFormat, String description, HashSet<String> modDomainsSet) throws Exception {
Set<String> fileList = new HashSet<>();
try (ZipOutputStream zos = new ZipOutputStream(
Files.newOutputStream(tmpFilePath),
StandardCharsets.UTF_8)) {
try (ZipOutputStream zos = new ZipOutputStream(Files.newOutputStream(tmpFilePath), StandardCharsets.UTF_8)) {
// zos.setMethod(ZipOutputStream.STORED);
for (Path p : sourcePath) {
Log.info("Converting: " + p);
try (ZipFile zf = new ZipFile(p.toFile(), StandardCharsets.UTF_8)) {
for (Enumeration<? extends ZipEntry> e = zf.entries(); e.hasMoreElements(); ) {
ZipEntry ze = e.nextElement();
String name = ze.getName();
String[] parts = name.split("/");
// 正在筛选的是assets/modDomain/** && 当前的modDomain不需要
if (parts.length >= 2 && !modDomainsSet.contains(parts[1])) {
continue;
}

// Don't put same file
if (fileList.contains(name)) {
// Log.debug(name + ": DUPLICATE");
continue;
}
fileList.add(name);
// Log.debug(name);

// Put file into new zip
zos.putNextEntry(new ZipEntry(name));
Expand All @@ -67,8 +70,9 @@ public void convert(int packFormat, String description) throws Exception {
}
}
zos.close();
//Log.debug("unsolved mod domains" + modDomainsSet.toString());
Log.info("Converted: %s -> %s", sourcePath, tmpFilePath);
FileUtil.syncTmpFile(tmpFilePath, filePath, true);
FileUtil.syncTmpFile(tmpFilePath, filePath);
} catch (Exception e) {
throw new Exception(String.format("Error converting %s to %s: %s", sourcePath, tmpFilePath, e));
}
Expand Down
30 changes: 29 additions & 1 deletion src/main/java/i18nupdatemod/fabricloader/FabricLoaderMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import net.fabricmc.loader.api.FabricLoader;

import java.nio.file.Path;
import java.util.HashSet;
import java.util.Map;

//1.14-latest
public class FabricLoaderMod implements ClientModInitializer {
Expand All @@ -20,7 +22,7 @@ public void onInitializeClient() {
Log.warning("Minecraft version not found");
return;
}
I18nUpdateMod.init(gameDir, mcVersion, "Fabric");
I18nUpdateMod.init(gameDir, mcVersion, "Fabric", getMods());
}

private String getMcVersion() {
Expand All @@ -44,4 +46,30 @@ private String getMcVersion() {
}
return null;
}


private HashSet<String> getMods() {
HashSet<String> modList = new HashSet<>();
try {
// Fabric
@SuppressWarnings("unchecked") final Map<String, Object> instance = (Map<String, Object>) Reflection.clazz("net.fabricmc.loader.impl.FabricLoaderImpl")
.get("INSTANCE")
.get("modMap").get();
modList = new HashSet<>(instance.keySet());
return modList;
} catch (Exception ignored) {

}
try {
// Quilt
@SuppressWarnings("unchecked") final Map<String, Object> instance = (Map<String, Object>) Reflection.clazz("org.quiltmc.loader.impl.QuiltLoaderImpl")
.get("INSTANCE")
.get("modMap").get();
modList = new HashSet<>(instance.keySet());
return modList;
} catch (Exception ignored) {

}
return modList;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import net.minecraft.launchwrapper.LaunchClassLoader;

import java.io.File;
import java.util.HashSet;
import java.util.List;

//1.6-1.12.2
Expand All @@ -20,7 +21,7 @@ public void acceptOptions(List<String> args, File gameDir, File assetsDir, Strin
Log.warning("Failed to get minecraft version.");
return;
}
I18nUpdateMod.init(gameDir.toPath(), mcVersion, "Forge");
I18nUpdateMod.init(gameDir.toPath(), mcVersion, "Forge", new HashSet<>());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.*;

import static i18nupdatemod.I18nUpdateMod.GSON;

Expand All @@ -41,7 +38,7 @@ public void initialize(IEnvironment environment) {
Log.warning("Minecraft version not found");
return;
}
I18nUpdateMod.init(minecraftPath.get(), minecraftVersion, "Forge");
I18nUpdateMod.init(minecraftPath.get(), minecraftVersion, "Forge", new HashSet<>());
}

@Override
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/i18nupdatemod/util/FileUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static Path getTemporaryPath(String filename) {
return temporaryDirPath.resolve(filename);
}

public static void syncTmpFile(Path filePath, Path tmpFilePath, boolean saveToGame) throws IOException {
public static void syncTmpFile(Path filePath, Path tmpFilePath) throws IOException {
//Both temp and current file not found
if (!Files.exists(filePath) && !Files.exists(tmpFilePath)) {
Log.debug("Both temp and current file not found");
Expand All @@ -59,7 +59,7 @@ public static void syncTmpFile(Path filePath, Path tmpFilePath, boolean saveToGa
to = filePath;
}

if (!saveToGame && to == filePath) {
if (to == filePath) {
//Don't save to game
return;
}
Expand Down