mirror of
https://github.com/Melledy/Grasscutter.git
synced 2024-11-25 23:07:50 +00:00
Move Data, Plugin, Script, Packet access from Strings to Paths (#1839)
* Move Data, Plugin, Script, Packet access from Strings to Paths - No longer dump default Data files to folder on launch - Allow Scripts to be loaded from Resources zip - Lay groundwork for Plugins to be loaded from zip
This commit is contained in:
parent
f6ce7e349d
commit
dd6e1bb8a3
@ -84,7 +84,7 @@ public class ConfigContainer {
|
|||||||
public String resources = "./resources/";
|
public String resources = "./resources/";
|
||||||
public String data = "./data/";
|
public String data = "./data/";
|
||||||
public String packets = "./packets/";
|
public String packets = "./packets/";
|
||||||
public String scripts = "./resources/Scripts/";
|
public String scripts = "resources:Scripts/";
|
||||||
public String plugins = "./plugins/";
|
public String plugins = "./plugins/";
|
||||||
|
|
||||||
// UNUSED (potentially added later?)
|
// UNUSED (potentially added later?)
|
||||||
|
@ -1,16 +1,9 @@
|
|||||||
package emu.grasscutter.config;
|
package emu.grasscutter.config;
|
||||||
|
|
||||||
import java.util.Locale;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
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.Path;
|
||||||
import java.nio.file.Paths;
|
import java.util.Locale;
|
||||||
|
|
||||||
import static emu.grasscutter.Grasscutter.config;
|
import static emu.grasscutter.Grasscutter.config;
|
||||||
|
|
||||||
@ -34,46 +27,9 @@ public final class Configuration extends ConfigContainer {
|
|||||||
public static final Locale FALLBACK_LANGUAGE = config.language.fallback;
|
public static final Locale FALLBACK_LANGUAGE = config.language.fallback;
|
||||||
public static final String DOCUMENT_LANGUAGE = config.language.document;
|
public static final String DOCUMENT_LANGUAGE = config.language.document;
|
||||||
private static final String DATA_FOLDER = config.folderStructure.data;
|
private static final String DATA_FOLDER = config.folderStructure.data;
|
||||||
private static final String RESOURCES_FOLDER = config.folderStructure.resources;
|
|
||||||
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;
|
||||||
@ -93,22 +49,27 @@ public final class Configuration extends ConfigContainer {
|
|||||||
/*
|
/*
|
||||||
* Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String DATA() {
|
public static String DATA() {
|
||||||
return DATA_FOLDER;
|
return DATA_FOLDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String DATA(String path) {
|
public static String DATA(String path) {
|
||||||
return Path.of(DATA_FOLDER, path).toString();
|
return Path.of(DATA_FOLDER, path).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static Path getResourcePath(String path) {
|
public static Path getResourcePath(String path) {
|
||||||
return RESOURCES_PATH.resolve(path);
|
return FileUtils.getResourcePath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String RESOURCE(String path) {
|
public static String RESOURCE(String path) {
|
||||||
return getResourcePath(path).toString();
|
return FileUtils.getResourcePath(path).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String PLUGIN() {
|
public static String PLUGIN() {
|
||||||
return PLUGINS_FOLDER;
|
return PLUGINS_FOLDER;
|
||||||
}
|
}
|
||||||
@ -117,10 +78,12 @@ public final class Configuration extends ConfigContainer {
|
|||||||
return Path.of(PLUGINS_FOLDER, path).toString();
|
return Path.of(PLUGINS_FOLDER, path).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String SCRIPT(String path) {
|
public static String SCRIPT(String path) {
|
||||||
return Path.of(SCRIPTS_FOLDER, path).toString();
|
return Path.of(SCRIPTS_FOLDER, path).toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static String PACKET(String path) {
|
public static String PACKET(String path) {
|
||||||
return Path.of(PACKETS_FOLDER, path).toString();
|
return Path.of(PACKETS_FOLDER, path).toString();
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,12 @@ import emu.grasscutter.server.http.handlers.GachaHandler;
|
|||||||
import emu.grasscutter.tools.Tools;
|
import emu.grasscutter.tools.Tools;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.JsonUtils;
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.DATA;
|
|
||||||
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -59,15 +56,17 @@ public class DataLoader {
|
|||||||
* @throws FileNotFoundException
|
* @throws FileNotFoundException
|
||||||
*/
|
*/
|
||||||
public static InputStream load(String resourcePath, boolean useFallback) throws FileNotFoundException {
|
public static InputStream load(String resourcePath, boolean useFallback) throws FileNotFoundException {
|
||||||
if (Utils.fileExists(DATA(resourcePath))) {
|
Path path = useFallback
|
||||||
|
? FileUtils.getDataPath(resourcePath)
|
||||||
|
: FileUtils.getDataUserPath(resourcePath);
|
||||||
|
if (Files.exists(path)) {
|
||||||
// Data is in the resource directory
|
// Data is in the resource directory
|
||||||
return new FileInputStream(DATA(resourcePath));
|
try {
|
||||||
} else {
|
return Files.newInputStream(path);
|
||||||
if (useFallback) {
|
} catch (IOException e) {
|
||||||
return FileUtils.readResourceAsStream("/defaults/data/" + resourcePath);
|
throw new FileNotFoundException(e.getMessage()); // This is evil but so is changing the function signature at this point
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,11 +94,11 @@ public class DataLoader {
|
|||||||
|
|
||||||
if (filenames == null) {
|
if (filenames == null) {
|
||||||
Grasscutter.getLogger().error("We were unable to locate your default data files.");
|
Grasscutter.getLogger().error("We were unable to locate your default data files.");
|
||||||
} else for (Path file : filenames) {
|
} //else for (Path file : filenames) {
|
||||||
String relativePath = String.valueOf(file).split("defaults[\\\\\\/]data[\\\\\\/]")[1];
|
// String relativePath = String.valueOf(file).split("defaults[\\\\\\/]data[\\\\\\/]")[1];
|
||||||
|
|
||||||
checkAndCopyData(relativePath);
|
// checkAndCopyData(relativePath);
|
||||||
}
|
// }
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("An error occurred while trying to check the data folder.", e);
|
Grasscutter.getLogger().error("An error occurred while trying to check the data folder.", e);
|
||||||
}
|
}
|
||||||
@ -108,36 +107,25 @@ public class DataLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkAndCopyData(String name) {
|
private static void checkAndCopyData(String name) {
|
||||||
String filePath = Utils.toFilePath(DATA(name));
|
// TODO: Revisit this if default dumping is ever reintroduced
|
||||||
|
Path filePath = FileUtils.getDataPath(name);
|
||||||
|
|
||||||
if (!Utils.fileExists(filePath)) {
|
if (!Files.exists(filePath)) {
|
||||||
// Check if file is in subdirectory
|
var root = filePath.getParent();
|
||||||
if (name.contains("/")) {
|
if (root.toFile().mkdirs())
|
||||||
String[] path = name.split("/");
|
Grasscutter.getLogger().info("Created data folder '" + root + "'");
|
||||||
|
|
||||||
String folder = "";
|
|
||||||
for (int i = 0; i < (path.length - 1); i++) {
|
|
||||||
folder += path[i] + "/";
|
|
||||||
|
|
||||||
// Make sure the current folder exists
|
|
||||||
String folderToCreate = Utils.toFilePath(DATA(folder));
|
|
||||||
if (!Utils.fileExists(folderToCreate)) {
|
|
||||||
Grasscutter.getLogger().info("Creating data folder '" + folder + "'");
|
|
||||||
Utils.createFolder(folderToCreate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Grasscutter.getLogger().info("Creating default '" + name + "' data");
|
Grasscutter.getLogger().info("Creating default '" + name + "' data");
|
||||||
FileUtils.copyResource("/defaults/data/" + name, filePath);
|
FileUtils.copyResource("/defaults/data/" + name, filePath.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void generateGachaMappings() {
|
private static void generateGachaMappings() {
|
||||||
if (!Utils.fileExists(GachaHandler.gachaMappings)) {
|
var path = GachaHandler.getGachaMappingsPath();
|
||||||
|
if (!Files.exists(path)) {
|
||||||
try {
|
try {
|
||||||
Grasscutter.getLogger().info("Creating default '" + GachaHandler.gachaMappings + "' data");
|
Grasscutter.getLogger().info("Creating default '" + path.toString() + "' data");
|
||||||
Tools.createGachaMapping(GachaHandler.gachaMappings);
|
Tools.createGachaMappings(path);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
Grasscutter.getLogger().warn("Failed to create gacha mappings. \n" + exception);
|
Grasscutter.getLogger().warn("Failed to create gacha mappings. \n" + exception);
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ import java.util.*;
|
|||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.DATA;
|
import static emu.grasscutter.utils.FileUtils.getDataPath;
|
||||||
import static emu.grasscutter.config.Configuration.getResourcePath;
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
public class ResourceLoader {
|
public class ResourceLoader {
|
||||||
@ -174,7 +174,7 @@ public class ResourceLoader {
|
|||||||
|
|
||||||
// Read from cached file if exists
|
// Read from cached file if exists
|
||||||
try {
|
try {
|
||||||
embryoList = JsonUtils.loadToList(DATA("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
|
embryoList = JsonUtils.loadToList(getDataPath("AbilityEmbryos.json"), AbilityEmbryoEntry.class);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
if (embryoList == null) {
|
if (embryoList == null) {
|
||||||
@ -318,7 +318,7 @@ public class ResourceLoader {
|
|||||||
List<OpenConfigEntry> list = null;
|
List<OpenConfigEntry> list = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
list = JsonUtils.loadToList(DATA("OpenConfig.json"), OpenConfigEntry.class);
|
list = JsonUtils.loadToList(getDataPath("OpenConfig.json"), OpenConfigEntry.class);
|
||||||
} catch (Exception ignored) {}
|
} catch (Exception ignored) {}
|
||||||
|
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
|
@ -33,6 +33,7 @@ import emu.grasscutter.server.game.GameServer;
|
|||||||
import emu.grasscutter.server.game.GameServerTickEvent;
|
import emu.grasscutter.server.game.GameServerTickEvent;
|
||||||
import emu.grasscutter.server.packet.send.PacketDoGachaRsp;
|
import emu.grasscutter.server.packet.send.PacketDoGachaRsp;
|
||||||
import emu.grasscutter.server.packet.send.PacketGachaWishRsp;
|
import emu.grasscutter.server.packet.send.PacketGachaWishRsp;
|
||||||
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
@ -383,8 +384,7 @@ public class GachaSystem extends BaseGameSystem {
|
|||||||
if (this.watchService == null) {
|
if (this.watchService == null) {
|
||||||
try {
|
try {
|
||||||
this.watchService = FileSystems.getDefault().newWatchService();
|
this.watchService = FileSystems.getDefault().newWatchService();
|
||||||
Path path = new File(DATA()).toPath();
|
FileUtils.getDataUserPath("").register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH);
|
||||||
path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload");
|
Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -190,13 +190,12 @@ public class GameMainQuest {
|
|||||||
}
|
}
|
||||||
public void addRewindPoints() {
|
public void addRewindPoints() {
|
||||||
Bindings bindings = ScriptLoader.getEngine().createBindings();
|
Bindings bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
String script = "Quest/Share/Q" + getParentQuestId() + "ShareConfig.lua";
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
CompiledScript cs = ScriptLoader.getScript(script);
|
||||||
SCRIPT("Quest/Share/Q" + getParentQuestId() + "ShareConfig." + ScriptLoader.getScriptType()));
|
|
||||||
|
|
||||||
//mainQuest 303 doesn't have a ShareConfig
|
//mainQuest 303 doesn't have a ShareConfig
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
Grasscutter.getLogger().debug("Couldn't find Q" + getParentQuestId() + "ShareConfig." + ScriptLoader.getScriptType());
|
Grasscutter.getLogger().debug("Couldn't find " + script);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@ package emu.grasscutter.plugin;
|
|||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.plugin.api.ServerHook;
|
import emu.grasscutter.plugin.api.ServerHook;
|
||||||
import emu.grasscutter.server.game.GameServer;
|
import emu.grasscutter.server.game.GameServer;
|
||||||
|
import emu.grasscutter.utils.FileUtils;
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
@ -37,7 +37,7 @@ public abstract class Plugin {
|
|||||||
|
|
||||||
this.identifier = identifier;
|
this.identifier = identifier;
|
||||||
this.classLoader = classLoader;
|
this.classLoader = classLoader;
|
||||||
this.dataFolder = new File(PLUGIN(), identifier.name);
|
this.dataFolder = FileUtils.getPluginPath(identifier.name).toFile();
|
||||||
this.logger = LoggerFactory.getLogger(identifier.name);
|
this.logger = LoggerFactory.getLogger(identifier.name);
|
||||||
|
|
||||||
if (!this.dataFolder.exists() && !this.dataFolder.mkdirs()) {
|
if (!this.dataFolder.exists() && !this.dataFolder.mkdirs()) {
|
||||||
|
@ -2,13 +2,12 @@ package emu.grasscutter.plugin;
|
|||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.server.event.*;
|
import emu.grasscutter.server.event.*;
|
||||||
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.JsonUtils;
|
import emu.grasscutter.utils.JsonUtils;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.PLUGIN;
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
@ -43,7 +42,7 @@ public final class PluginManager {
|
|||||||
* Loads plugins from the config-specified directory.
|
* Loads plugins from the config-specified directory.
|
||||||
*/
|
*/
|
||||||
private void loadPlugins() {
|
private void loadPlugins() {
|
||||||
File pluginsDir = new File(Utils.toFilePath(PLUGIN()));
|
File pluginsDir = FileUtils.getPluginPath("").toFile();
|
||||||
if (!pluginsDir.exists() && !pluginsDir.mkdirs()) {
|
if (!pluginsDir.exists() && !pluginsDir.mkdirs()) {
|
||||||
Grasscutter.getLogger().error(translate("plugin.directory_failed", pluginsDir.getAbsolutePath()));
|
Grasscutter.getLogger().error(translate("plugin.directory_failed", pluginsDir.getAbsolutePath()));
|
||||||
return;
|
return;
|
||||||
|
@ -9,6 +9,9 @@ import emu.grasscutter.scripts.constants.ScriptRegionShape;
|
|||||||
import emu.grasscutter.scripts.data.SceneMeta;
|
import emu.grasscutter.scripts.data.SceneMeta;
|
||||||
import emu.grasscutter.scripts.serializer.LuaSerializer;
|
import emu.grasscutter.scripts.serializer.LuaSerializer;
|
||||||
import emu.grasscutter.scripts.serializer.Serializer;
|
import emu.grasscutter.scripts.serializer.Serializer;
|
||||||
|
import emu.grasscutter.utils.FileUtils;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import org.luaj.vm2.LuaTable;
|
import org.luaj.vm2.LuaTable;
|
||||||
import org.luaj.vm2.LuaValue;
|
import org.luaj.vm2.LuaValue;
|
||||||
import org.luaj.vm2.lib.OneArgFunction;
|
import org.luaj.vm2.lib.OneArgFunction;
|
||||||
@ -19,6 +22,8 @@ import javax.script.*;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.lang.ref.SoftReference;
|
import java.lang.ref.SoftReference;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -26,12 +31,11 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
|
|
||||||
public class ScriptLoader {
|
public class ScriptLoader {
|
||||||
private static ScriptEngineManager sm;
|
private static ScriptEngineManager sm;
|
||||||
private static ScriptEngine engine;
|
@Getter private static ScriptEngine engine;
|
||||||
private static ScriptEngineFactory factory;
|
private static ScriptEngineFactory factory;
|
||||||
private static String fileType;
|
@Getter private static Serializer serializer;
|
||||||
private static Serializer serializer;
|
@Getter private static ScriptLib scriptLib;
|
||||||
private static ScriptLib scriptLib;
|
@Getter private static LuaValue scriptLibLua;
|
||||||
private static LuaValue scriptLibLua;
|
|
||||||
/**
|
/**
|
||||||
* suggest GC to remove it if the memory is less
|
* suggest GC to remove it if the memory is less
|
||||||
*/
|
*/
|
||||||
@ -52,7 +56,6 @@ public class ScriptLoader {
|
|||||||
factory = getEngine().getFactory();
|
factory = getEngine().getFactory();
|
||||||
|
|
||||||
// Lua stuff
|
// Lua stuff
|
||||||
fileType = "lua";
|
|
||||||
serializer = new LuaSerializer();
|
serializer = new LuaSerializer();
|
||||||
|
|
||||||
// Set engine to replace require as a temporary fix to missing scripts
|
// Set engine to replace require as a temporary fix to missing scripts
|
||||||
@ -81,26 +84,6 @@ public class ScriptLoader {
|
|||||||
ctx.globals.set("ScriptLib", scriptLibLua);
|
ctx.globals.set("ScriptLib", scriptLibLua);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ScriptEngine getEngine() {
|
|
||||||
return engine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getScriptType() {
|
|
||||||
return fileType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Serializer getSerializer() {
|
|
||||||
return serializer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ScriptLib getScriptLib() {
|
|
||||||
return scriptLib;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LuaValue getScriptLibLua() {
|
|
||||||
return scriptLibLua;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> Optional<T> tryGet(SoftReference<T> softReference){
|
public static <T> Optional<T> tryGet(SoftReference<T> softReference){
|
||||||
try{
|
try{
|
||||||
return Optional.ofNullable(softReference.get());
|
return Optional.ofNullable(softReference.get());
|
||||||
@ -108,6 +91,8 @@ public class ScriptLoader {
|
|||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
public static CompiledScript getScriptByPath(String path) {
|
public static CompiledScript getScriptByPath(String path) {
|
||||||
var sc = tryGet(scriptsCache.get(path));
|
var sc = tryGet(scriptsCache.get(path));
|
||||||
if (sc.isPresent()) {
|
if (sc.isPresent()) {
|
||||||
@ -131,6 +116,26 @@ public class ScriptLoader {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static CompiledScript getScript(String path) {
|
||||||
|
var sc = tryGet(scriptsCache.get(path));
|
||||||
|
if (sc.isPresent()) {
|
||||||
|
return sc.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Grasscutter.getLogger().debug("Loading script " + path);
|
||||||
|
final Path scriptPath = FileUtils.getScriptPath(path);
|
||||||
|
if (!Files.exists(scriptPath)) return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var script = ((Compilable) getEngine()).compile(Files.newBufferedReader(scriptPath));
|
||||||
|
scriptsCache.put(path, new SoftReference<>(script));
|
||||||
|
return script;
|
||||||
|
} catch (Exception e) {
|
||||||
|
Grasscutter.getLogger().error("Loading script {} failed!", path, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static SceneMeta getSceneMeta(int sceneId) {
|
public static SceneMeta getSceneMeta(int sceneId) {
|
||||||
return tryGet(sceneMetaCache.get(sceneId)).orElseGet(() -> {
|
return tryGet(sceneMetaCache.get(sceneId)).orElseGet(() -> {
|
||||||
var instance = SceneMeta.of(sceneId);
|
var instance = SceneMeta.of(sceneId);
|
||||||
|
@ -14,8 +14,6 @@ import javax.script.Bindings;
|
|||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.SCRIPT;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@ -52,8 +50,7 @@ public class SceneBlock {
|
|||||||
this.sceneId = sceneId;
|
this.sceneId = sceneId;
|
||||||
this.setLoaded(true);
|
this.setLoaded(true);
|
||||||
|
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
CompiledScript cs = ScriptLoader.getScript("Scene/" + sceneId + "/scene" + sceneId + "_block" + this.id + ".lua");
|
||||||
SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_block" + this.id + "." + ScriptLoader.getScriptType()));
|
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -11,8 +11,6 @@ import javax.script.Bindings;
|
|||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.SCRIPT;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -84,8 +82,7 @@ public class SceneGroup {
|
|||||||
|
|
||||||
this.bindings = ScriptLoader.getEngine().createBindings();
|
this.bindings = ScriptLoader.getEngine().createBindings();
|
||||||
|
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
CompiledScript cs = ScriptLoader.getScript("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + ".lua");
|
||||||
SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + "." + ScriptLoader.getScriptType()));
|
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
return this;
|
return this;
|
||||||
|
@ -12,8 +12,6 @@ import javax.script.Bindings;
|
|||||||
import javax.script.CompiledScript;
|
import javax.script.CompiledScript;
|
||||||
import javax.script.ScriptException;
|
import javax.script.ScriptException;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.SCRIPT;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -35,8 +33,7 @@ public class SceneMeta {
|
|||||||
|
|
||||||
public SceneMeta load(int sceneId) {
|
public SceneMeta load(int sceneId) {
|
||||||
// Get compiled script if cached
|
// Get compiled script if cached
|
||||||
CompiledScript cs = ScriptLoader.getScriptByPath(
|
CompiledScript cs = ScriptLoader.getScript("Scene/" + sceneId + "/scene" + sceneId + ".lua");
|
||||||
SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "." + ScriptLoader.getScriptType()));
|
|
||||||
|
|
||||||
if (cs == null) {
|
if (cs == null) {
|
||||||
Grasscutter.getLogger().warn("No script found for scene " + sceneId);
|
Grasscutter.getLogger().warn("No script found for scene " + sceneId);
|
||||||
|
@ -2,7 +2,8 @@ package emu.grasscutter.server.game;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.util.Set;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
import emu.grasscutter.Grasscutter.ServerDebugMode;
|
||||||
import emu.grasscutter.game.Account;
|
import emu.grasscutter.game.Account;
|
||||||
@ -16,6 +17,8 @@ import emu.grasscutter.utils.FileUtils;
|
|||||||
import emu.grasscutter.utils.Utils;
|
import emu.grasscutter.utils.Utils;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.buffer.Unpooled;
|
import io.netty.buffer.Unpooled;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
@ -24,14 +27,14 @@ public class GameSession implements GameSessionManager.KcpChannel {
|
|||||||
private final GameServer server;
|
private final GameServer server;
|
||||||
private GameSessionManager.KcpTunnel tunnel;
|
private GameSessionManager.KcpTunnel tunnel;
|
||||||
|
|
||||||
private Account account;
|
@Getter @Setter private Account account;
|
||||||
private Player player;
|
@Getter private Player player;
|
||||||
|
|
||||||
private boolean useSecretKey;
|
@Setter private boolean useSecretKey;
|
||||||
private SessionState state;
|
@Getter @Setter private SessionState state;
|
||||||
|
|
||||||
private int clientTime;
|
@Getter private int clientTime;
|
||||||
private long lastPingTime;
|
@Getter private long lastPingTime;
|
||||||
private int lastClientSeq = 10;
|
private int lastClientSeq = 10;
|
||||||
|
|
||||||
public GameSession(GameServer server) {
|
public GameSession(GameServer server) {
|
||||||
@ -56,52 +59,20 @@ public class GameSession implements GameSessionManager.KcpChannel {
|
|||||||
return useSecretKey;
|
return useSecretKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Account getAccount() {
|
|
||||||
return account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAccount(Account account) {
|
|
||||||
this.account = account;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAccountId() {
|
public String getAccountId() {
|
||||||
return this.getAccount().getId();
|
return this.getAccount().getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Player getPlayer() {
|
|
||||||
return player;
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void setPlayer(Player player) {
|
public synchronized void setPlayer(Player player) {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
this.player.setSession(this);
|
this.player.setSession(this);
|
||||||
this.player.setAccount(this.getAccount());
|
this.player.setAccount(this.getAccount());
|
||||||
}
|
}
|
||||||
|
|
||||||
public SessionState getState() {
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setState(SessionState state) {
|
|
||||||
this.state = state;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isLoggedIn() {
|
public boolean isLoggedIn() {
|
||||||
return this.getPlayer() != null;
|
return this.getPlayer() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUseSecretKey(boolean useSecretKey) {
|
|
||||||
this.useSecretKey = useSecretKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getClientTime() {
|
|
||||||
return this.clientTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getLastPingTime() {
|
|
||||||
return lastPingTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateLastPingTime(int clientTime) {
|
public void updateLastPingTime(int clientTime) {
|
||||||
this.clientTime = clientTime;
|
this.clientTime = clientTime;
|
||||||
this.lastPingTime = System.currentTimeMillis();
|
this.lastPingTime = System.currentTimeMillis();
|
||||||
@ -112,8 +83,8 @@ public class GameSession implements GameSessionManager.KcpChannel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void replayPacket(int opcode, String name) {
|
public void replayPacket(int opcode, String name) {
|
||||||
String filePath = PACKET(name);
|
Path filePath = FileUtils.getPluginPath(name);
|
||||||
File p = new File(filePath);
|
File p = filePath.toFile();
|
||||||
|
|
||||||
if (!p.exists()) return;
|
if (!p.exists()) return;
|
||||||
|
|
||||||
|
@ -11,42 +11,38 @@ import emu.grasscutter.data.excels.MonsterData;
|
|||||||
import emu.grasscutter.data.excels.SceneData;
|
import emu.grasscutter.data.excels.SceneData;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.Language;
|
import emu.grasscutter.utils.Language;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
import io.javalin.http.ContentType;
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
final class HandbookRequestHandler implements DocumentationHandler {
|
final class HandbookRequestHandler implements DocumentationHandler {
|
||||||
private List<String> handbookHtmls;
|
private List<String> handbookHtmls;
|
||||||
private final String template;
|
|
||||||
|
|
||||||
public HandbookRequestHandler() {
|
public HandbookRequestHandler() {
|
||||||
final File templateFile = new File(Utils.toFilePath(DATA("documentation/handbook.html")));
|
var templatePath = FileUtils.getDataPath("documentation/handbook.html");
|
||||||
if (templateFile.exists()) {
|
try {
|
||||||
this.template = new String(FileUtils.read(templateFile), StandardCharsets.UTF_8);
|
this.handbookHtmls = generateHandbookHtmls(Files.readString(templatePath));
|
||||||
this.handbookHtmls = generateHandbookHtmls();
|
} catch (IOException ignored) {
|
||||||
} else {
|
Grasscutter.getLogger().warn("File does not exist: " + templatePath);
|
||||||
Grasscutter.getLogger().warn("File does not exist: " + templateFile);
|
|
||||||
this.template = null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(Context ctx) {
|
public void handle(Context ctx) {
|
||||||
final int langIdx = Language.TextStrings.MAP_LANGUAGES.getOrDefault(DOCUMENT_LANGUAGE, 0); // TODO: This should really be based off the client language somehow
|
final int langIdx = Language.TextStrings.MAP_LANGUAGES.getOrDefault(DOCUMENT_LANGUAGE, 0); // TODO: This should really be based off the client language somehow
|
||||||
if (template == null) {
|
if (this.handbookHtmls == null) {
|
||||||
ctx.status(500);
|
ctx.status(500);
|
||||||
} else {
|
} else {
|
||||||
ctx.contentType(ContentType.TEXT_HTML);
|
ctx.contentType(ContentType.TEXT_HTML);
|
||||||
ctx.result(handbookHtmls.get(langIdx));
|
ctx.result(this.handbookHtmls.get(langIdx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> generateHandbookHtmls() {
|
private List<String> generateHandbookHtmls(String template) {
|
||||||
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
||||||
final List<String> output = new ArrayList<>(NUM_LANGUAGES);
|
final List<String> output = new ArrayList<>(NUM_LANGUAGES);
|
||||||
final List<Language> languages = Language.TextStrings.getLanguages();
|
final List<Language> languages = Language.TextStrings.getLanguages();
|
||||||
|
@ -1,29 +1,28 @@
|
|||||||
package emu.grasscutter.server.http.documentation;
|
package emu.grasscutter.server.http.documentation;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.DATA;
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
import emu.grasscutter.Grasscutter;
|
import emu.grasscutter.Grasscutter;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
import io.javalin.http.ContentType;
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.file.Files;
|
||||||
|
|
||||||
final class RootRequestHandler implements DocumentationHandler {
|
final class RootRequestHandler implements DocumentationHandler {
|
||||||
|
|
||||||
private final String template;
|
private final String template;
|
||||||
|
|
||||||
public RootRequestHandler() {
|
public RootRequestHandler() {
|
||||||
final File templateFile = new File(Utils.toFilePath(DATA("documentation/index.html")));
|
var templatePath = FileUtils.getDataPath("documentation/index.html");
|
||||||
if (templateFile.exists()) {
|
String t = null;
|
||||||
template = new String(FileUtils.read(templateFile), StandardCharsets.UTF_8);
|
try {
|
||||||
} else {
|
t = Files.readString(templatePath);
|
||||||
Grasscutter.getLogger().warn("File does not exist: " + templateFile);
|
} catch (IOException ignored) {
|
||||||
template = null;
|
Grasscutter.getLogger().warn("File does not exist: " + templatePath);
|
||||||
}
|
}
|
||||||
|
this.template = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -5,7 +5,6 @@ import emu.grasscutter.data.DataLoader;
|
|||||||
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
import emu.grasscutter.server.http.objects.HttpJsonResponse;
|
||||||
import emu.grasscutter.server.http.Router;
|
import emu.grasscutter.server.http.Router;
|
||||||
import emu.grasscutter.utils.FileUtils;
|
import emu.grasscutter.utils.FileUtils;
|
||||||
import emu.grasscutter.utils.Utils;
|
|
||||||
import io.javalin.Javalin;
|
import io.javalin.Javalin;
|
||||||
import io.javalin.http.ContentType;
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
@ -74,7 +73,7 @@ public final class AnnouncementsHandler implements Router {
|
|||||||
|
|
||||||
private static void getPageResources(Context ctx) {
|
private static void getPageResources(Context ctx) {
|
||||||
try (InputStream filestream = DataLoader.load(ctx.path())) {
|
try (InputStream filestream = DataLoader.load(ctx.path())) {
|
||||||
String possibleFilename = Utils.toFilePath(DATA(ctx.path()));
|
String possibleFilename = ctx.path();
|
||||||
|
|
||||||
ContentType fromExtension = ContentType.getContentTypeByExtension(possibleFilename.substring(possibleFilename.lastIndexOf(".") + 1));
|
ContentType fromExtension = ContentType.getContentTypeByExtension(possibleFilename.substring(possibleFilename.lastIndexOf(".") + 1));
|
||||||
ctx.contentType(fromExtension != null ? fromExtension : ContentType.APPLICATION_OCTET_STREAM);
|
ctx.contentType(fromExtension != null ? fromExtension : ContentType.APPLICATION_OCTET_STREAM);
|
||||||
|
@ -13,31 +13,36 @@ import io.javalin.Javalin;
|
|||||||
import io.javalin.http.ContentType;
|
import io.javalin.http.ContentType;
|
||||||
import io.javalin.http.Context;
|
import io.javalin.http.Context;
|
||||||
import io.javalin.http.staticfiles.Location;
|
import io.javalin.http.staticfiles.Location;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.DATA;
|
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles all gacha-related HTTP requests.
|
* Handles all gacha-related HTTP requests.
|
||||||
*/
|
*/
|
||||||
public final class GachaHandler implements Router {
|
public final class GachaHandler implements Router {
|
||||||
public static final String gachaMappings = DATA(Utils.toFilePath("gacha/mappings.js"));
|
@Getter private static final Path gachaMappingsPath = FileUtils.getDataUserPath("gacha/mappings.js");
|
||||||
|
@Deprecated(forRemoval = true)
|
||||||
|
public static final String gachaMappings = gachaMappingsPath.toString();
|
||||||
|
|
||||||
@Override public void applyRoutes(Javalin javalin) {
|
@Override public void applyRoutes(Javalin javalin) {
|
||||||
javalin.get("/gacha", GachaHandler::gachaRecords);
|
javalin.get("/gacha", GachaHandler::gachaRecords);
|
||||||
javalin.get("/gacha/details", GachaHandler::gachaDetails);
|
javalin.get("/gacha/details", GachaHandler::gachaDetails);
|
||||||
|
|
||||||
javalin._conf.addSinglePageRoot("/gacha/mappings", gachaMappings, Location.EXTERNAL);
|
javalin._conf.addSinglePageRoot("/gacha/mappings", gachaMappingsPath.toString(), Location.EXTERNAL); // TODO: This ***must*** be changed to take the Path not a String. This might involve upgrading Javalin.
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void gachaRecords(Context ctx) {
|
private static void gachaRecords(Context ctx) {
|
||||||
File recordsTemplate = new File(Utils.toFilePath(DATA("gacha/records.html")));
|
File recordsTemplate = FileUtils.getDataPath("gacha/records.html").toFile();
|
||||||
if (!recordsTemplate.exists()) {
|
if (!recordsTemplate.exists()) {
|
||||||
Grasscutter.getLogger().warn("File does not exist: " + recordsTemplate);
|
Grasscutter.getLogger().warn("File does not exist: " + recordsTemplate);
|
||||||
ctx.status(500);
|
ctx.status(500);
|
||||||
@ -77,13 +82,7 @@ public final class GachaHandler implements Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void gachaDetails(Context ctx) {
|
private static void gachaDetails(Context ctx) {
|
||||||
File detailsTemplate = new File(Utils.toFilePath(DATA("gacha/details.html")));
|
Path detailsTemplate = FileUtils.getDataPath("gacha/details.html");
|
||||||
if (!detailsTemplate.exists()) {
|
|
||||||
Grasscutter.getLogger().warn("File does not exist: " + detailsTemplate);
|
|
||||||
ctx.status(500);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String sessionKey = ctx.queryParam("s");
|
String sessionKey = ctx.queryParam("s");
|
||||||
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
Account account = DatabaseHelper.getAccountBySessionKey(sessionKey);
|
||||||
if (account == null) {
|
if (account == null) {
|
||||||
@ -96,7 +95,14 @@ public final class GachaHandler implements Router {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String template = new String(FileUtils.read(detailsTemplate), StandardCharsets.UTF_8);
|
String template;
|
||||||
|
try {
|
||||||
|
template = Files.readString(detailsTemplate);
|
||||||
|
} catch (IOException e) {
|
||||||
|
Grasscutter.getLogger().warn("Failed to read data/gacha/details.html");
|
||||||
|
ctx.status(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Add translated title etc. to the page.
|
// Add translated title etc. to the page.
|
||||||
template = template.replace("{{TITLE}}", translate(player, "gacha.details.title"))
|
template = template.replace("{{TITLE}}", translate(player, "gacha.details.title"))
|
||||||
|
@ -7,6 +7,7 @@ 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.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -28,6 +29,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntRBTreeMap;
|
|||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
|
|
||||||
public final class Tools {
|
public final class Tools {
|
||||||
public static void createGmHandbooks() throws Exception {
|
public static void createGmHandbooks() throws Exception {
|
||||||
@ -109,10 +111,6 @@ public final class Tools {
|
|||||||
Grasscutter.getLogger().info("GM Handbooks generated!");
|
Grasscutter.getLogger().info("GM Handbooks generated!");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void createGachaMapping(String location) throws Exception {
|
|
||||||
createGachaMappings(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<String> createGachaMappingJsons() {
|
public static List<String> createGachaMappingJsons() {
|
||||||
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
final int NUM_LANGUAGES = Language.TextStrings.NUM_LANGUAGES;
|
||||||
final Language.TextStrings CHARACTER = Language.getTextMapKey(4233146695L); // "Character" in EN
|
final Language.TextStrings CHARACTER = Language.getTextMapKey(4233146695L); // "Character" in EN
|
||||||
@ -196,7 +194,7 @@ public final class Tools {
|
|||||||
return sbs.stream().map(StringBuilder::toString).toList();
|
return sbs.stream().map(StringBuilder::toString).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void createGachaMappings(String location) throws Exception {
|
public static void createGachaMappings(Path location) throws IOException {
|
||||||
ResourceLoader.loadResources();
|
ResourceLoader.loadResources();
|
||||||
List<String> jsons = createGachaMappingJsons();
|
List<String> jsons = createGachaMappingJsons();
|
||||||
StringBuilder sb = new StringBuilder("mappings = {\n");
|
StringBuilder sb = new StringBuilder("mappings = {\n");
|
||||||
@ -207,13 +205,9 @@ public final class Tools {
|
|||||||
sb.setLength(sb.length() - 2); // Delete trailing ",\n"
|
sb.setLength(sb.length() - 2); // Delete trailing ",\n"
|
||||||
sb.append("\n}");
|
sb.append("\n}");
|
||||||
|
|
||||||
try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) {
|
Files.createDirectories(location.getParent());
|
||||||
// if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us"
|
Files.writeString(location, sb);
|
||||||
// since it's the fallback language and there will be no difference in the gacha record page.
|
Grasscutter.getLogger().info("Mappings generated to " + location);
|
||||||
// The end-user can still modify the `gacha/mappings.js` directly to enable multilingual for the gacha record system.
|
|
||||||
writer.println(sb);
|
|
||||||
Grasscutter.getLogger().info("Mappings generated to " + location + " !");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> getAvailableLanguage() {
|
public static List<String> getAvailableLanguage() {
|
||||||
|
@ -10,11 +10,107 @@ 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.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class FileUtils {
|
public final class FileUtils {
|
||||||
|
private static final FileSystem JAR_FILE_SYSTEM;
|
||||||
|
private static final Path DATA_DEFAULT_PATH;
|
||||||
|
private static final Path DATA_USER_PATH = Path.of(Grasscutter.config.folderStructure.data);
|
||||||
|
private static final Path PACKETS_PATH = Path.of(Grasscutter.config.folderStructure.packets);
|
||||||
|
private static final Path PLUGINS_PATH = Path.of(Grasscutter.config.folderStructure.plugins);
|
||||||
|
private static final Path RESOURCES_PATH;
|
||||||
|
private static final Path SCRIPTS_PATH;
|
||||||
|
static {
|
||||||
|
FileSystem fs = null;
|
||||||
|
Path path = DATA_USER_PATH;
|
||||||
|
// Setup Data paths
|
||||||
|
// Get pathUri of the current running JAR
|
||||||
|
try {
|
||||||
|
URI jarUri = Grasscutter.class.getProtectionDomain()
|
||||||
|
.getCodeSource()
|
||||||
|
.getLocation()
|
||||||
|
.toURI();
|
||||||
|
fs = FileSystems.newFileSystem(Path.of(jarUri));
|
||||||
|
path = fs.getPath("/defaults/data");
|
||||||
|
} catch (URISyntaxException | IOException e) {
|
||||||
|
// Failed to load this jar. How?
|
||||||
|
System.err.println("Failed to load jar?????????????????????");
|
||||||
|
} finally {
|
||||||
|
JAR_FILE_SYSTEM = fs;
|
||||||
|
DATA_DEFAULT_PATH = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup Resources path
|
||||||
|
final String resources = Grasscutter.config.folderStructure.resources;
|
||||||
|
fs = null;
|
||||||
|
path = Path.of(resources);
|
||||||
|
if (resources.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 + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs != null) {
|
||||||
|
var root = fs.getPath("");
|
||||||
|
try (Stream<Path> pathStream = 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 + "/" + path.toString() + "\"");
|
||||||
|
} else {
|
||||||
|
Grasscutter.getLogger().error("Failed to find ExcelBinOutput in resources zip \"" + resources + "\"");
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Grasscutter.getLogger().error("Failed to scan resources zip \"" + resources + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RESOURCES_PATH = path;
|
||||||
|
|
||||||
|
// Setup Scripts path
|
||||||
|
final String scripts = Grasscutter.config.folderStructure.scripts;
|
||||||
|
SCRIPTS_PATH = (scripts.startsWith("resources:"))
|
||||||
|
? RESOURCES_PATH.resolve(scripts.substring("resources:".length()))
|
||||||
|
: Path.of(scripts);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Path getDataPath(String path) {
|
||||||
|
Path userPath = DATA_USER_PATH.resolve(path);
|
||||||
|
if (Files.exists(userPath)) return userPath;
|
||||||
|
Path defaultPath = DATA_DEFAULT_PATH.resolve(path);
|
||||||
|
if (Files.exists(defaultPath)) return defaultPath;
|
||||||
|
return userPath; // Maybe they want to write to a new file
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getDataUserPath(String path) {
|
||||||
|
return DATA_USER_PATH.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getPacketPath(String path) {
|
||||||
|
return PACKETS_PATH.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getPluginPath(String path) {
|
||||||
|
return PLUGINS_PATH.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getResourcePath(String path) {
|
||||||
|
return RESOURCES_PATH.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Path getScriptPath(String path) {
|
||||||
|
return SCRIPTS_PATH.resolve(path);
|
||||||
|
}
|
||||||
|
|
||||||
public static void write(String dest, byte[] bytes) {
|
public static void write(String dest, byte[] bytes) {
|
||||||
Path path = Path.of(dest);
|
Path path = Path.of(dest);
|
||||||
|
|
||||||
@ -79,20 +175,11 @@ public final class FileUtils {
|
|||||||
public static List<Path> getPathsFromResource(String folder) throws URISyntaxException {
|
public static List<Path> getPathsFromResource(String folder) throws URISyntaxException {
|
||||||
List<Path> result = null;
|
List<Path> result = null;
|
||||||
|
|
||||||
// Get pathUri of the current running JAR
|
|
||||||
URI pathUri = Grasscutter.class.getProtectionDomain()
|
|
||||||
.getCodeSource()
|
|
||||||
.getLocation()
|
|
||||||
.toURI();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// file walks JAR
|
// file walks JAR
|
||||||
URI uri = URI.create("jar:file:" + pathUri.getRawPath());
|
result = Files.walk(JAR_FILE_SYSTEM.getPath(folder))
|
||||||
try (FileSystem fs = FileSystems.newFileSystem(uri, Collections.emptyMap())) {
|
.filter(Files::isRegularFile)
|
||||||
result = Files.walk(fs.getPath(folder))
|
.collect(Collectors.toList());
|
||||||
.filter(Files::isRegularFile)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// Eclipse puts resources in its bin folder
|
// Eclipse puts resources in its bin folder
|
||||||
File f = new File(System.getProperty("user.dir") + folder);
|
File f = new File(System.getProperty("user.dir") + folder);
|
||||||
|
@ -17,6 +17,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import static emu.grasscutter.config.Configuration.*;
|
import static emu.grasscutter.config.Configuration.*;
|
||||||
|
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
|
@ -22,7 +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.FileUtils.getResourcePath;
|
||||||
import static emu.grasscutter.utils.Language.translate;
|
import static emu.grasscutter.utils.Language.translate;
|
||||||
|
|
||||||
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
|
@SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"})
|
||||||
|
Loading…
Reference in New Issue
Block a user