Commit fbc0219c authored by AnimeGitB's avatar AnimeGitB
Browse files

Allow loading Resources from zip files

Move Resources loading from String filenames to Paths
Add zip support
parent a90455a7
...@@ -45,7 +45,6 @@ import javax.annotation.Nullable; ...@@ -45,7 +45,6 @@ import javax.annotation.Nullable;
import java.io.*; import java.io.*;
import java.util.Calendar; import java.util.Calendar;
import static emu.grasscutter.config.Configuration.DATA;
import static emu.grasscutter.config.Configuration.SERVER; import static emu.grasscutter.config.Configuration.SERVER;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
...@@ -203,7 +202,7 @@ public final class Grasscutter { ...@@ -203,7 +202,7 @@ public final class Grasscutter {
// If the file already exists, we attempt to load it. // If the file already exists, we attempt to load it.
try { try {
config = JsonUtils.loadToClass(configFile.getPath(), ConfigContainer.class); config = JsonUtils.loadToClass(configFile.toPath(), ConfigContainer.class);
} catch (Exception exception) { } catch (Exception exception) {
getLogger().error("There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json."); getLogger().error("There was an error while trying to load the configuration from config.json. Please make sure that there are no syntax errors. If you want to start with a default configuration, delete your existing config.json.");
System.exit(1); System.exit(1);
......
...@@ -26,7 +26,7 @@ public class ConfigContainer { ...@@ -26,7 +26,7 @@ public class ConfigContainer {
*/ */
public static void updateConfig() { public static void updateConfig() {
try { // Check if the server is using a legacy config. try { // Check if the server is using a legacy config.
JsonObject configObject = JsonUtils.loadToClass(Grasscutter.configFile.getPath(), JsonObject.class); JsonObject configObject = JsonUtils.loadToClass(Grasscutter.configFile.toPath(), JsonObject.class);
if (!configObject.has("version")) { if (!configObject.has("version")) {
Grasscutter.getLogger().info("Updating legacy .."); Grasscutter.getLogger().info("Updating legacy ..");
Grasscutter.saveConfig(null); Grasscutter.saveConfig(null);
......
package emu.grasscutter.config; package emu.grasscutter.config;
import java.util.Locale; import java.util.Locale;
import java.util.stream.Stream;
import emu.grasscutter.Grasscutter;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import static emu.grasscutter.Grasscutter.config; import static emu.grasscutter.Grasscutter.config;
...@@ -30,6 +38,42 @@ public final class Configuration extends ConfigContainer { ...@@ -30,6 +38,42 @@ public final class Configuration extends ConfigContainer {
private static final String PLUGINS_FOLDER = config.folderStructure.plugins; private static final String PLUGINS_FOLDER = config.folderStructure.plugins;
private static final String SCRIPTS_FOLDER = config.folderStructure.scripts; private static final String SCRIPTS_FOLDER = config.folderStructure.scripts;
private static final String PACKETS_FOLDER = config.folderStructure.packets; private static final String PACKETS_FOLDER = config.folderStructure.packets;
private static final FileSystem RESOURCES_FILE_SYSTEM; // Not sure about lifetime rules on this one, might be safe to remove
private static final Path RESOURCES_PATH;
static {
FileSystem fs = null;
Path path = Path.of(RESOURCES_FOLDER);
if (RESOURCES_FOLDER.endsWith(".zip")) { // Would be nice to support .tar.gz too at some point, but it doesn't come for free in Java
try {
fs = FileSystems.newFileSystem(path);
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to load resources zip \"" + RESOURCES_FOLDER + "\"");
}
}
if (fs != null) {
var root = fs.getPath("");
try (Stream<Path> pathStream = java.nio.file.Files.find(root, 3, (p, a) -> {
var filename = p.getFileName();
if (filename == null) return false;
return filename.toString().equals("ExcelBinOutput");
})) {
var excelBinOutput = pathStream.findFirst();
if (excelBinOutput.isPresent()) {
path = excelBinOutput.get().getParent();
if (path == null)
path = root;
Grasscutter.getLogger().debug("Resources will be loaded from \"" + RESOURCES_FOLDER + "/" + path.toString() + "\"");
} else {
Grasscutter.getLogger().error("Failed to find ExcelBinOutput in resources zip \"" + RESOURCES_FOLDER + "\"");
}
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to scan resources zip \"" + RESOURCES_FOLDER + "\"");
}
}
RESOURCES_FILE_SYSTEM = fs;
RESOURCES_PATH = path;
};
public static final Server SERVER = config.server; public static final Server SERVER = config.server;
public static final Database DATABASE = config.databaseInfo; public static final Database DATABASE = config.databaseInfo;
...@@ -54,11 +98,15 @@ public final class Configuration extends ConfigContainer { ...@@ -54,11 +98,15 @@ public final class Configuration extends ConfigContainer {
} }
public static String DATA(String path) { public static String DATA(String path) {
return Paths.get(DATA_FOLDER, path).toString(); return Path.of(DATA_FOLDER, path).toString();
}
public static Path getResourcePath(String path) {
return RESOURCES_PATH.resolve(path);
} }
public static String RESOURCE(String path) { public static String RESOURCE(String path) {
return Paths.get(RESOURCES_FOLDER, path).toString(); return getResourcePath(path).toString();
} }
public static String PLUGIN() { public static String PLUGIN() {
...@@ -66,15 +114,15 @@ public final class Configuration extends ConfigContainer { ...@@ -66,15 +114,15 @@ public final class Configuration extends ConfigContainer {
} }
public static String PLUGIN(String path) { public static String PLUGIN(String path) {
return Paths.get(PLUGINS_FOLDER, path).toString(); return Path.of(PLUGINS_FOLDER, path).toString();
} }
public static String SCRIPT(String path) { public static String SCRIPT(String path) {
return Paths.get(SCRIPTS_FOLDER, path).toString(); return Path.of(SCRIPTS_FOLDER, path).toString();
} }
public static String PACKET(String path) { public static String PACKET(String path) {
return Paths.get(PACKETS_FOLDER, path).toString(); return Path.of(PACKETS_FOLDER, path).toString();
} }
/** /**
......
...@@ -2,9 +2,11 @@ package emu.grasscutter.tools; ...@@ -2,9 +2,11 @@ package emu.grasscutter.tools;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
...@@ -215,11 +217,15 @@ public final class Tools { ...@@ -215,11 +217,15 @@ public final class Tools {
} }
public static List<String> getAvailableLanguage() { public static List<String> getAvailableLanguage() {
File textMapFolder = new File(RESOURCE("TextMap"));
List<String> availableLangList = new ArrayList<>(); List<String> availableLangList = new ArrayList<>();
for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) { try {
availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase()); Files.newDirectoryStream(getResourcePath("TextMap"), "TextMap*.json").forEach(path -> {
} return availableLangList; availableLangList.add(path.getFileName().toString().replace("TextMap", "").replace(".json", "").toLowerCase());
});
} catch (IOException e) {
Grasscutter.getLogger().error("Failed to get available languages:", e);
}
return availableLangList;
} }
@Deprecated(forRemoval = true, since = "1.2.3") @Deprecated(forRemoval = true, since = "1.2.3")
......
...@@ -9,7 +9,6 @@ import java.net.URI; ...@@ -9,7 +9,6 @@ import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.*; import java.nio.file.*;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
...@@ -17,7 +16,7 @@ import java.util.stream.Collectors; ...@@ -17,7 +16,7 @@ import java.util.stream.Collectors;
public final class FileUtils { public final class FileUtils {
public static void write(String dest, byte[] bytes) { public static void write(String dest, byte[] bytes) {
Path path = Paths.get(dest); Path path = Path.of(dest);
try { try {
Files.write(path, bytes); Files.write(path, bytes);
...@@ -27,7 +26,7 @@ public final class FileUtils { ...@@ -27,7 +26,7 @@ public final class FileUtils {
} }
public static byte[] read(String dest) { public static byte[] read(String dest) {
return read(Paths.get(dest)); return read(Path.of(dest));
} }
public static byte[] read(Path path) { public static byte[] read(Path path) {
......
...@@ -3,7 +3,10 @@ package emu.grasscutter.utils; ...@@ -3,7 +3,10 @@ package emu.grasscutter.utils;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -32,36 +35,57 @@ public final class JsonUtils { ...@@ -32,36 +35,57 @@ public final class JsonUtils {
return gson.fromJson(jsonElement, classType); return gson.fromJson(jsonElement, classType);
} }
public static <T> T loadToClass(InputStreamReader fileReader, Class<T> classType) throws IOException { public static <T> T loadToClass(Reader fileReader, Class<T> classType) throws IOException {
return gson.fromJson(fileReader, classType); return gson.fromJson(fileReader, classType);
} }
@Deprecated
public static <T> T loadToClass(String filename, Class<T> classType) throws IOException { public static <T> T loadToClass(String filename, Class<T> classType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) { try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToClass(fileReader, classType); return loadToClass(fileReader, classType);
} }
} }
public static <T> List<T> loadToList(InputStreamReader fileReader, Class<T> classType) throws IOException { public static <T> T loadToClass(Path filename, Class<T> classType) throws IOException {
try (var fileReader = Files.newBufferedReader(filename, StandardCharsets.UTF_8)) {
return loadToClass(fileReader, classType);
}
}
public static <T> List<T> loadToList(Reader fileReader, Class<T> classType) throws IOException {
return gson.fromJson(fileReader, TypeToken.getParameterized(List.class, classType).getType()); return gson.fromJson(fileReader, TypeToken.getParameterized(List.class, classType).getType());
} }
@Deprecated
public static <T> List<T> loadToList(String filename, Class<T> classType) throws IOException { public static <T> List<T> loadToList(String filename, Class<T> classType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) { try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToList(fileReader, classType); return loadToList(fileReader, classType);
} }
} }
public static <T1,T2> Map<T1,T2> loadToMap(InputStreamReader fileReader, Class<T1> keyType, Class<T2> valueType) throws IOException { public static <T> List<T> loadToList(Path filename, Class<T> classType) throws IOException {
try (var fileReader = Files.newBufferedReader(filename, StandardCharsets.UTF_8)) {
return loadToList(fileReader, classType);
}
}
public static <T1,T2> Map<T1,T2> loadToMap(Reader fileReader, Class<T1> keyType, Class<T2> valueType) throws IOException {
return gson.fromJson(fileReader, TypeToken.getParameterized(Map.class, keyType, valueType).getType()); return gson.fromJson(fileReader, TypeToken.getParameterized(Map.class, keyType, valueType).getType());
} }
@Deprecated
public static <T1,T2> Map<T1,T2> loadToMap(String filename, Class<T1> keyType, Class<T2> valueType) throws IOException { public static <T1,T2> Map<T1,T2> loadToMap(String filename, Class<T1> keyType, Class<T2> valueType) throws IOException {
try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) { try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(filename)), StandardCharsets.UTF_8)) {
return loadToMap(fileReader, keyType, valueType); return loadToMap(fileReader, keyType, valueType);
} }
} }
public static <T1,T2> Map<T1,T2> loadToMap(Path filename, Class<T1> keyType, Class<T2> valueType) throws IOException {
try (var fileReader = Files.newBufferedReader(filename, StandardCharsets.UTF_8)) {
return loadToMap(fileReader, keyType, valueType);
}
}
/** /**
* Safely JSON decodes a given string. * Safely JSON decodes a given string.
* @param jsonData The JSON-encoded data. * @param jsonData The JSON-encoded data.
......
...@@ -325,7 +325,7 @@ public final class Language { ...@@ -325,7 +325,7 @@ public final class Language {
private static Int2ObjectMap<String> loadTextMapFile(String language, IntSet nameHashes) { private static Int2ObjectMap<String> loadTextMapFile(String language, IntSet nameHashes) {
Int2ObjectMap<String> output = new Int2ObjectOpenHashMap<>(); Int2ObjectMap<String> output = new Int2ObjectOpenHashMap<>();
try (BufferedReader file = new BufferedReader(new FileReader(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json")), StandardCharsets.UTF_8))) { try (BufferedReader file = Files.newBufferedReader(getResourcePath("TextMap/TextMap"+language+".json"), StandardCharsets.UTF_8)) {
Matcher matcher = textMapKeyValueRegex.matcher(""); Matcher matcher = textMapKeyValueRegex.matcher("");
return new Int2ObjectOpenHashMap<>( return new Int2ObjectOpenHashMap<>(
file.lines() file.lines()
...@@ -406,7 +406,7 @@ public final class Language { ...@@ -406,7 +406,7 @@ public final class Language {
try { try {
long cacheModified = Files.getLastModifiedTime(TEXTMAP_CACHE_PATH).toMillis(); long cacheModified = Files.getLastModifiedTime(TEXTMAP_CACHE_PATH).toMillis();
long textmapsModified = Files.list(Path.of(RESOURCE("TextMap"))) long textmapsModified = Files.list(getResourcePath("TextMap"))
.filter(path -> path.toString().endsWith(".json")) .filter(path -> path.toString().endsWith(".json"))
.map(path -> { .map(path -> {
try { try {
......
...@@ -22,6 +22,7 @@ import org.slf4j.Logger; ...@@ -22,6 +22,7 @@ import org.slf4j.Logger;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import static emu.grasscutter.config.Configuration.getResourcePath;
import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.utils.Language.translate;
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"}) @SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
...@@ -169,19 +170,18 @@ public final class Utils { ...@@ -169,19 +170,18 @@ public final class Utils {
Logger logger = Grasscutter.getLogger(); Logger logger = Grasscutter.getLogger();
boolean exit = false; boolean exit = false;
String resourcesFolder = config.folderStructure.resources;
String dataFolder = config.folderStructure.data; String dataFolder = config.folderStructure.data;
// Check for resources folder. // Check for resources folder.
if (!fileExists(resourcesFolder)) { if (!Files.exists(getResourcePath(""))) {
logger.info(translate("messages.status.create_resources")); logger.info(translate("messages.status.create_resources"));
logger.info(translate("messages.status.resources_error")); logger.info(translate("messages.status.resources_error"));
createFolder(resourcesFolder); exit = true; createFolder(config.folderStructure.resources); exit = true;
} }
// Check for BinOutput + ExcelBinOutput. // Check for BinOutput + ExcelBinOutput.
if (!fileExists(resourcesFolder + "BinOutput") || if (!Files.exists(getResourcePath("BinOutput")) ||
!fileExists(resourcesFolder + "ExcelBinOutput")) { !Files.exists(getResourcePath("ExcelBinOutput"))) {
logger.info(translate("messages.status.resources_error")); logger.info(translate("messages.status.resources_error"));
exit = true; exit = true;
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment