diff --git a/core/src/main/java/pl/skidam/automodpack_core/GlobalVariables.java b/core/src/main/java/pl/skidam/automodpack_core/GlobalVariables.java index 4b743f828..52fcb9ffa 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/GlobalVariables.java +++ b/core/src/main/java/pl/skidam/automodpack_core/GlobalVariables.java @@ -5,6 +5,7 @@ import pl.skidam.automodpack_core.config.Jsons; import pl.skidam.automodpack_core.loader.*; import pl.skidam.automodpack_core.modpack.ModpackExecutor; +import pl.skidam.automodpack_core.modpack.FullServerPack; import pl.skidam.automodpack_core.protocol.netty.NettyServer; import java.nio.file.Path; @@ -23,9 +24,11 @@ public class GlobalVariables { public static GameCallService GAME_CALL = new NullGameCall(); public static Path THIZ_JAR; public static Path MODS_DIR; + // new modpack class, now gen about the Executor public static ModpackExecutor modpackExecutor; + public static FullServerPack fullpacks; public static NettyServer hostServer; - public static Jsons.ServerConfigFieldsV2 serverConfig; + public static Jsons.ServerConfigFieldsV3 serverConfig; public static Jsons.ClientConfigFieldsV2 clientConfig; public static Jsons.KnownHostsFields knownHosts; public static final Path automodpackDir = Path.of("automodpack"); @@ -34,8 +37,8 @@ public class GlobalVariables { // Main - required // Addons - optional addon packs // Switches - optional or required packs, chosen by the player, only one can be installed at a time - public static final Path hostContentModpackDir = hostModpackDir.resolve("main"); - public static Path hostModpackContentFile = hostModpackDir.resolve("automodpack-content.json"); + public static final Path mainHostContentModpackDir = hostModpackDir.resolve("main"); + public static final Path hostModpackContentFile = hostModpackDir.resolve("automodpack-content.json"); public static Path serverConfigFile = automodpackDir.resolve("automodpack-server.json"); public static Path serverCoreConfigFile = automodpackDir.resolve("automodpack-core.json"); public static final Path privateDir = automodpackDir.resolve(".private"); @@ -50,6 +53,7 @@ public class GlobalVariables { public static final Path clientConfigFile = automodpackDir.resolve("automodpack-client.json"); public static final Path clientSecretsFile = privateDir.resolve("automodpack-client-secrets.json"); public static final Path modpacksDir = automodpackDir.resolve("modpacks"); + public static final Path hostFullServerPackDir = automodpackDir.resolve("serverpack"); public static final String clientConfigFileOverrideResource = "overrides-automodpack-client.json"; public static String clientConfigOverride; // read from inside a jar file on preload, used instead of clientConfigFile if exists diff --git a/core/src/main/java/pl/skidam/automodpack_core/Server.java b/core/src/main/java/pl/skidam/automodpack_core/Server.java index 763e8d7cd..6e782a0fe 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/Server.java +++ b/core/src/main/java/pl/skidam/automodpack_core/Server.java @@ -2,17 +2,22 @@ import pl.skidam.automodpack_core.config.ConfigTools; import pl.skidam.automodpack_core.config.Jsons; +import pl.skidam.automodpack_core.modpack.FullServerPackContent; import pl.skidam.automodpack_core.modpack.ModpackExecutor; -import pl.skidam.automodpack_core.modpack.ModpackContent; +import pl.skidam.automodpack_core.modpack.FullServerPack; import pl.skidam.automodpack_core.protocol.netty.NettyServer; +import pl.skidam.automodpack_core.utils.CustomFileUtils; import java.nio.file.Path; -import java.util.ArrayList; import static pl.skidam.automodpack_core.GlobalVariables.*; public class Server { + //hostmodpack folder + private static final Path hostContentModpackDir = CustomFileUtils.getPathFromCWD("automodpack/host-modpack"); + + // TODO Finish this class that it will be able to host the server without mod public static void main(String[] args) { @@ -31,13 +36,12 @@ public static void main(String[] args) { modpackDir.toFile().mkdirs(); - hostModpackContentFile = modpackDir.resolve("automodpack-content.json"); +// hostModpackContentFile = modpackDir.resolve("automodpack-content.json"); serverConfigFile = modpackDir.resolve("automodpack-server.json"); serverCoreConfigFile = modpackDir.resolve("automodpack-core.json"); - serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV2.class); + serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV3.class); if (serverConfig != null) { - serverConfig.syncedFiles = new ArrayList<>(); serverConfig.validateSecrets = false; ConfigTools.save(serverConfigFile, serverConfig); @@ -60,18 +64,45 @@ public static void main(String[] args) { mainModpackDir.toFile().mkdirs(); ModpackExecutor modpackExecutor = new ModpackExecutor(); - ModpackContent modpackContent = new ModpackContent(serverConfig.modpackName, null, mainModpackDir, serverConfig.syncedFiles, serverConfig.allowEditsInFiles, serverConfig.forceCopyFilesToStandardLocation, modpackExecutor.getExecutor()); - boolean generated = modpackExecutor.generateNew(modpackContent); +// ModpackContent modpackContent = new ModpackContent(serverConfig.modpackName, null, mainModpackDir, serverConfig.syncedFiles, serverConfig.allowEditsInFiles, serverConfig.forceCopyFilesToStandardLocation, modpackExecutor.getExecutor()); +// boolean generated = modpackExecutor.generateNew(modpackContent); + +// if (generated) { +// LOGGER.info("Modpack generated!"); +// } else { +// LOGGER.error("Failed to generate modpack!"); +// } + + //beta modpack Executor + //modpackExecutor.stop(); + + // change hostPort to bindPort? + //LOGGER.info("Starting server on port {}", serverConfig.bindPort); - if (generated) { - LOGGER.info("Modpack generated!"); + FullServerPack fullserverpack = new FullServerPack(modpackExecutor); + + String modpackName = serverConfig.groups.get("host").groupName; + FullServerPackContent fullServerPackContent = new FullServerPackContent(modpackName, hostContentModpackDir, fullserverpack.executor.getExecutor()); + boolean fullpackgenerated = fullserverpack.generateNew(fullServerPackContent); + + if (fullpackgenerated) { + LOGGER.info("FullServerPack generated!"); } else { - LOGGER.error("Failed to generate modpack!"); + LOGGER.error("Failed to generate serverpack!"); } modpackExecutor.stop(); + fullserverpack.shutdownExecutor(); + //port from Config + Jsons.GroupDeclaration hostGroup = serverConfig.groups.get("host"); + if (hostGroup == null) { + LOGGER.error("Host group not found in server config!"); + return; + } + + int port = serverConfig.bindPort; + LOGGER.info("Starting server on port {}", port); - LOGGER.info("Starting server on port {}", serverConfig.bindPort); server.start(); // wait for server to stop while (server.isRunning()) { diff --git a/core/src/main/java/pl/skidam/automodpack_core/config/ConfigTools.java b/core/src/main/java/pl/skidam/automodpack_core/config/ConfigTools.java index 7f921017e..29f01a083 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/config/ConfigTools.java +++ b/core/src/main/java/pl/skidam/automodpack_core/config/ConfigTools.java @@ -2,13 +2,25 @@ package pl.skidam.automodpack_core.config; import com.google.gson.*; -import pl.skidam.automodpack_core.utils.AddressHelpers; - +import com.google.gson.GsonBuilder; +import com.google.gson.JsonSyntaxException; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonParser; import java.lang.reflect.Type; import java.net.InetSocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; +import java.io.Reader; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import pl.skidam.automodpack_core.utils.AddressHelpers; + import static pl.skidam.automodpack_core.GlobalVariables.*; @@ -91,6 +103,7 @@ public static T load(Path configFile, Class configClass) { } } + public static T load(String json, Class configClass) { try { if (json != null) { @@ -123,11 +136,11 @@ public static void save(Path configFile, Object configObject) { // Modpack content stuff - public static Jsons.ModpackContentFields loadModpackContent(Path modpackContentFile) { + public static Jsons.ModpackGroupFields loadModpackContent(Path modpackContentFile) { try { if (Files.isRegularFile(modpackContentFile)) { String json = Files.readString(modpackContentFile); - return GSON.fromJson(json, Jsons.ModpackContentFields.class); + return GSON.fromJson(json, Jsons.ModpackGroupFields.class); } } catch (Exception e) { LOGGER.error("Couldn't load modpack content! {}", modpackContentFile.toAbsolutePath().normalize(), e); @@ -135,7 +148,7 @@ public static Jsons.ModpackContentFields loadModpackContent(Path modpackContentF return null; } - public static void saveModpackContent(Path modpackContentFile, Jsons.ModpackContentFields configObject) { + public static void saveModpackContent(Path modpackContentFile, Jsons.ModpackGroupFields configObject) { try { if (!Files.isDirectory(modpackContentFile.getParent())) { Files.createDirectories(modpackContentFile.getParent()); @@ -147,4 +160,37 @@ public static void saveModpackContent(Path modpackContentFile, Jsons.ModpackCont e.printStackTrace(); } } + + public static void saveFullServerPackContent(Path modpackContentFile, Jsons.FullServerPackContentFields configObject) { + try { + if (!Files.isDirectory(modpackContentFile.getParent())) { + Files.createDirectories(modpackContentFile.getParent()); + } + + Files.writeString(modpackContentFile, GSON.toJson(configObject), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING); + } catch (Exception e) { + LOGGER.error("Couldn't save full server pack content! " + configObject.getClass()); + e.printStackTrace(); + } + } + + public static Set loadFullServerPackExclude(Path serverConfigPath) { + Set excludedFiles = new HashSet<>(); + + if (!Files.exists(serverConfigPath)) return excludedFiles; + + try (Reader reader = Files.newBufferedReader(serverConfigPath)) { + JsonObject json = JsonParser.parseReader(reader).getAsJsonObject(); + JsonArray excluded = json.getAsJsonArray("ServerPackExcluded"); + if (excluded != null) { + for (JsonElement e : excluded) { + excludedFiles.add(e.getAsString()); + } + } + } catch (IOException | JsonParseException e) { + LOGGER.error("Error in automodpack-server.json with FullServerPack exclude", e); + } + + return excludedFiles; + } } diff --git a/core/src/main/java/pl/skidam/automodpack_core/config/Jsons.java b/core/src/main/java/pl/skidam/automodpack_core/config/Jsons.java index 5313bef08..20bc39fe4 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/config/Jsons.java +++ b/core/src/main/java/pl/skidam/automodpack_core/config/Jsons.java @@ -63,15 +63,24 @@ public static class ServerConfigFieldsV1 { public String modpackName = ""; public boolean modpackHost = true; public boolean generateModpackOnStart = true; - public List syncedFiles = List.of("/mods/*.jar", "/kubejs/**", "!/kubejs/server_scripts/**", "/emotes/*"); - public List allowEditsInFiles = List.of("/options.txt", "/config/**"); + public List syncedFiles = List.of("/mods/*.jar", "/kubejs/**", "!/kubejs/server_scripts/**", "/emotes/*", "!/mods/iDontWantThisModInModpack.jar", "!/config/andThisConfigToo.json", "!/mods/andAllTheseMods-*.jar", "!/mods/server-*.jar"); + public List allowEditsInFiles = List.of("/options.txt", "/config/**", "!/config/excludeThisFile"); + public boolean enableFullServerPack = false; + public List ServerPackExcluded = List.of("!/config/bottokens.toml", "!/config/ipadresses.json"); public boolean autoExcludeUnnecessaryFiles = true; + //public List forceLoad = List.of("/resourcepacks/someResourcePack.zip", "/shaderpacks/someShaderPack.zip"); + //public List> forceLoad = new ArrayList<>(); + public boolean requireAutoModpackOnClient = true; public boolean nagUnModdedClients = true; public String nagMessage = "This server provides dedicated modpack through AutoModpack!"; public String nagClickableMessage = "Click here to get the AutoModpack!"; public String nagClickableLink = "https://modrinth.com/project/automodpack"; public boolean autoExcludeServerSideMods = true; + + //public boolean velocityMode = false; compat plugin... someday I hope + //public boolean forceToDisableAllOtherModsOnClients = false; + public boolean hostModpackOnMinecraftPort = true; public String hostIp = ""; public String hostLocalIp = ""; @@ -113,6 +122,63 @@ public static class ServerConfigFieldsV2 { public List acceptedLoaders; } + public static class GroupDeclaration { + public String groupName = ""; //Also Modpack Name? + public boolean generateModpackOnStart = true; + public List syncedFiles = List.of(); + public List allowEditsInFiles = List.of(); + public List forceCopyFilesToStandardLocation = List.of(); + public boolean autoExcludeServerSideMods = true; + public boolean autoExcludeUnnecessaryFiles = true; + public boolean required = false; + public boolean checkByDefault = false; + public List breaksWith = List.of(); + public List requiredBy = List.of(); + public List compatibleOS = List.of(); + } + + public static GroupDeclaration mainGroupDeclaration() { + GroupDeclaration decl = new GroupDeclaration(); + decl.groupName = "main"; + decl.required = true; + decl.checkByDefault = true; + decl.syncedFiles = List.of("/mods/*.jar", "/kubejs/**", "!/kubejs/server_scripts/**", "/emotes/*"); + decl.allowEditsInFiles = List.of("/options.txt", "/config/**"); + return decl; + } + + public static GroupDeclaration hostGroupDeclaration() { + GroupDeclaration decl = new GroupDeclaration(); + decl.groupName = "host"; //also modpackname? + return decl; + } + + public static class ServerConfigFieldsV3 { + public int DO_NOT_CHANGE_IT = 3; // file version + public boolean modpackHost = true; + public boolean enableFullServerPack = false; + public Map groups = Map.of( + "main", mainGroupDeclaration(), + "host", hostGroupDeclaration() + ); + public boolean requireAutoModpackOnClient = true; + public boolean nagUnModdedClients = true; + public String nagMessage = "This server provides dedicated modpack through AutoModpack!"; + public String nagClickableMessage = "Click here to get the AutoModpack!"; + public String nagClickableLink = "https://modrinth.com/project/automodpack"; + public String bindAddress = ""; + public int bindPort = -1; + public String addressToSend = ""; + public int portToSend = -1; + public boolean disableInternalTLS = false; + public boolean updateIpsOnEveryStart = false; + public int bandwidthLimit = 0; + public boolean validateSecrets = true; + public long secretLifetime = 336; // 336 hours = 14 days + public boolean selfUpdater = false; + public List acceptedLoaders; + } + public static class ServerCoreConfigFields { public String automodpackVersion = "4.0.0-beta37"; // TODO: dont hardcode it public String loader = "fabric"; @@ -128,19 +194,38 @@ public static class KnownHostsFields { public Map hosts; // host, fingerprint } - public static class ModpackContentFields { - public String modpackName = ""; + public static class ModpackContentMasterFields { public String automodpackVersion = ""; public String loader = ""; public String loaderVersion = ""; public String mcVersion = ""; + public boolean enableFullServerPack = false; + public Set groups; + + public ModpackContentMasterFields(Set groups) { + this.groups = groups; + } + + public ModpackContentMasterFields() { + this.groups = Set.of(); + } + } + + public static class ModpackGroupFields { + public String groupName = ""; //also modpack name? + public String automodpackVersion = ""; + public String loader = ""; + public String loaderVersion = ""; + public String mcVersion = ""; + public String modpackName = ""; + public boolean enableFullServerPack = false; public Set list; - public ModpackContentFields(Set list) { + public ModpackGroupFields(Set list) { this.list = list; } - public ModpackContentFields() { + public ModpackGroupFields() { this.list = Set.of(); } @@ -169,4 +254,43 @@ public String toString() { } } } -} + + public static class FullServerPackContentFields { + public String modpackName = ""; + public String mcVersion = ""; + public String loader = ""; + public Set list; + + public FullServerPackContentFields(String modpackName, String mcVersion, String loader, Set list) { + this.modpackName = modpackName; + this.mcVersion = mcVersion; + this.loader = loader; + this.list = list; + } + + public FullServerPackContentFields() { + this.list = Set.of(); + } + + public static class FullServerPackContentItem { + public String file; + public String size; + public String type; + public String sha1; + public String murmur; + + public FullServerPackContentItem(String file, String size, String type, String sha1, String murmur) { + this.file = file; + this.size = size; + this.type = type; + this.sha1 = sha1; + this.murmur = murmur; + } + + @Override + public String toString() { + return String.format("FullServerPackContentItem(file=%s, size=%s, type=%s, sha1=%s, murmur=%s)", file, size, type, sha1, murmur); + } + } + } +} \ No newline at end of file diff --git a/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPack.java b/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPack.java new file mode 100644 index 000000000..49eb28382 --- /dev/null +++ b/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPack.java @@ -0,0 +1,107 @@ +package pl.skidam.automodpack_core.modpack; + +import pl.skidam.automodpack_core.config.ConfigTools; +import pl.skidam.automodpack_core.config.Jsons; +import pl.skidam.automodpack_core.utils.CustomFileUtils; +import pl.skidam.automodpack_core.utils.CustomThreadFactoryBuilder; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static pl.skidam.automodpack_core.GlobalVariables.*; + +public class FullServerPack { + public final ModpackExecutor executor; + + public final Map fullpacks = Collections.synchronizedMap(new HashMap<>()); + + public FullServerPack(ModpackExecutor executor) { + this.executor = executor; + } + + + + private FullServerPackContent init() { + LOGGER.info("init() von FullServerPack wurde aufgerufen"); + if (isGenerating()) { + LOGGER.error("Called generate() twice!"); + return null; + } + + // Load config if Fullpack is enabled + Path serverConfigFile = CustomFileUtils.getPathFromCWD("automodpack/automodpack-server.json"); + if (!Files.exists(serverConfigFile)) { + LOGGER.error("Server config file not found!"); + return null; + } + + Jsons.ServerConfigFieldsV3 serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV3.class); + if (serverConfig == null || !serverConfig.enableFullServerPack) { + LOGGER.info("FullServerPack is disabled."); + return null; + } + + try { + if (!Files.exists(hostModpackDir)) { + Files.createDirectories(hostModpackDir); + } + } catch (IOException e) { + LOGGER.error("Failed to create modpack directory", e); + e.printStackTrace(); + return null; + } + + // Use a fixed name for the full server pack + return new FullServerPackContent("FullServerPack", hostModpackDir, executor.getExecutor()); + } + + public boolean generateNew(FullServerPackContent content) { + if (content == null) return false; + boolean generated = content.create(); + fullpacks.put(content.getModpackName(), content); + return generated; + } + + public boolean generateNew() { + FullServerPackContent content = init(); + if (content == null) return false; + boolean generated = content.create(); + fullpacks.put(content.getModpackName(), content); + return generated; + } + + public boolean isGenerating() { + return executor.isRunning(); + /* Old executer + + int activeCount = CREATION_EXECUTOR.getActiveCount(); + int queueSize = CREATION_EXECUTOR.getQueue().size(); + return activeCount > 0 || queueSize > 0; + + */ + } + + public void shutdownExecutor() { + executor.stop(); + + /* Old executer + CREATION_EXECUTOR.shutdown(); + + try { + if (!CREATION_EXECUTOR.awaitTermination(5, TimeUnit.SECONDS)) { + CREATION_EXECUTOR.shutdownNow(); + if (!CREATION_EXECUTOR.awaitTermination(3, TimeUnit.SECONDS)) { + LOGGER.error("CREATION Executor did not terminate"); + } + } + } catch (InterruptedException e) { + CREATION_EXECUTOR.shutdownNow(); + } + */ + + } +} \ No newline at end of file diff --git a/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPackContent.java b/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPackContent.java new file mode 100644 index 000000000..e7ec0521a --- /dev/null +++ b/core/src/main/java/pl/skidam/automodpack_core/modpack/FullServerPackContent.java @@ -0,0 +1,335 @@ +package pl.skidam.automodpack_core.modpack; + +import pl.skidam.automodpack_core.config.*; +import pl.skidam.automodpack_core.utils.CustomFileUtils; +import pl.skidam.automodpack_core.utils.FileInspection; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; + +import static pl.skidam.automodpack_core.GlobalVariables.*; + +public class FullServerPackContent { + + public final Set list = Collections.synchronizedSet(new HashSet<>()); + private final String MODPACK_NAME; + private final Path MODPACK_DIR; + private final ThreadPoolExecutor CREATION_EXECUTOR; + private final Map sha1MurmurMapPreviousContent = new HashMap<>(); + + public FullServerPackContent(String modpackName, Path modpackDir, ThreadPoolExecutor executor) { + this.MODPACK_NAME = modpackName; + this.MODPACK_DIR = modpackDir; + this.CREATION_EXECUTOR = executor; + } + + public String getModpackName() { + return MODPACK_NAME; + } + + public boolean create() { + LOGGER.info("FullServerPackContent.create() is called"); + try { + LOGGER.info("Creating Full Server Pack for: {}", MODPACK_NAME); + + Path serverConfigFile = CustomFileUtils.getPathFromCWD("automodpack/automodpack-server.json"); + if (!Files.exists(serverConfigFile)) { + LOGGER.warn("Serverconfigfile is missing, did you delete it?: {}", serverConfigFile); + return false; + } + + // Use the latest version of server config + Jsons.ServerConfigFieldsV3 serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV3.class); + if (serverConfig == null || !serverConfig.modpackHost) { + LOGGER.info("FullServerPack creation is disabled or config invalid."); + return false; + } + + List filesToInclude = new ArrayList<>(); + + //check synced files but not excluded, because we will get all files + Jsons.GroupDeclaration mainGroup = serverConfig.groups.get("main"); + List syncedFilePaths = mainGroup != null ? mainGroup.syncedFiles : new ArrayList<>(); + + for (String relativePath : syncedFilePaths) { + Path path = CustomFileUtils.getPathFromCWD(relativePath); + if (!Files.exists(path) || Files.isDirectory(path)) continue; + + String formatted = "/" + relativePath.replace("\\", "/"); + LOGGER.info("included from syncedFiles: {}", formatted); + filesToInclude.add(path); + } + + //adding default folders + List includeDefaultDirs = List.of( + CustomFileUtils.getPathFromCWD("mods"), + CustomFileUtils.getPathFromCWD("config"), + CustomFileUtils.getPathFromCWD("resourcepacks"), + CustomFileUtils.getPathFromCWD("shaderpacks") + //add more folders like KubeJS? or something whats needed, what not to be generated automaticly? + ); + + for (Path dir : includeDefaultDirs) { + if (!Files.exists(dir)) continue; + + try (Stream files = Files.walk(dir)) { + files.filter(Files::isRegularFile).forEach(path -> { + if (filesToInclude.contains(path)) return; + + String relative = CustomFileUtils.getPathFromCWD("").relativize(path).toString().replace("\\", "/"); + String formatted = "/" + relative; + + LOGGER.info("included from default folders: {}", formatted); + filesToInclude.add(path); + }); + } catch (Exception e) { + LOGGER.error("Error while looking in folders: {}", dir, e); + } + } + // automodpack-host folders and files adding + Path automodpackHostFolder = CustomFileUtils.getPathFromCWD("automodpack/host-modpack"); + if (Files.exists(automodpackHostFolder) && Files.isDirectory(automodpackHostFolder)) { + try (Stream files = Files.walk(automodpackHostFolder)) { + files.filter(Files::isRegularFile).forEach(path -> { + LOGGER.info("Gefundene Datei: {}", path.toAbsolutePath()); + String fileName = path.getFileName().toString().toLowerCase(); + if (fileName.equals("fullserverpack-content.json") || fileName.equals("automodpack-content.json")) { + LOGGER.info("skipped content files from automodpack-host: {}", fileName); + return; + } + + String relative = CustomFileUtils.getPathFromCWD("").relativize(path).toString().replace("\\", "/"); + String formatted = "/" + relative; + + LOGGER.info("included from automodpack-host: {}", formatted); + filesToInclude.add(path); + }); + } catch (Exception e) { + LOGGER.error("Error while looking in the automodpack-host folder: {}", automodpackHostFolder, e); + } + } + + // add server config itself + LOGGER.info("automodpack server config import: {}", serverConfigFile); + filesToInclude.add(serverConfigFile); + + // exclude files from loadFullServerPackExclude config defined + Set excludedFullPackFiles = ConfigTools.loadFullServerPackExclude(serverConfigFile); + + filesToInclude.removeIf(path -> { + String formatted = "/" + CustomFileUtils.getPathFromCWD("").relativize(path).toString().replace("\\", "/"); + boolean isExcluded = excludedFullPackFiles.stream().anyMatch(rule -> { + if (rule.startsWith("!")) rule = rule.substring(1); + return rule.equalsIgnoreCase(formatted); + }); + + if (isExcluded) { + LOGGER.info("excluded files from config defined: {}", formatted); + } + return isExcluded; + }); + + // generate content and save it + Jsons.FullServerPackContentFields fullServerContent = buildFullServerPackContent(filesToInclude); + + Path outputPath = hostModpackDir.resolve("fullserverpack-content.json"); + ConfigTools.saveFullServerPackContent(outputPath, fullServerContent); + + LOGGER.info("FullServerPack content saved to: {}", outputPath.toAbsolutePath()); + return true; + + } catch (Exception e) { + LOGGER.error("Error during FullServerPack creation", e); + return false; + } + } + + private List collectFiles(Jsons.ServerConfigFieldsV3 serverConfig) { + List filesToInclude = new ArrayList<>(); + return filesToInclude; + } + + public Jsons.FullServerPackContentFields buildFullServerPackContent(List files) { + Set contentList = + Collections.synchronizedSet(new HashSet<>()); + + //ADDED ATOMICInteger to read, how much files are processed + AtomicInteger processed = new AtomicInteger(); + + List> futures = new ArrayList<>(); + + for (int i = 0; i < files.size(); i += 6) { + List subList = files.subList(i, Math.min(files.size(), i + 6)); + futures.add(CompletableFuture.runAsync(() -> { + for (Path file : subList) { + generate(file, contentList); + int done = processed.incrementAndGet(); + LOGGER.info("Files processed {} / {}", done, files.size()); + } + }, CREATION_EXECUTOR)); // use class defined executer + } + + futures.forEach(CompletableFuture::join); + + return new Jsons.FullServerPackContentFields(MODPACK_NAME, MC_VERSION, LOADER, contentList); + } + + private void generate(Path file, Set contentList) { + try { + if (!Files.isRegularFile(file)) return; + + String formattedFile = CustomFileUtils.formatPath(file, CustomFileUtils.getPathFromCWD("")); + if (formattedFile.startsWith("/automodpack/")) return; + + String size = String.valueOf(Files.size(file)); + + //exclude invalid files + if (size.equals("0") || file.getFileName().toString().startsWith(".") || formattedFile.endsWith(".tmp") || formattedFile.endsWith(".bak") || formattedFile.endsWith(".disabled")) { + LOGGER.info("Skipping file {}, because they are invalid and not needed in fullserverModpack Content", formattedFile); + return; + } + + String type; + if (FileInspection.isMod(file)) { + type = "mod"; + if ((MOD_ID + "-bootstrap").equals(FileInspection.getModID(file))) { + return; + } + } else if (formattedFile.contains("/config/")) { + type = "config"; + } else if (formattedFile.contains("/shaderpacks/")) { + type = "shader"; + } else if (formattedFile.contains("/resourcepacks/")) { + type = "resourcepack"; + } else if (formattedFile.endsWith("/options.txt")) { + type = "mc_options"; + } else { + type = "other"; + } + + String sha1 = CustomFileUtils.getHash(file); + String murmur = null; + if (type.equals("mod") || type.equals("shader") || type.equals("resourcepack")) { + murmur = CustomFileUtils.getCurseforgeMurmurHash(file); + } + + String cleanedFile = formattedFile.replaceAll("^/+", "/"); + var item = new Jsons.FullServerPackContentFields.FullServerPackContentItem(cleanedFile, size, type, sha1, murmur); + contentList.add(item); + + } catch (Exception e) { + LOGGER.warn("Could not add file for FullServerPackContent: {}", file, e); + } + } + + // if creation the full pack work, generate from server config is not needed anymore + public static void generateFromServerConfig() { + try { + LOGGER.info("start generating server pack content file"); + Path automodpackserverConfig = CustomFileUtils.getPathFromCWD("automodpack/automodpack-server.json"); + + if (!Files.exists(automodpackserverConfig)) { + LOGGER.info("automodpack-server.json is missing? did you delete the file?"); + return; + } + + // Use the latest version of server config (V3) + Jsons.ServerConfigFieldsV3 serverConfig = ConfigTools.load(automodpackserverConfig, Jsons.ServerConfigFieldsV3.class); + if (serverConfig == null || !serverConfig.modpackHost) { + LOGGER.info("Fullserverpack creation on default disabled."); + return; + } + Set excludedFiles = ConfigTools.loadFullServerPackExclude(automodpackserverConfig); + List filesToInclude = new ArrayList<>(); + + //check synced files + Jsons.GroupDeclaration mainGroup = serverConfig.groups.get("main"); + List syncedFilePaths = mainGroup != null ? mainGroup.syncedFiles : new ArrayList<>(); + + for (String relativePath : syncedFilePaths) { + Path path = CustomFileUtils.getPathFromCWD(relativePath); + if (!Files.exists(path) || Files.isDirectory(path)) continue; + String formatted = "/" + relativePath.replace("\\", "/"); + + LOGGER.info("included from syncedFiles: {}", formatted); + filesToInclude.add(path); + } + + // look for paths on default folders + List includeDefaultDirs = List.of( + CustomFileUtils.getPathFromCWD("mods"), + CustomFileUtils.getPathFromCWD("config"), + CustomFileUtils.getPathFromCWD("resourcepacks"), + CustomFileUtils.getPathFromCWD("shaderpacks") + //adding library or other folders like kubejs? + ); + //Check default folders if not in synced files declared + for (Path dir : includeDefaultDirs) { + if (!Files.exists(dir)) continue; + + try (Stream files = Files.walk(dir)) { + files.filter(Files::isRegularFile).forEach(path -> { + // check if already included + if (filesToInclude.contains(path)) return; + + String relative = CustomFileUtils.getPathFromCWD("").relativize(path).toString().replace("\\", "/"); + String formatted = ("/" + relative).replaceAll("^/+", "/"); + + LOGGER.info("included from defaultdir: {}", formatted); + filesToInclude.add(path); + }); + } catch (Exception e) { + LOGGER.error("Error while walking through folder: {}", dir, e); + } + } + // automodpack server config import + if (Files.exists(automodpackserverConfig)) { + LOGGER.info("automodpack server config import: {}", automodpackserverConfig); + filesToInclude.add(automodpackserverConfig); + } + + // adding client mod folders from automodpack host + Path automodpackHostDir = CustomFileUtils.getPathFromCWD("automodpack/host-modpack"); + if (Files.exists(automodpackHostDir) && Files.isDirectory(automodpackHostDir)) { + try (Stream files = Files.walk(automodpackHostDir)) { + files.filter(Files::isRegularFile).forEach(path -> { + String fileName = path.getFileName().toString().toLowerCase(); + if (fileName.equals("fullserverpack-content.json") || fileName.equals("automodpack-content.json")) { + LOGGER.info("skipped content files from automodpack-host: {}", fileName); + return; + } + + String relative = CustomFileUtils.getPathFromCWD("").relativize(path).toString().replace("\\", "/"); + String formatted = "/" + relative; + + LOGGER.info("included from automodpack-host: {}", formatted); + filesToInclude.add(path); + }); + } catch (Exception e) { + LOGGER.error("Error while walking through automodpack-host folder: {}", automodpackHostDir, e); + } + } + + try { + FullServerPackContent fullServerPack = new FullServerPackContent("FullServer", CustomFileUtils.getPathFromCWD("automodpack/host-modpack"), (ThreadPoolExecutor) Executors.newFixedThreadPool(4)); + Jsons.FullServerPackContentFields fullServerContent = fullServerPack.buildFullServerPackContent(filesToInclude); + + Path outputPath = CustomFileUtils.getPathFromCWD("automodpack/host-modpack/fullserverpack-content.json"); + ConfigTools.saveFullServerPackContent(outputPath, fullServerContent); + + LOGGER.info("servermodpack content file saved under: {}", outputPath); + } catch (Exception e) { + LOGGER.error("error on creation from fullserverpack-content.json", e); + } + } catch (Exception e) { + LOGGER.error("ERROR ON CREATION?", e); + } + } + +} diff --git a/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackContent.java b/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackContent.java index 9831cdcb5..059ba14d6 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackContent.java +++ b/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackContent.java @@ -15,17 +15,19 @@ import static pl.skidam.automodpack_core.GlobalVariables.LOGGER; public class ModpackContent { - public final Set list = Collections.synchronizedSet(new HashSet<>()); + public final Set list = Collections.synchronizedSet(new HashSet<>()); public final ObservableMap pathsMap = new ObservableMap<>(); private final String MODPACK_NAME; private final WildCards SYNCED_FILES_CARDS; private final WildCards EDITABLE_CARDS; private final WildCards FORCE_COPY_FILES_TO_STANDARD_LOCATION; + private final boolean AUTO_EXCLUDE_UNNECESSARY_FILES; + private final boolean AUTO_EXCLUDE_SERVER_SIDE_MODS; private final Path MODPACK_DIR; private final ThreadPoolExecutor CREATION_EXECUTOR; private final Map sha1MurmurMapPreviousContent = new HashMap<>(); - public ModpackContent(String modpackName, Path cwd, Path modpackDir, List syncedFiles, List allowEditsInFiles, List forceCopyFilesToStandardLocation, ThreadPoolExecutor CREATION_EXECUTOR) { + public ModpackContent(String modpackName, Path cwd, Path modpackDir, List syncedFiles, List allowEditsInFiles, List forceCopyFilesToStandardLocation, boolean autoExcludeUnnecessaryFiles, boolean autoExcludeServerSideMods, ThreadPoolExecutor CREATION_EXECUTOR) { this.MODPACK_NAME = modpackName; this.MODPACK_DIR = modpackDir; Set directoriesToSearch = new HashSet<>(2); @@ -38,6 +40,8 @@ public ModpackContent(String modpackName, Path cwd, Path modpackDir, List getPreviousContent() { + public Optional getPreviousContent() { var optionalModpackContentFile = ModpackContentTools.getModpackContentFile(MODPACK_DIR); return optionalModpackContentFile.map(ConfigTools::loadModpackContent); } @@ -108,12 +116,12 @@ public Optional getPreviousContent() { public boolean loadPreviousContent() { var optionalModpackContent = getPreviousContent(); if (optionalModpackContent.isEmpty()) return false; - Jsons.ModpackContentFields modpackContent = optionalModpackContent.get(); + Jsons.ModpackGroupFields modpackContent = optionalModpackContent.get(); synchronized (list) { list.addAll(modpackContent.list); - for (Jsons.ModpackContentFields.ModpackContentItem modpackContentItem : list) { + for (Jsons.ModpackGroupFields.ModpackContentItem modpackContentItem : list) { Path file = CustomFileUtils.getPath(MODPACK_DIR, modpackContentItem.file); if (!Files.exists(file)) file = CustomFileUtils.getPathFromCWD(modpackContentItem.file); if (!Files.exists(file)) { @@ -138,15 +146,31 @@ public boolean loadPreviousContent() { // This is important to make it synchronized otherwise it could corrupt the file and crash public synchronized void saveModpackContent() { synchronized (list) { - Jsons.ModpackContentFields modpackContent = new Jsons.ModpackContentFields(list); - + Jsons.ModpackGroupFields modpackContent = new Jsons.ModpackGroupFields(list); + modpackContent.groupName = MODPACK_NAME; + + // Set version information and server pack permission modpackContent.automodpackVersion = AM_VERSION; modpackContent.mcVersion = MC_VERSION; modpackContent.loaderVersion = LOADER_VERSION; modpackContent.loader = LOADER; modpackContent.modpackName = MODPACK_NAME; + modpackContent.enableFullServerPack = serverConfig.enableFullServerPack; + + ConfigTools.saveModpackContent(getModpackContentFile(), modpackContent); + + synchronized (hostModpackContentFile) { + Jsons.ModpackContentMasterFields masterContent = ConfigTools.load(hostModpackContentFile, Jsons.ModpackContentMasterFields.class); + if (masterContent == null) { + masterContent = new Jsons.ModpackContentMasterFields(); + } - ConfigTools.saveModpackContent(hostModpackContentFile, modpackContent); + masterContent.groups.removeIf(group -> group.groupName.equals(MODPACK_NAME)); + masterContent.groups.add(modpackContent); + + // Save the master content file + ConfigTools.save(hostModpackContentFile, masterContent); + } } } @@ -163,7 +187,7 @@ private List> generateAsync(List files) { private void generate(Path file) { try { - Jsons.ModpackContentFields.ModpackContentItem item = generateContent(file); + Jsons.ModpackGroupFields.ModpackContentItem item = generateContent(file); if (item != null) { LOGGER.info("generated content for {}", item.file); synchronized (list) { @@ -190,7 +214,7 @@ public void remove(Path file) { String modpackFile = CustomFileUtils.formatPath(file, MODPACK_DIR); synchronized (list) { - for (Jsons.ModpackContentFields.ModpackContentItem item : this.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem item : this.list) { if (item.file.equals(modpackFile)) { this.pathsMap.remove(item.sha1); this.list.remove(item); @@ -213,14 +237,9 @@ public static boolean isInnerFile(Path file) { return isInner; } - private Jsons.ModpackContentFields.ModpackContentItem generateContent(final Path file) throws Exception { + private Jsons.ModpackGroupFields.ModpackContentItem generateContent(final Path file) throws Exception { if (!Files.isRegularFile(file)) return null; - if (serverConfig == null) { - LOGGER.error("Server config is null!"); - return null; - } - if (isInnerFile(file)) { return null; } @@ -234,7 +253,7 @@ private Jsons.ModpackContentFields.ModpackContentItem generateContent(final Path final String size = String.valueOf(Files.size(file)); - if (serverConfig.autoExcludeUnnecessaryFiles) { + if (AUTO_EXCLUDE_UNNECESSARY_FILES) { if (size.equals("0")) { LOGGER.info("Skipping file {} because it is empty", formattedFile); return null; @@ -265,7 +284,7 @@ private Jsons.ModpackContentFields.ModpackContentItem generateContent(final Path if (FileInspection.isMod(file)) { type = "mod"; - if (serverConfig.autoExcludeServerSideMods && Objects.equals(FileInspection.getModEnvironment(file), LoaderManagerService.EnvironmentType.SERVER)) { + if (AUTO_EXCLUDE_SERVER_SIDE_MODS && Objects.equals(FileInspection.getModEnvironment(file), LoaderManagerService.EnvironmentType.SERVER)) { LOGGER.info("File {} is server mod! Skipping...", formattedFile); return null; } @@ -310,7 +329,7 @@ private Jsons.ModpackContentFields.ModpackContentItem generateContent(final Path LOGGER.info("File {} is forced to copy to standard location!", formattedFile); } - return new Jsons.ModpackContentFields.ModpackContentItem(formattedFile, size, type, isEditable, forcedToCopy, sha1, murmur); + return new Jsons.ModpackGroupFields.ModpackContentItem(formattedFile, size, type, isEditable, forcedToCopy, sha1, murmur); } } \ No newline at end of file diff --git a/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackExecutor.java b/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackExecutor.java index 887dd7aeb..99b940caa 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackExecutor.java +++ b/core/src/main/java/pl/skidam/automodpack_core/modpack/ModpackExecutor.java @@ -14,26 +14,30 @@ public class ModpackExecutor { private final ThreadPoolExecutor CREATION_EXECUTOR = (ThreadPoolExecutor) Executors.newFixedThreadPool(Math.max(1, Runtime.getRuntime().availableProcessors() * 2), new CustomThreadFactoryBuilder().setNameFormat("AutoModpackCreation-%d").build()); public final Map modpacks = Collections.synchronizedMap(new HashMap<>()); - private ModpackContent init() { + private ModpackContent init(String groupId) { if (isGenerating()) { LOGGER.error("Called generate() twice!"); return null; } + Path modpackHostPath = hostModpackDir.resolve(groupId); + try { - if (!Files.exists(hostContentModpackDir)) { - Files.createDirectories(hostContentModpackDir); - Files.createDirectory(hostContentModpackDir.resolve("mods")); - Files.createDirectory(hostContentModpackDir.resolve("config")); - Files.createDirectory(hostContentModpackDir.resolve("shaderpacks")); - Files.createDirectory(hostContentModpackDir.resolve("resourcepacks")); + if (!Files.exists(modpackHostPath)) { + Files.createDirectories(modpackHostPath); + Files.createDirectory(modpackHostPath.resolve("mods")); + Files.createDirectory(modpackHostPath.resolve("config")); + Files.createDirectory(modpackHostPath.resolve("shaderpacks")); + Files.createDirectory(modpackHostPath.resolve("resourcepacks")); } } catch (IOException e) { e.printStackTrace(); } + var groupDecl = serverConfig.groups.get(groupId); + Path cwd = Path.of(System.getProperty("user.dir")); - return new ModpackContent(serverConfig.modpackName, cwd, hostContentModpackDir, serverConfig.syncedFiles, serverConfig.allowEditsInFiles, serverConfig.forceCopyFilesToStandardLocation, CREATION_EXECUTOR); + return new ModpackContent(groupDecl.groupName, cwd, modpackHostPath, groupDecl.syncedFiles, groupDecl.allowEditsInFiles, groupDecl.forceCopyFilesToStandardLocation, groupDecl.autoExcludeUnnecessaryFiles, groupDecl.autoExcludeServerSideMods, CREATION_EXECUTOR); } public boolean generateNew(ModpackContent content) { @@ -43,16 +47,16 @@ public boolean generateNew(ModpackContent content) { return generated; } - public boolean generateNew() { - ModpackContent content = init(); + public boolean generateNew(String groupId) { + ModpackContent content = init(groupId); if (content == null) return false; boolean generated = content.create(); modpacks.put(content.getModpackName(), content); return generated; } - public boolean loadLast() { - ModpackContent content = init(); + public boolean loadLast(String groupId) { + ModpackContent content = init(groupId); if (content == null) return false; boolean generated = content.loadPreviousContent(); modpacks.put(content.getModpackName(), content); @@ -65,6 +69,10 @@ public boolean isGenerating() { return activeCount > 0 || queueSize > 0; } + public boolean isRunning() { + return !CREATION_EXECUTOR.isShutdown() && !CREATION_EXECUTOR.isTerminated(); + } + public ThreadPoolExecutor getExecutor() { return CREATION_EXECUTOR; } diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/DownloadClient.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/DownloadClient.java index 912c4c22b..27589312f 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/DownloadClient.java +++ b/core/src/main/java/pl/skidam/automodpack_core/protocol/DownloadClient.java @@ -148,6 +148,15 @@ public CompletableFuture downloadFile(byte[] fileHash, Path destination, I return conn.sendDownloadFile(fileHash, destination, chunkCallback); } + /** + * + */ + public CompletableFuture fetchPackMeta(String groupId, Path destination, IntConsumer chunkCallback) { + Connection conn = getFreeConnection(); + return conn.sendPackMetaRequest(groupId, destination, chunkCallback); + } + + /** * Sends a refresh request with the given file hashes. */ @@ -395,6 +404,42 @@ public CompletableFuture sendDownloadFile(byte[] fileHash, Path destinatio }, executor); } + /** + * Sends a pack meta request over this connection. + */ + public CompletableFuture sendPackMetaRequest(String groupId, Path destination, IntConsumer chunkCallback) { + if (destination == null) { + throw new IllegalArgumentException("Destination cannot be null"); + } + + byte[] groupIdBytes = groupId.getBytes(); + + return CompletableFuture.supplyAsync(() -> { + Exception exception = null; + try { + // Build File Request message: + // [protocolVersion][FILE_REQUEST_TYPE][secret][int: groupIdBytes.length][groupIdBytes] + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeByte(PROTOCOL_VERSION); + dos.writeByte(FILE_REQUEST_TYPE); + dos.write(secretBytes); + dos.writeInt(groupIdBytes.length); + dos.write(groupIdBytes); + dos.flush(); + byte[] payload = baos.toByteArray(); + + writeProtocolMessage(payload); + return readFileResponse(destination, chunkCallback); + } catch (Exception e) { + exception = e; + throw new CompletionException(e); + } finally { + finalBlock(exception); + } + }, executor); + } + /** * Sends a refresh request over this connection. */ diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/NetUtils.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/NetUtils.java index cc4a0994d..a58086f8e 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/NetUtils.java +++ b/core/src/main/java/pl/skidam/automodpack_core/protocol/NetUtils.java @@ -28,7 +28,7 @@ public class NetUtils { public static final int MAGIC_AMMC = 0x414D4D43; public static final int MAGIC_AMOK = 0x414D4F4B; - public static final byte ECHO_TYPE = 0x00; + public static final byte PACK_META_REQUEST_TYPE = 0x00; public static final byte FILE_REQUEST_TYPE = 0x01; public static final byte FILE_RESPONSE_TYPE = 0x02; public static final byte REFRESH_REQUEST_TYPE = 0x03; diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageDecoder.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageDecoder.java index d73095f3c..e38845601 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageDecoder.java +++ b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageDecoder.java @@ -4,7 +4,7 @@ import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.ByteToMessageDecoder; import pl.skidam.automodpack_core.protocol.NetUtils; -import pl.skidam.automodpack_core.protocol.netty.message.EchoMessage; +import pl.skidam.automodpack_core.protocol.netty.message.PackMetaRequestMessage; import pl.skidam.automodpack_core.protocol.netty.message.FileRequestMessage; import pl.skidam.automodpack_core.protocol.netty.message.FileResponseMessage; import pl.skidam.automodpack_core.protocol.netty.message.RefreshRequestMessage; @@ -23,11 +23,11 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) t in.readBytes(secret); switch (type) { - case ECHO_TYPE: + case PACK_META_REQUEST_TYPE: int dataLength = in.readInt(); byte[] data = new byte[dataLength]; in.readBytes(data); - out.add(new EchoMessage(version, secret, data)); + out.add(new PackMetaRequestMessage(version, secret, data)); break; case FILE_REQUEST_TYPE: int fileHashLength = in.readInt(); diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageEncoder.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageEncoder.java deleted file mode 100644 index 9a8c59691..000000000 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ProtocolMessageEncoder.java +++ /dev/null @@ -1,45 +0,0 @@ -package pl.skidam.automodpack_core.protocol.netty.handler; - -import io.netty.buffer.ByteBuf; -import io.netty.channel.ChannelHandlerContext; -import io.netty.handler.codec.MessageToByteEncoder; -import pl.skidam.automodpack_core.protocol.netty.message.*; - -import static pl.skidam.automodpack_core.protocol.NetUtils.*; - -public class ProtocolMessageEncoder extends MessageToByteEncoder { - @Override - protected void encode(ChannelHandlerContext ctx, ProtocolMessage msg, ByteBuf out) throws Exception { - out.writeByte(msg.getVersion()); - out.writeByte(msg.getType()); - out.writeBytes(msg.getSecret()); - - switch (msg.getType()) { - case ECHO_TYPE: - EchoMessage echoMsg = (EchoMessage) msg; - out.writeInt(echoMsg.getDataLength()); - out.writeBytes(echoMsg.getData()); - break; - case FILE_REQUEST_TYPE: - FileRequestMessage fileRequestMessage = (FileRequestMessage) msg; - out.writeInt(fileRequestMessage.getFileHashLength()); - out.writeBytes(fileRequestMessage.getFileHash()); - break; - case FILE_RESPONSE_TYPE: - FileResponseMessage fileResponseMessage = (FileResponseMessage) msg; - out.writeInt(fileResponseMessage.getDataLength()); - out.writeBytes(fileResponseMessage.getData()); - break; - case REFRESH_REQUEST_TYPE: - RefreshRequestMessage refreshRequestMessage = (RefreshRequestMessage) msg; - out.writeInt(refreshRequestMessage.getFileHashesCount()); - out.writeInt(refreshRequestMessage.getFileHashesLength()); - for (byte[] fileHash : refreshRequestMessage.getFileHashesList()) { - out.writeBytes(fileHash); - } - break; - default: - throw new IllegalArgumentException("Unknown message type: " + msg.getType()); - } - } -} diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ServerMessageHandler.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ServerMessageHandler.java index f21968b58..fc39df5d8 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ServerMessageHandler.java +++ b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/handler/ServerMessageHandler.java @@ -8,8 +8,9 @@ import io.netty.handler.stream.ChunkedFile; import io.netty.util.CharsetUtil; import pl.skidam.automodpack_core.auth.Secrets; +import pl.skidam.automodpack_core.config.Jsons; import pl.skidam.automodpack_core.modpack.ModpackContent; -import pl.skidam.automodpack_core.protocol.netty.message.EchoMessage; +import pl.skidam.automodpack_core.protocol.netty.message.PackMetaRequestMessage; import pl.skidam.automodpack_core.protocol.netty.message.FileRequestMessage; import pl.skidam.automodpack_core.protocol.netty.message.ProtocolMessage; import pl.skidam.automodpack_core.protocol.netty.message.RefreshRequestMessage; @@ -48,19 +49,18 @@ protected void channelRead0(ChannelHandlerContext ctx, ProtocolMessage msg) thro } switch (msg.getType()) { - case ECHO_TYPE: - EchoMessage echoMsg = (EchoMessage) msg; - ByteBuf echoBuf = Unpooled.buffer(1 + 1 + msg.getSecret().length + echoMsg.getData().length); - echoBuf.writeByte(clientProtocolVersion); - echoBuf.writeByte(ECHO_TYPE); - echoBuf.writeBytes(echoMsg.getSecret()); - echoBuf.writeBytes(echoMsg.getData()); - ctx.writeAndFlush(echoBuf); - ctx.channel().close(); + case PACK_META_REQUEST_TYPE: + PackMetaRequestMessage metaRequest = (PackMetaRequestMessage) msg; + sendPackMeta(ctx, metaRequest.getData()); break; case FILE_REQUEST_TYPE: FileRequestMessage fileRequest = (FileRequestMessage) msg; - sendFile(ctx, fileRequest.getFileHash()); + Path filePath = resolveFile(fileRequest.getFileHash()); + if (filePath == null) { + sendError(ctx, (byte) 1, "File not found"); + } else { + sendFile(ctx, filePath); + } break; case REFRESH_REQUEST_TYPE: RefreshRequestMessage refreshRequest = (RefreshRequestMessage) msg; @@ -108,7 +108,7 @@ private void refreshModpackFiles(ChannelHandlerContext context, byte[][] FileHas LOGGER.info("Sending new modpack-content.json"); // Sends new json - sendFile(context, new byte[0]); + sendPackMeta(context, new byte[0]); } @@ -130,16 +130,40 @@ private boolean validateSecret(ChannelHandlerContext ctx, SocketAddress address, return valid; } - private void sendFile(ChannelHandlerContext ctx, byte[] bsha1) throws IOException { + private void sendPackMeta(ChannelHandlerContext ctx, byte[] data) throws IOException { + final String groupId = new String(data, CharsetUtil.UTF_8); + Jsons.GroupDeclaration requestedGroup = null; + if (!groupId.isBlank()) { + requestedGroup = serverConfig.groups.getOrDefault(groupId, null); + } + + if (requestedGroup == null) { + sendError(ctx, PROTOCOL_VERSION, "Group not found: " + groupId); + return; + } + + ModpackContent modpackContent = modpackExecutor.modpacks.get(requestedGroup.groupName); + Path hostModpackContentFile = modpackContent.getModpackContentFile(); + if (hostModpackContentFile == null || !Files.exists(hostModpackContentFile)) { + sendError(ctx, PROTOCOL_VERSION, "Modpack content file not found for group: " + groupId); + return; + } + + sendFile(ctx, hostModpackContentFile); + } + + private Path resolveFile(byte[] bsha1) { final String sha1 = new String(bsha1, CharsetUtil.UTF_8); final Optional optionalPath = resolvePath(sha1); - if (optionalPath.isEmpty() || !Files.exists(optionalPath.get())) { - sendError(ctx, (byte) 1, "File not found"); - return; + if (optionalPath.isPresent() && Files.exists(optionalPath.get())) { + return optionalPath.get(); } - final Path path = optionalPath.get(); + return null; + } + + private void sendFile(ChannelHandlerContext ctx, Path path) throws IOException { final long fileSize = Files.size(path); // Send file response header: version, FILE_RESPONSE type, then file size (8 bytes) diff --git a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/EchoMessage.java b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/PackMetaRequestMessage.java similarity index 55% rename from core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/EchoMessage.java rename to core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/PackMetaRequestMessage.java index e13a0110d..1a72e4bc6 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/EchoMessage.java +++ b/core/src/main/java/pl/skidam/automodpack_core/protocol/netty/message/PackMetaRequestMessage.java @@ -1,13 +1,13 @@ package pl.skidam.automodpack_core.protocol.netty.message; -import static pl.skidam.automodpack_core.protocol.NetUtils.ECHO_TYPE; +import static pl.skidam.automodpack_core.protocol.NetUtils.*; -public class EchoMessage extends ProtocolMessage { +public class PackMetaRequestMessage extends ProtocolMessage { private final int dataLength; private final byte[] data; - public EchoMessage(byte version, byte[] secret, byte[] data) { - super(version, ECHO_TYPE, secret); + public PackMetaRequestMessage(byte version, byte[] secret, byte[] data) { + super(version, PACK_META_REQUEST_TYPE, secret); this.dataLength = data.length; this.data = data; } @@ -19,4 +19,4 @@ public int getDataLength() { public byte[] getData() { return data; } -} +} \ No newline at end of file diff --git a/core/src/main/java/pl/skidam/automodpack_core/utils/CustomFileUtils.java b/core/src/main/java/pl/skidam/automodpack_core/utils/CustomFileUtils.java index 8fa727290..9871277b4 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/utils/CustomFileUtils.java +++ b/core/src/main/java/pl/skidam/automodpack_core/utils/CustomFileUtils.java @@ -163,7 +163,7 @@ public static String formatPath(final Path modpackFile, final Path modpackPath) } - public static void deleteDummyFiles(Path directory, Set ignoreList) { + public static void deleteDummyFiles(Path directory, Set ignoreList) { if (directory == null || ignoreList == null) { return; } @@ -180,14 +180,14 @@ public static void deleteDummyFiles(Path directory, Set ignoreList) { + private static boolean shouldIgnore(Path file, Set ignoreList) { if (ignoreList == null) { return false; } - String modpackFile = CustomFileUtils.formatPath(file, Objects.requireNonNullElse(selectedModpackDir, hostContentModpackDir)); + String modpackFile = CustomFileUtils.formatPath(file, Objects.requireNonNullElse(selectedModpackDir, mainHostContentModpackDir)); - for (Jsons.ModpackContentFields.ModpackContentItem item : ignoreList) { + for (Jsons.ModpackGroupFields.ModpackContentItem item : ignoreList) { if (item.file.equals(modpackFile)) { return true; } diff --git a/core/src/main/java/pl/skidam/automodpack_core/utils/ModpackContentTools.java b/core/src/main/java/pl/skidam/automodpack_core/utils/ModpackContentTools.java index bd24f32bc..e77e012c9 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/utils/ModpackContentTools.java +++ b/core/src/main/java/pl/skidam/automodpack_core/utils/ModpackContentTools.java @@ -9,8 +9,9 @@ import static pl.skidam.automodpack_core.GlobalVariables.*; public class ModpackContentTools { - public static String getFileType(String file, Jsons.ModpackContentFields list) { - for (Jsons.ModpackContentFields.ModpackContentItem item : list.list) { + + public static String getFileType(String file, Jsons.ModpackGroupFields list) { + for (Jsons.ModpackGroupFields.ModpackContentItem item : list.list) { if (item.file.contains(file)) { // compare file absolute path if it contains item.file return item.type; } @@ -24,7 +25,6 @@ public static Optional getModpackDir(String modpack) { } // eg. modpack = /automodpack/modpacks/TestPack `directory` - return Optional.of(modpacksDir.resolve(modpack)); } @@ -43,4 +43,4 @@ public static Optional getModpackContentFile(Path modpackDir) { return Optional.of(path); } -} +} \ No newline at end of file diff --git a/core/src/main/java/pl/skidam/automodpack_core/utils/WorkaroundUtil.java b/core/src/main/java/pl/skidam/automodpack_core/utils/WorkaroundUtil.java index 931fab77f..64f9e544a 100644 --- a/core/src/main/java/pl/skidam/automodpack_core/utils/WorkaroundUtil.java +++ b/core/src/main/java/pl/skidam/automodpack_core/utils/WorkaroundUtil.java @@ -17,7 +17,7 @@ public WorkaroundUtil(Path modapckPath) { // returns list of formatted modpack files which are mods with services (these mods need special treatment in order to work properly) // mods returned by this method should be installed in standard `~/mods/` directory - public Set getWorkaroundMods(Jsons.ModpackContentFields modpackContentFields) { + public Set getWorkaroundMods(Jsons.ModpackGroupFields modpackGroupFields) { Set workaroundMods = new HashSet<>(); // this workaround is needed only for neo/forge mods @@ -25,7 +25,7 @@ public Set getWorkaroundMods(Jsons.ModpackContentFields modpackContentFi return workaroundMods; } - for (Jsons.ModpackContentFields.ModpackContentItem item : modpackContentFields.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem item : modpackGroupFields.list) { if (item.type.equals("mod")) { Path modPath = CustomFileUtils.getPath(modpackPath, item.file); if (FileInspection.hasSpecificServices(modPath)) { diff --git a/core/src/test/java/pl/skidam/automodpack_core/modpack/ModpackTest.java b/core/src/test/java/pl/skidam/automodpack_core/modpack/ModpackTest.java index e97b197fb..92602efc6 100644 --- a/core/src/test/java/pl/skidam/automodpack_core/modpack/ModpackTest.java +++ b/core/src/test/java/pl/skidam/automodpack_core/modpack/ModpackTest.java @@ -48,7 +48,7 @@ void modpackTest() { "ModpackContentItems(file=/mods/server-mod-1.20.jar, size=1, type=other, editable=false, sha1=86f7e437faa5a7fce15d1ddcb9eaeaea377667b8, murmur=null)" ); - ModpackContent content = new ModpackContent("TestPack", null, testFilesDir, new ArrayList<>(), new ArrayList<>(editable), new ArrayList<>(), new ModpackExecutor().getExecutor()); + ModpackContent content = new ModpackContent("TestPack", null, testFilesDir, new ArrayList<>(), new ArrayList<>(editable), new ArrayList<>(), false, false, new ModpackExecutor().getExecutor()); content.create(); boolean correct = true; diff --git a/gradle.properties b/gradle.properties index 1cc6df18a..433c74a8d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,4 +13,4 @@ mod.id = automodpack mod_name = AutoModpack mod_version = 4.0.0-beta38 mod.group = pl.skidam.automodpack -mod.description = Enjoy a seamless modpack installation process and effortless updates with a user-friendly solution that simplifies management, making your gaming experience a breeze. +mod.description = Enjoy a seamless modpack installation process and effortless updates with a user-friendly solution that simplifies management, making your gaming experience a breeze. \ No newline at end of file diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/Preload.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/Preload.java index 60217a188..5e2dc85e7 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/Preload.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/Preload.java @@ -17,6 +17,7 @@ import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.zip.ZipEntry; @@ -41,7 +42,6 @@ public Preload() { } private void updateAll() { - var optionalSelectedModpackDir = ModpackContentTools.getModpackDir(clientConfig.selectedModpack); if (LOADER_MANAGER.getEnvironmentType() == LoaderManagerService.EnvironmentType.SERVER || optionalSelectedModpackDir.isEmpty()) { @@ -69,27 +69,62 @@ private void updateAll() { Jsons.ModpackAddresses modpackAddresses = new Jsons.ModpackAddresses(selectedModpackAddress, selectedServerAddress, requiresMagic); var optionalLatestModpackContent = ModpackUtils.requestServerModpackContent(modpackAddresses, secret, false); - var latestModpackContent = ConfigTools.loadModpackContent(selectedModpackDir.resolve(hostModpackContentFile.getFileName())); + + // Laden Sie den vorhandenen Modpack-Inhalt + Jsons.ModpackContentMasterFields latestModpackContent = ConfigTools.load(selectedModpackDir.resolve(hostModpackContentFile.getFileName()), Jsons.ModpackContentMasterFields.class); // Use the latest modpack content if available if (optionalLatestModpackContent.isPresent()) { - latestModpackContent = optionalLatestModpackContent.get(); + Jsons.ModpackGroupFields serverGroupContent = optionalLatestModpackContent.get(); + + // Erstellen Sie ein MasterContent-Objekt aus der Gruppenantwort + Jsons.ModpackContentMasterFields serverMasterContent = new Jsons.ModpackContentMasterFields(); + serverMasterContent.groups = Set.of(serverGroupContent); + serverMasterContent.automodpackVersion = serverGroupContent.automodpackVersion; + serverMasterContent.loader = serverGroupContent.loader; + serverMasterContent.loaderVersion = serverGroupContent.loaderVersion; + serverMasterContent.mcVersion = serverGroupContent.mcVersion; + serverMasterContent.enableFullServerPack = serverGroupContent.enableFullServerPack; // Update AutoModpack to server version only if we can get newest modpack content - if (SelfUpdater.update(latestModpackContent)) { + if (SelfUpdater.update(serverMasterContent)) { return; } + + // Aktualisieren Sie den lokalen Inhalt mit dem Server-Inhalt + latestModpackContent = serverMasterContent; + } + + // Extract all content items from all groups for deleteDummyFiles + Set allContentItems = null; + if (latestModpackContent != null && latestModpackContent.groups != null) { + allContentItems = new HashSet<>(); + for (Jsons.ModpackGroupFields group : latestModpackContent.groups) { + if (group.list != null) { + allContentItems.addAll(group.list); + } + } } // Delete dummy files - CustomFileUtils.deleteDummyFiles(Path.of(System.getProperty("user.dir")), latestModpackContent == null ? null : latestModpackContent.list); + CustomFileUtils.deleteDummyFiles(Path.of(System.getProperty("user.dir")), allContentItems); + + // Find the main group for ModpackUpdater + Jsons.ModpackGroupFields mainGroup = null; + if (latestModpackContent != null && latestModpackContent.groups != null) { + for (Jsons.ModpackGroupFields group : latestModpackContent.groups) { + if ("main".equals(group.groupName)) { + mainGroup = group; + break; + } + } + } // Update modpack - new ModpackUpdater().prepareUpdate(latestModpackContent, modpackAddresses, secret, selectedModpackDir); + new ModpackUpdater().prepareUpdate(mainGroup, modpackAddresses, secret); } } - private void initializeGlobalVariables() { // Initialize global variables preload = true; @@ -129,12 +164,10 @@ private void loadConfigs() { clientConfigV1.DO_NOT_CHANGE_IT = 2; clientConfigV1.installedModpacks = null; } - ConfigTools.save(clientConfigFile, clientConfigV1); LOGGER.info("Updated client config version to {}", clientConfigVersion.DO_NOT_CHANGE_IT); } } - clientConfig = ConfigTools.load(clientConfigFile, Jsons.ClientConfigFieldsV2.class); } else { // TODO: when connecting to the new server which provides modpack different modpack, ask the user if they want, stop using overrides @@ -168,14 +201,32 @@ private void loadConfigs() { serverConfigV2.portToSend = serverConfigV1.hostPort; } } - ConfigTools.save(serverConfigFile, serverConfigV2); LOGGER.info("Updated server config version to {}", serverConfigVersion.DO_NOT_CHANGE_IT); } - } + if (serverConfigVersion.DO_NOT_CHANGE_IT == 2) { + var serverConfigV2 = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV2.class); + var serverConfigV3 = ConfigTools.softLoad(serverConfigFile, Jsons.ServerConfigFieldsV3.class); + if (serverConfigV2 != null && serverConfigV3 != null) { + serverConfigVersion.DO_NOT_CHANGE_IT = 3; + serverConfigV3.DO_NOT_CHANGE_IT = 3; + + serverConfigV3.groups.get("main").groupName = serverConfigV2.modpackName; + serverConfigV3.groups.get("main").generateModpackOnStart = serverConfigV2.generateModpackOnStart; + serverConfigV3.groups.get("main").autoExcludeUnnecessaryFiles = serverConfigV2.autoExcludeUnnecessaryFiles; + serverConfigV3.groups.get("main").autoExcludeServerSideMods = serverConfigV2.autoExcludeServerSideMods; + serverConfigV3.groups.get("main").allowEditsInFiles = serverConfigV2.allowEditsInFiles; + serverConfigV3.groups.get("main").syncedFiles = serverConfigV2.syncedFiles; + serverConfigV3.groups.get("main").forceCopyFilesToStandardLocation = serverConfigV2.forceCopyFilesToStandardLocation; + + ConfigTools.save(serverConfigFile, serverConfigV3); + LOGGER.info("Updated server config version to {}", serverConfigVersion.DO_NOT_CHANGE_IT); + } + } + } // load server config - serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV2.class); + serverConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV3.class); if (serverConfig != null) { // Add current loader to the list @@ -185,12 +236,14 @@ private void loadConfigs() { serverConfig.acceptedLoaders.add(LOADER); } - // Check modpack name and fix it if needed, because it will be used for naming a folder on client - if (!serverConfig.modpackName.isEmpty() && FileInspection.isInValidFileName(serverConfig.modpackName)) { - serverConfig.modpackName = FileInspection.fixFileName(serverConfig.modpackName); - LOGGER.info("Changed modpack name to {}", serverConfig.modpackName); + for (String groupId : serverConfig.groups.keySet()) { + // Check modpack name and fix it if needed, because it will be used for naming a folder on client + if (!groupId.isEmpty() && FileInspection.isInValidFileName(groupId)) { + serverConfig.groups.put(FileInspection.fixFileName(groupId), serverConfig.groups.get(groupId)); + serverConfig.groups.remove(groupId); + LOGGER.info("Changed modpack name to {}", groupId); + } } - // Save changes ConfigTools.save(serverConfigFile, serverConfig); } @@ -204,7 +257,6 @@ private void loadConfigs() { if (clientConfig.selectedModpack == null) { clientConfig.selectedModpack = ""; } - // Save changes ConfigTools.save(clientConfigFile, clientConfig); } @@ -223,7 +275,7 @@ private void loadConfigs() { if (os.contains("win")) { Files.setAttribute(privateDir, "dos:hidden", true); } else if (os.contains("nix") || os.contains("nux") || os.contains("aix") || os.contains("mac")) { - Set perms = PosixFilePermissions.fromString("rwx------"); // Corresponds to 0700 + Set perms = PosixFilePermissions.fromString("rwx------"); Files.setPosixFilePermissions(privateDir, perms); } } catch (UnsupportedOperationException | IOException e) { @@ -233,11 +285,10 @@ private void loadConfigs() { LOGGER.error("Failed to create private directory", e); } - if (serverConfig == null || clientConfig == null) { throw new RuntimeException("Failed to load config!"); } LOGGER.info("Loaded config! took {}ms", System.currentTimeMillis() - startTime); } -} +} \ No newline at end of file diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/SelfUpdater.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/SelfUpdater.java index 889efee8b..cdeec5a34 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/SelfUpdater.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/SelfUpdater.java @@ -31,7 +31,7 @@ public static boolean update () { return update(null); } - public static boolean update(Jsons.ModpackContentFields serverModpackContent) { + public static boolean update(Jsons.ModpackContentMasterFields serverModpackContentMaster) { if (LOADER_MANAGER.isDevelopmentEnvironment()) return false; if (LOADER_MANAGER.getEnvironmentType() == LoaderManagerService.EnvironmentType.SERVER && !serverConfig.selfUpdater) { @@ -43,15 +43,15 @@ public static boolean update(Jsons.ModpackContentFields serverModpackContent) { boolean gettingServerVersion = false; // Check if server version is available - if (serverModpackContent != null && serverModpackContent.automodpackVersion != null) { - modrinthAPIList.add(ModrinthAPI.getModSpecificVersion(AUTOMODPACK_ID, serverModpackContent.automodpackVersion, serverModpackContent.mcVersion)); + if (serverModpackContentMaster != null && serverModpackContentMaster.automodpackVersion != null) { + modrinthAPIList.add(ModrinthAPI.getModSpecificVersion(AUTOMODPACK_ID, serverModpackContentMaster.automodpackVersion, serverModpackContentMaster.mcVersion)); gettingServerVersion = true; } else { modrinthAPIList = ModrinthAPI.getModInfosFromID(AUTOMODPACK_ID); } if (gettingServerVersion) { - LOGGER.info("Syncing AutoModpack to server version: {}", serverModpackContent.automodpackVersion); + LOGGER.info("Syncing AutoModpack to server version: {}", serverModpackContentMaster.automodpackVersion); } else if (LOADER_MANAGER.getEnvironmentType() == LoaderManagerService.EnvironmentType.CLIENT && !clientConfig.selfUpdater) { LOGGER.info("AutoModpack self-updater is disabled in client config."); return false; diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUpdater.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUpdater.java index e4578eba0..614a4da0f 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUpdater.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUpdater.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.net.ConnectException; +import java.net.InetSocketAddress; import java.net.SocketTimeoutException; import java.nio.file.*; import java.util.*; @@ -24,31 +25,41 @@ // TODO: clean up this mess public class ModpackUpdater { public Changelogs changelogs = new Changelogs(); + public SelectionManager selectionManager; public DownloadManager downloadManager; public FetchManager fetchManager; public long totalBytesToDownload = 0; public boolean fullDownload = false; - private Jsons.ModpackContentFields serverModpackContent; + private Jsons.ModpackGroupFields serverModpackContent; private String modpackContentJson; - public Map> failedDownloads = new HashMap<>(); + public Map> failedDownloads = new HashMap<>(); private final Set newDownloadedFiles = new HashSet<>(); // Only files which did not exist before. Because some files may have the same name/path and be updated. private Jsons.ModpackAddresses modpackAddresses; + private InetSocketAddress modpackAddress; private Secrets.Secret modpackSecret; private Path modpackDir; private Path modpackContentFile; - + //if name is null... i hope it is right public String getModpackName() { + if (serverModpackContent == null) { + LOGGER.warn("name was initialized before server modpack content."); + return "unknown Modpack"; + } return serverModpackContent.modpackName; } - - public void prepareUpdate(Jsons.ModpackContentFields modpackContent, Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, Path modpackPath) { + + public void prepareUpdate(Jsons.ModpackGroupFields modpackContent, Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret) { this.serverModpackContent = modpackContent; this.modpackAddresses = modpackAddresses; + this.modpackAddress = modpackAddresses.hostAddress; this.modpackSecret = secret; - this.modpackDir = modpackPath; + this.modpackDir = ModpackUtils.getModpackPath(modpackAddresses, modpackContent.modpackName); - if (this.modpackAddresses.isAnyEmpty() || modpackPath.toString().isEmpty()) { + // check out of selected Modpack + SelectionManager.setSelectedPack(serverModpackContent.modpackName); + + if (modpackAddress == null || modpackDir.toString().isEmpty()) { throw new IllegalArgumentException("Address or modpackPath is null or empty"); } @@ -83,12 +94,18 @@ public void prepareUpdate(Jsons.ModpackContentFields modpackContent, Jsons.Modpa } } else if (!preload) { fullDownload = true; - new ScreenManager().danger(new ScreenManager().getScreen().orElseThrow(), this); + new ScreenManager().danger(new ScreenManager().getScreen().orElseThrow(), this, null); return; } LOGGER.warn("Modpack update found"); startUpdate(); + /* should be cleaned after update + startHighUpdate(); + startLowUpdate(); + startServerUpdate(); + + */ } catch (Exception e) { LOGGER.error("Error while initializing modpack updater", e); } @@ -143,9 +160,18 @@ public void CheckAndLoadModpack() throws Exception { LOGGER.info("Modpack is already loaded"); } + /* Delete soon this one // TODO split it into different methods, its too long + // Todo HighUpdate main folder rename in high end folder for Client (complete Folder from Automodpack folders (main)) + public void startHighUpdate() {} + // Todo LowUpdate low folder adding and only Download low client folder + public void startLowUpdate() {} + // TODO Download all files, also the files whats declared in automodpack-server and server sided files. + public void startServerUpdate() {} + */ public void startUpdate() { - + modpackDir = ModpackUtils.getModpackPath(modpackAddresses, serverModpackContent.modpackName); + LOGGER.info("Using modpack directory: {}", modpackDir); if (modpackSecret == null) { LOGGER.error("Cannot update modpack, secret is null"); return; @@ -159,7 +185,7 @@ public void startUpdate() { modpackDir = ModpackUtils.renameModpackDir(serverModpackContent, modpackDir); modpackContentFile = modpackDir.resolve(modpackContentFile.getFileName()); - Iterator iterator = serverModpackContent.list.iterator(); + Iterator iterator = serverModpackContent.list.iterator(); // CLEAN UP THE LIST @@ -167,7 +193,7 @@ public void startUpdate() { int skippedEditableFiles = 0; while (iterator.hasNext()) { - Jsons.ModpackContentFields.ModpackContentItem modpackContentField = iterator.next(); + Jsons.ModpackGroupFields.ModpackContentItem modpackContentField = iterator.next(); String file = modpackContentField.file; String serverSHA1 = modpackContentField.sha1; @@ -208,7 +234,7 @@ public void startUpdate() { List fetchDatas = new LinkedList<>(); - for (Jsons.ModpackContentFields.ModpackContentItem field : serverModpackContent.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem field : serverModpackContent.list) { totalBytesToDownload += Long.parseLong(field.size); @@ -418,7 +444,7 @@ private boolean applyModpack() throws Exception { } catch (IllegalArgumentException e) { LOGGER.error("Failed to save client secret", e); } - Jsons.ModpackContentFields modpackContent = ConfigTools.loadModpackContent(modpackContentFile); + Jsons.ModpackGroupFields modpackContent = ConfigTools.loadModpackContent(modpackContentFile); if (modpackContent == null) { throw new IllegalStateException("Failed to load modpack content"); // Something gone very wrong... @@ -511,11 +537,11 @@ private boolean applyModpack() throws Exception { } // returns set of formated files which we should not copy to the cwd - let them stay in the modpack directory - private Set getFilesNotToCopy(Set modpackContentItems, Set workaroundMods) { + private Set getFilesNotToCopy(Set modpackContentItems, Set workaroundMods) { Set filesNotToCopy = new HashSet<>(); // Make list of files which we do not copy to the running directory - for (Jsons.ModpackContentFields.ModpackContentItem item : modpackContentItems) { + for (Jsons.ModpackGroupFields.ModpackContentItem item : modpackContentItems) { if (item.forceCopy) { continue; } @@ -535,7 +561,7 @@ private Set getFilesNotToCopy(Set modpackFiles = modpackContent.list.stream().map(modpackContentField -> modpackContentField.file).toList(); List pathList; try (Stream pathStream = Files.walk(modpackDir)) { diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUtils.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUtils.java index d66b3fe9e..9dfe7fbaf 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUtils.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/client/ModpackUtils.java @@ -23,9 +23,10 @@ import static pl.skidam.automodpack_core.GlobalVariables.*; + public class ModpackUtils { - public static boolean isUpdate(Jsons.ModpackContentFields serverModpackContent, Path modpackDir) { + public static boolean isUpdate(Jsons.ModpackGroupFields serverModpackContent, Path modpackDir) { if (serverModpackContent == null || serverModpackContent.list == null) { throw new IllegalArgumentException("Server modpack content list is null"); } @@ -35,13 +36,13 @@ public static boolean isUpdate(Jsons.ModpackContentFields serverModpackContent, var optionalClientModpackContentFile = ModpackContentTools.getModpackContentFile(modpackDir); if (optionalClientModpackContentFile.isPresent() && Files.exists(optionalClientModpackContentFile.get())) { - Jsons.ModpackContentFields clientModpackContent = ConfigTools.loadModpackContent(optionalClientModpackContentFile.get()); + Jsons.ModpackGroupFields clientModpackContent = ConfigTools.loadModpackContent(optionalClientModpackContentFile.get()); if (clientModpackContent == null) { return true; } LOGGER.info("Checking files..."); - for (Jsons.ModpackContentFields.ModpackContentItem modpackContentField : serverModpackContent.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem modpackContentField : serverModpackContent.list) { String file = modpackContentField.file; String serverSHA1 = modpackContentField.sha1; @@ -62,7 +63,7 @@ public static boolean isUpdate(Jsons.ModpackContentFields serverModpackContent, } // Server also might have deleted some files - for (Jsons.ModpackContentFields.ModpackContentItem modpackContentField : clientModpackContent.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem modpackContentField : clientModpackContent.list) { var serverItemOpt = serverModpackContent.list.stream().filter(item -> item.file.equals(modpackContentField.file)).findFirst(); if (serverItemOpt.isEmpty()) { LOGGER.info("File does not exist on server {}", modpackContentField.file); @@ -77,11 +78,11 @@ public static boolean isUpdate(Jsons.ModpackContentFields serverModpackContent, } } - public static boolean correctFilesLocations(Path modpackDir, Jsons.ModpackContentFields serverModpackContent, Set filesNotToCopy) throws IOException { + public static boolean correctFilesLocations(Path modpackDir, Jsons.ModpackGroupFields serverModpackContent, Set filesNotToCopy) throws IOException { boolean needsRestart = false; // correct the files locations - for (Jsons.ModpackContentFields.ModpackContentItem contentItem : serverModpackContent.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem contentItem : serverModpackContent.list) { String formattedFile = contentItem.file; Path modpackFile = CustomFileUtils.getPath(modpackDir, formattedFile); Path runFile = CustomFileUtils.getPathFromCWD(formattedFile); @@ -131,10 +132,10 @@ public static boolean correctFilesLocations(Path modpackDir, Jsons.ModpackConten return needsRestart; } - public static boolean removeRestModsNotToCopy(Jsons.ModpackContentFields serverModpackContent, Set filesNotToCopy, Set modsToKeep) { + public static boolean removeRestModsNotToCopy(Jsons.ModpackGroupFields serverModpackContent, Set filesNotToCopy, Set modsToKeep) { boolean needsRestart = false; - for (Jsons.ModpackContentFields.ModpackContentItem contentItem : serverModpackContent.list) { + for (Jsons.ModpackGroupFields.ModpackContentItem contentItem : serverModpackContent.list) { String formattedFile = contentItem.file; Path runFile = CustomFileUtils.getPathFromCWD(formattedFile); boolean isMod = "mod".equals(contentItem.type); @@ -299,14 +300,14 @@ private static void addDependenciesRecursively(FileInspection.Mod mod, Collectio } } - public static Path renameModpackDir(Jsons.ModpackContentFields serverModpackContent, Path modpackDir) { + public static Path renameModpackDir(Jsons.ModpackGroupFields serverModpackContent, Path modpackDir) { if (clientConfig.installedModpacks == null || clientConfig.selectedModpack == null || clientConfig.selectedModpack.isBlank()) { return modpackDir; } String installedModpackName = clientConfig.selectedModpack; Jsons.ModpackAddresses installedModpackAddresses = clientConfig.installedModpacks.get(installedModpackName); - String serverModpackName = serverModpackContent.modpackName; + String serverModpackName = serverModpackContent.groupName; if (installedModpackAddresses != null && !serverModpackName.equals(installedModpackName) && !serverModpackName.isEmpty()) { @@ -330,9 +331,33 @@ public static Path renameModpackDir(Jsons.ModpackContentFields serverModpackCont return modpackDir; } + //get minecraft path.... + public static Path getMinecraftPath() { + return Path.of(System.getProperty("user.dir")); + } + + //try to get modpacks about minecraft path for utils + public static Path getModpackPathFolder(String modpackpackage) { + return getMinecraftPath().resolve("automodpack/host-modpack/").resolve(modpackpackage); + } + // get all client Packages and paths from host-modpack util test + public static Path getClientPackage() { + return getMinecraftPath().resolve("automodpack/host-modpack"); + } + + //add FullserverPack to selecting packs and it is need to change save folder + //add corrected Modpackpath if fullserverpack is selected + public static Path getCorrectModpackDir(Path modpackDirToSelect) { + if (modpackDirToSelect.getFileName().toString().equalsIgnoreCase("fullserver")) { + return hostFullServerPackDir.resolve("fullserver"); + } + return modpackDirToSelect; + } // Returns true if value changed public static boolean selectModpack(Path modpackDirToSelect, Jsons.ModpackAddresses modpackAddresses, Set newDownloadedFiles) { + modpackDirToSelect = getCorrectModpackDir(modpackDirToSelect); + final String modpackToSelect = modpackDirToSelect.getFileName().toString(); String selectedModpack = clientConfig.selectedModpack; @@ -340,7 +365,7 @@ public static boolean selectModpack(Path modpackDirToSelect, Jsons.ModpackAddres // Save current editable files Path selectedModpackDir = modpacksDir.resolve(selectedModpack); Path selectedModpackContentFile = selectedModpackDir.resolve(hostModpackContentFile.getFileName()); - Jsons.ModpackContentFields modpackContent = ConfigTools.loadModpackContent(selectedModpackContentFile); + Jsons.ModpackGroupFields modpackContent = ConfigTools.loadModpackContent(selectedModpackContentFile); if (modpackContent != null) { Set editableFiles = getEditableFiles(modpackContent.list); ModpackUtils.preserveEditableFiles(selectedModpackDir, editableFiles, newDownloadedFiles); @@ -349,7 +374,7 @@ public static boolean selectModpack(Path modpackDirToSelect, Jsons.ModpackAddres // Copy editable files from modpack to select Path modpackContentFile = modpackDirToSelect.resolve(hostModpackContentFile.getFileName()); - Jsons.ModpackContentFields modpackContentToSelect = ConfigTools.loadModpackContent(modpackContentFile); + Jsons.ModpackGroupFields modpackContentToSelect = ConfigTools.loadModpackContent(modpackContentFile); if (modpackContentToSelect != null) { Set editableFiles = getEditableFiles(modpackContentToSelect.list); ModpackUtils.copyPreviousEditableFiles(modpackDirToSelect, editableFiles, newDownloadedFiles); @@ -388,9 +413,13 @@ public static void addModpackToList(String modpackName, Jsons.ModpackAddresses m } // Returns modpack name formatted for path or url if server doesn't provide modpack name - public static Path getModpackPath(InetSocketAddress address, String modpackName) { + public static Path getModpackPath(Jsons.ModpackAddresses address, String modpackName) { + if (modpackName.equalsIgnoreCase("fullserver")) { + return hostFullServerPackDir.resolve("fullserver"); + } - String strAddress = address.getHostString() + ":" + address.getPort(); + InetSocketAddress Address = address.hostAddress; + String strAddress = Address.getHostString() + ":" + Address.getPort(); String correctedName = strAddress; if (FileInspection.isInValidFileName(strAddress)) { @@ -412,19 +441,19 @@ public static Path getModpackPath(InetSocketAddress address, String modpackName) return modpackDir; } - public static Optional requestServerModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, boolean allowAskingUser) { + public static Optional requestServerModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, boolean allowAskingUser) { return fetchModpackContent(modpackAddresses, secret, (client) -> client.downloadFile(new byte[0], modpackContentTempFile, null), "Fetched", allowAskingUser); } - public static Optional refreshServerModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, byte[][] fileHashes, boolean allowAskingUser) { + public static Optional refreshServerModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, byte[][] fileHashes, boolean allowAskingUser) { return fetchModpackContent(modpackAddresses, secret, (client) -> client.requestRefresh(fileHashes, modpackContentTempFile), "Re-fetched", allowAskingUser); } - private static Optional fetchModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, Function> operation, String fetchType, boolean allowAskingUser) { + private static Optional fetchModpackContent(Jsons.ModpackAddresses modpackAddresses, Secrets.Secret secret, Function> operation, String fetchType, boolean allowAskingUser) { if (secret == null) return Optional.empty(); if (modpackAddresses.isAnyEmpty()) @@ -522,8 +551,8 @@ private static Boolean askUserAboutCertificate(InetSocketAddress address, String } // check if modpackContent is valid/isn't malicious - public static boolean potentiallyMalicious(Jsons.ModpackContentFields serverModpackContent) { - String modpackName = serverModpackContent.modpackName; + public static boolean potentiallyMalicious(Jsons.ModpackGroupFields serverModpackContent) { + String modpackName = serverModpackContent.groupName; if (modpackName.contains("../") || modpackName.contains("/..")) { LOGGER.error("Modpack content is invalid, it contains /../ in modpack name"); return true; @@ -583,10 +612,10 @@ public static void copyPreviousEditableFiles(Path modpackDir, Set editab } } - static Set getEditableFiles(Set modpackContentItems) { + static Set getEditableFiles(Set modpackContentItems) { Set editableFiles = new HashSet<>(); - for (Jsons.ModpackContentFields.ModpackContentItem modpackContentItem : modpackContentItems) { + for (Jsons.ModpackGroupFields.ModpackContentItem modpackContentItem : modpackContentItems) { if (modpackContentItem.editable) { editableFiles.add(modpackContentItem.file); } diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/PreloadScreenImpl.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/PreloadScreenImpl.java index 3628edc6e..dd42fc711 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/PreloadScreenImpl.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/PreloadScreenImpl.java @@ -5,6 +5,9 @@ public class PreloadScreenImpl implements ScreenService { // We leave this all empty + @Override + public void downloadselection(Object... args) { } + @Override public void download(Object... args) { } diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenManager.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenManager.java index 02a7ff3f3..472ff9de2 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenManager.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenManager.java @@ -6,6 +6,10 @@ public class ScreenManager implements ScreenService { public static ScreenService INSTANCE = new PreloadScreenImpl(); + @Override + public void downloadselection(Object... args) { + INSTANCE.downloadselection(args); + } @Override public void download(Object... args) { INSTANCE.download(args); @@ -30,7 +34,6 @@ public void restart(Object... args) { public void danger(Object... args) { INSTANCE.danger(args); } - @Override public void error(String... args) { INSTANCE.error(args); diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenService.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenService.java index e7962bdb1..e13b957f5 100644 --- a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenService.java +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/screen/ScreenService.java @@ -4,6 +4,7 @@ public interface ScreenService { + void downloadselection(Object... args); void download(Object... args); void fetch(Object... args); void changelog(Object... args); diff --git a/loader/core/src/main/java/pl/skidam/automodpack_loader_core/utils/SelectionManager.java b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/utils/SelectionManager.java new file mode 100644 index 000000000..4fe8f1fc7 --- /dev/null +++ b/loader/core/src/main/java/pl/skidam/automodpack_loader_core/utils/SelectionManager.java @@ -0,0 +1,49 @@ +package pl.skidam.automodpack_loader_core.utils; + +import pl.skidam.automodpack_loader_core.client.ModpackUtils; +import pl.skidam.automodpack_core.config.ConfigTools; +import pl.skidam.automodpack_core.config.Jsons; + +import java.io.*; +import java.util.*; + +import static pl.skidam.automodpack_core.GlobalVariables.clientConfig; +import static pl.skidam.automodpack_core.GlobalVariables.clientConfigFile; + +public class SelectionManager { + + private static String selectedPack = "main"; + + //select folders from host-modpack for difference client packs + public static List getModpackFolders() { + List modpacks = new ArrayList<>(); + + File modpackfolders = ModpackUtils.getClientPackage().toFile(); + File[] folders = modpackfolders.listFiles(File::isDirectory); + + if (folders != null) { + for (File dir : folders) { + if (!dir.getName().equalsIgnoreCase("fullserver")) { // not using fullserver + modpacks.add(dir.getName()); + } + } + } + return modpacks; + } + + //give modpack from selected modpack and save to config + public static void setSelectedPack(String modpack) { + if (Objects.equals(selectedPack, modpack)) return; + selectedPack = modpack; + //trying to add selected Modpack + if (!modpack.equalsIgnoreCase("fullserver")) { + clientConfig.selectedModpack = modpack; + ConfigTools.save(clientConfigFile, clientConfig); + } + } + + //fetch modpack from config + public static String getSelectedPack() { + return selectedPack; + } +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/client/ScreenImpl.java b/src/main/java/pl/skidam/automodpack/client/ScreenImpl.java index 08b2e45cb..add999034 100644 --- a/src/main/java/pl/skidam/automodpack/client/ScreenImpl.java +++ b/src/main/java/pl/skidam/automodpack/client/ScreenImpl.java @@ -1,6 +1,7 @@ package pl.skidam.automodpack.client; import pl.skidam.automodpack.client.ui.*; +import pl.skidam.automodpack.client.ui.versioned.VersionedScreen; import pl.skidam.automodpack_loader_core.client.Changelogs; import pl.skidam.automodpack_loader_core.client.ModpackUpdater; import pl.skidam.automodpack_loader_core.screen.ScreenService; @@ -62,6 +63,11 @@ public void validation(Object... args) { Screens.validation(args[0], args[1], args[2], args[3]); } + @Override + public void downloadselection(Object... args) { + Screens.downloadselection(args[0], args[1]); + } + @Override public Optional getScreenString() { Screen screen = Screens.getScreen(); @@ -114,6 +120,9 @@ public static void title() { public static void menu() { // Screens.setScreen(new MenuScreen()); } + public static void downloadselection(Object parent, Object modpackUpdaterInstance) { + Screens.setScreen(new DownloadSelectionScreen((VersionedScreen) parent, (ModpackUpdater) modpackUpdaterInstance)); + } public static void validation(Object parent, Object serverFingerprint, Object validatedCallback, Object canceledCallback) { diff --git a/src/main/java/pl/skidam/automodpack/client/ui/ChangelogScreen.java b/src/main/java/pl/skidam/automodpack/client/ui/ChangelogScreen.java index a20a6fc1c..fc0d9e834 100644 --- a/src/main/java/pl/skidam/automodpack/client/ui/ChangelogScreen.java +++ b/src/main/java/pl/skidam/automodpack/client/ui/ChangelogScreen.java @@ -14,8 +14,7 @@ import java.nio.file.Path; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; + import net.minecraft.Util; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; @@ -101,7 +100,7 @@ public void versionedRender(VersionedMatrices matrices, int mouseX, int mouseY, drawSummaryOfChanges(matrices); } - private Jsons.ModpackContentFields modpackContent = null; + private Jsons.ModpackGroupFields modpackContent = null; private void drawSummaryOfChanges(VersionedMatrices matrices) { diff --git a/src/main/java/pl/skidam/automodpack/client/ui/DownloadSelectionScreen.java b/src/main/java/pl/skidam/automodpack/client/ui/DownloadSelectionScreen.java new file mode 100644 index 000000000..3836d26a5 --- /dev/null +++ b/src/main/java/pl/skidam/automodpack/client/ui/DownloadSelectionScreen.java @@ -0,0 +1,87 @@ +package pl.skidam.automodpack.client.ui; + +import java.util.List; + +import pl.skidam.automodpack_loader_core.client.ModpackUpdater; +import pl.skidam.automodpack.client.audio.AudioManager; + +import pl.skidam.automodpack.client.ui.versioned.VersionedMatrices; +import pl.skidam.automodpack.client.ui.versioned.VersionedScreen; +import pl.skidam.automodpack.client.ui.versioned.VersionedText; +import pl.skidam.automodpack.client.ui.versioned.VersionedUtil; +import pl.skidam.automodpack_loader_core.utils.SelectionManager; + +import static pl.skidam.automodpack_core.GlobalVariables.serverConfig; + +public class DownloadSelectionScreen extends VersionedScreen { + private final VersionedScreen parent; + private final ModpackUpdater modpackUpdaterInstance; + + public DownloadSelectionScreen(VersionedScreen parent, ModpackUpdater modpackUpdaterInstance) { + super(VersionedText.literal("DownloadSelectionScreen")); + this.parent = parent; + this.modpackUpdaterInstance = modpackUpdaterInstance; + + if (AudioManager.isMusicPlaying()) { + AudioManager.stopMusic(); + } + } + + @Override + protected void init() { + super.init(); + assert this.getClient() != null; + + this.addDrawableChild(buttonWidget(this.width / 2, this.height / 2 + 150, 120, 20, VersionedText.translatable("automodpack.ds.cancel"), button -> { + this.getClient().setScreen(this.parent); + })); + + //buttons from Selectionmanager + String currentSelected = SelectionManager.getSelectedPack(); + List modpacks = SelectionManager.getModpackFolders(); + + //dynamical how much buttons there + int dynamicY = this.height / 2 - (modpacks.size() * 15); + int i=0; + + for (String modpack : modpacks) { + // between buttons + int y = dynamicY + (i * 25); + + var displayText = VersionedText.literal(modpack); + if (modpack.equalsIgnoreCase(currentSelected)) { + displayText = VersionedText.green(modpack); + } else { + displayText = VersionedText.bold(modpack); + } + + this.addDrawableChild(buttonWidget(this.width / 2, y, 140, 20, displayText, button -> { + //select and start + SelectionManager.setSelectedPack(modpack); + VersionedUtil.getMainWorkerExecutor().execute(modpackUpdaterInstance::startUpdate); + })); + i++; + } + + //Full Serverpack Button if Modpack has permission from server + if (serverConfig != null && serverConfig.enableFullServerPack) { + this.addDrawableChild(buttonWidget(this.width / 2, this.height / 2 + 175, 160, 20, VersionedText.red(VersionedText.translatable("automodpack.ds.fullserverpack").getString()), button -> { + SelectionManager.setSelectedPack("fullserver"); + VersionedUtil.getMainWorkerExecutor().execute(modpackUpdaterInstance::startUpdate); + })); + } + } + + @Override + public void versionedRender(VersionedMatrices matrices, int mouseX, int mouseY, float delta) { + drawCenteredTextWithShadow(matrices, this.getTextRenderer(), VersionedText.translatable("automodpack.ds.selected", VersionedText.green(VersionedText.bold(SelectionManager.getSelectedPack()).getString())), this.width / 2, this.height / 2 - 15, 0xAAAAAA); + drawCenteredTextWithShadow(matrices, this.getTextRenderer(), VersionedText.bold(VersionedText.translatable("automodpack.ds").getString()), this.width / 2, this.height / 2 - 60, 16777215); + drawCenteredTextWithShadow(matrices, this.getTextRenderer(), VersionedText.translatable("automodpack.ds.description"), this.width / 2, this.height / 2 - 35, 16777215); + drawCenteredTextWithShadow(matrices, this.getTextRenderer(), VersionedText.translatable("automodpack.ds.secDescription"), this.width / 2, this.height / 2 - 25, 16777215); + } + + @Override + public boolean shouldCloseOnEsc() { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedMatrices.java b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedMatrices.java index c7ef8d638..270e6c448 100644 --- a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedMatrices.java +++ b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedMatrices.java @@ -1,52 +1,63 @@ package pl.skidam.automodpack.client.ui.versioned; -/*? if >=1.20 {*/ -import net.minecraft.client.gui.GuiGraphics; -/*?} else {*/ -/*import com.mojang.blaze3d.vertex.PoseStack; -*//*?}*/ - -public class VersionedMatrices /*? if <1.20 {*/ /*extends PoseStack *//*?}*/ { - -/*? if >=1.20 {*/ - private final GuiGraphics context; - - public VersionedMatrices(GuiGraphics context) { - this.context = context; - } - - public GuiGraphics getContext() { - return context; - } - - /*? if >=1.21.6 {*/ - public void pushPose() { - context.pose().pushMatrix(); - } - - public void popPose() { - context.pose().popMatrix(); - } - - public void scale(float x, float y, float z) { - context.pose().scale(x, y); - } - /*?} else {*/ - /*public void pushPose() { - context.pose().pushPose(); - } - - public void popPose() { - context.pose().popPose(); - } - - public void scale(float x, float y, float z) { - context.pose().scale(x, y, z); - } - *//*?}*/ +/*? if <1.20 {*/ +import com.mojang.blaze3d.vertex.PoseStack; /*?} else {*/ - /*public PoseStack getContext() { - return this; - } -*//*?}*/ -} +import net.minecraft.client.gui.GuiGraphics; +/*?}*/ + +public class VersionedMatrices { + /*? if <1.20 {*/ + private PoseStack context; + /*?} else {*/ + private GuiGraphics context; + /*?}*/ + + /*? if <1.20 {*/ + public VersionedMatrices() { + this.context = new PoseStack(); + } + + public void set(PoseStack matrices) { + this.context = matrices; + } + /*?} else {*/ + public VersionedMatrices(GuiGraphics matrices) { + this.context = matrices; + } + /*?}*/ + + /*? if <1.20 {*/ + public PoseStack getContext() { + return context; + } + /*?} else {*/ + public GuiGraphics getContext() { + return context; + } + /*?}*/ + + public void pushPose() { + /*? if <1.20 {*/ + context.pushPose(); + /*?} else {*/ + context.pose().pushPose(); + /*?}*/ + } + + public void popPose() { + /*? if <1.20 {*/ + context.popPose(); + /*?} else {*/ + context.pose().popPose(); + /*?}*/ + } + + public void scale(float x, float y, float z) { + /*? if <1.20 {*/ + context.scale(x, y, z); + /*?} else {*/ + context.pose().scale(x, y, z); + /*?}*/ + } +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedScreen.java b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedScreen.java index c7d81330d..56da6e960 100644 --- a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedScreen.java +++ b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedScreen.java @@ -7,108 +7,112 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceLocation; -/*? if >=1.21.6 {*/ -import net.minecraft.client.renderer.RenderPipelines; -/*?} else if >=1.21.2 {*/ -/*import net.minecraft.client.renderer.RenderType; +/*? if >=1.21.2 {*//* +import net.minecraft.client.renderer.RenderType; import java.util.function.Function; *//*?}*/ +/*? if >=1.21.6 {*//* +import net.minecraft.client.renderer.RenderPipelines; +*//*?}*/ + /*? if <1.20 {*/ -/*import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; +/*? if <1.21.6 {*/ import net.minecraft.client.gui.GuiComponent; -*//*?} else {*/ +/*?} else { */ +// Ab 1.21.6 wurde GuiComponent entfernt +import net.minecraft.client.gui.GuiGraphics; +/*?} */ +/*?} else {*/ import net.minecraft.client.gui.GuiGraphics; /*?}*/ public class VersionedScreen extends Screen { - protected VersionedScreen(Component title) { - super(title); - } + protected VersionedScreen(Component title) { + super(title); + } - /*? if <1.20 {*/ - /*@Override + /*? if <1.20 {*/ + @Override public void render(PoseStack matrix, int mouseX, int mouseY, float delta) { VersionedMatrices matrices = new VersionedMatrices(); - *//*?} else {*/ - @Override - public void render(GuiGraphics matrix, int mouseX, int mouseY, float delta) { - VersionedMatrices matrices = new VersionedMatrices(matrix); - /*?}*/ - - // Render background - /*? if <1.20.2 {*/ - /*super.renderBackground(matrices.getContext()); - *//*?} elif <1.20.6 {*/ - /*super.renderBackground(matrices.getContext(), mouseX, mouseY, delta); - *//*?} else {*/ - super.render(matrix, mouseX, mouseY, delta); - /*?}*/ - - // Render the rest of our screen - versionedRender(matrices, mouseX, mouseY, delta); - - /*? if <1.20.6 {*/ - /*super.render(matrices.getContext(), mouseX, mouseY, delta); - *//*?}*/ - } - - // This method is to be override by the child classes - public void versionedRender(VersionedMatrices matrices, int mouseX, int mouseY, float delta) { } - - - /*? if <=1.16.5 {*//* - public void addDrawableChild(T child) { - if (child instanceof ClickableWidget) { - super.addButton((ClickableWidget) child); - return; - } - super.addChild(child); - } - *//*?}*/ - - /*? if >=1.20 {*/ - public static void drawCenteredTextWithShadow(VersionedMatrices matrices, Font textRenderer, MutableComponent text, int centerX, int y, int color) { - matrices.getContext().drawCenteredString(textRenderer, text, centerX, y, color); - } - /*?} else {*/ - /*public static void drawCenteredTextWithShadow(VersionedMatrices matrices, Font textRenderer, MutableComponent text, int centerX, int y, int color) { - textRenderer.drawShadow(matrices.getContext(), text, (float)(centerX - textRenderer.width(text) / 2), (float)y, color); - } - *//*?}*/ - - - /*? if <1.19.3 {*/ - /*public static Button buttonWidget(int x, int y, int width, int height, Component message, Button.OnPress onPress) { - return new Button(x, y, width, height, message, onPress); - } - *//*?} else {*/ - public static Button buttonWidget(int x, int y, int width, int height, Component message, Button.OnPress onPress) { - return Button.builder(message, onPress).pos(x, y).size(width, height).build(); - } - /*?}*/ - - /*? if <=1.20 {*/ - /*public static void drawTexture(ResourceLocation textureID, VersionedMatrices matrices, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) { - /^? if <=1.16.5 {^/ - /^Minecraft.getInstance().getTextureManager().bindTexture(textureID); - ^//^?} else {^/ - RenderSystem.setShaderTexture(0, textureID); - /^?}^/ - GuiComponent.blit(matrices.getContext(), x, y, u, v, width, height, textureWidth, textureHeight); - } - *//*?} else {*/ - public static void drawTexture(ResourceLocation textureID, VersionedMatrices matrices, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) { - /*? if >=1.21.6 {*/ - matrices.getContext().blit(RenderPipelines.GUI_TEXTURED, textureID, x, y, u, v, width, height, textureWidth, textureHeight); - /*?} elif >=1.21.2 {*/ - /*Function RenderTypes = RenderType::guiTextured; - matrices.getContext().blit(RenderTypes, textureID, x, y, u, v, width, height, textureWidth, textureHeight); - *//*?} else {*/ - /*matrices.getContext().blit(textureID, x, y, u, v, width, height, textureWidth, textureHeight); - *//*?}*/ - } - /*?}*/ -} + matrices.set(matrix); + super.render(matrix, mouseX, mouseY, delta); + versionedRender(matrices, mouseX, mouseY, delta); + } + /*?} else {*/ + @Override + public void render(GuiGraphics matrix, int mouseX, int mouseY, float delta) { + VersionedMatrices matrices = new VersionedMatrices(matrix); + super.render(matrix, mouseX, mouseY, delta); + versionedRender(matrices, mouseX, mouseY, delta); + } + /*?} */ + + public void versionedRender(VersionedMatrices matrices, int mouseX, int mouseY, float delta) { } + + public T addDrawableChild(T widget) { + return super.addRenderableWidget(widget); + } + + public static void drawCenteredTextWithShadow(VersionedMatrices matrices, Font textRenderer, MutableComponent text, int centerX, int y, int color) { + /*? if >=1.20 {*/ + matrices.getContext().drawCenteredString(textRenderer, text, centerX, y, color); + /*?} else {*/ + textRenderer.drawShadow(matrices.getContext(), text, centerX - textRenderer.width(text) / 2, y, color); + /*?}*/ + } + + public static Button buttonWidget(int x, int y, int width, int height, Component message, Button.OnPress onPress) { + /*? if >=1.20 {*/ + return Button.builder(message, onPress).bounds(x, y, width, height).build(); + /*?} else if >=1.19.3 {*/ + // Für Minecraft 1.19.3 und 1.19.4: Erstelle eine anonyme Button-Unterklasse + return new Button(x, y, width, height, message, onPress, button -> Component.empty()) { + // Zusätzliche Methodenüberschreibungen falls nötig + }; + /*?} else {*/ + return new Button(x, y, width, height, message, onPress); + /*?}*/ + } + + public static void drawTexture(ResourceLocation textureID, VersionedMatrices matrices, int x, int y, int u, int v, int width, int height, int textureWidth, int textureHeight) { + /*? if >=1.20 {*/ + /*? if >=1.21.6 {*/ + matrices.getContext().blit(textureID, x, y, u, v, width, height, textureWidth, textureHeight); + /*?} elif >=1.21.3 {*/ + matrices.getContext().blit((resourceLocation) -> RenderType.gui(), textureID, x, y, (float)u, (float)v, width, height, textureWidth, textureHeight); + /*?} elif >=1.21.2 {*/ + matrices.getContext().blit(RenderType::guiTextured, textureID, x, y, (float)u, (float)v, width, height, textureWidth, textureHeight); + /*?} else {*/ + matrices.getContext().blit(textureID, x, y, u, v, width, height, textureWidth, textureHeight); + /*?}*/ + /*?} else {*/ + RenderSystem.setShaderTexture(0, textureID); + /*? if <1.21.6 {*/ + GuiComponent.blit(matrices.getContext(), x, y, u, v, width, height, textureWidth, textureHeight); + /*?} else {*/ + matrices.getContext().blit(textureID, x, y, u, v, width, height, textureWidth, textureHeight); + /*?}*/ + /*?}*/ + } + + public net.minecraft.client.Minecraft getClient() { + return this.minecraft; + } + + public Font getTextRenderer() { + /*? if >=1.20 {*/ + return this.minecraft.font; + /*?} else {*/ + return this.font; + /*?}*/ + } + + public Screen getMinecraftScreen() { + return this; + } +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedText.java b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedText.java index 102a51b09..763970439 100644 --- a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedText.java +++ b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedText.java @@ -1,7 +1,8 @@ package pl.skidam.automodpack.client.ui.versioned; import net.minecraft.network.chat.MutableComponent; -/*? if <= 1.19.1 {*/ + +/*? if <=1.19.1 {*/ /*import net.minecraft.network.chat.TextComponent; import net.minecraft.network.chat.TranslatableComponent; *//*?} else {*/ @@ -10,7 +11,7 @@ public class VersionedText { - /*? if <=1.19.1 {*/ + /*? if <=1.19.1 {*/ /*public static MutableComponent translatable(String key, Object... args) { return new TranslatableComponent(key, args); } @@ -18,14 +19,37 @@ public class VersionedText { public static MutableComponent literal(String string) { return new TextComponent(string); } + *//*?} else {*/ + public static MutableComponent translatable(String key, Object... args) { + return Component.translatable(key, args); + } - *//*?} else {*/ - public static MutableComponent translatable(String key, Object... args) { - return Component.translatable(key, args); - } + public static MutableComponent literal(String string) { + return Component.literal(string); + } + /*?}*/ - public static MutableComponent literal(String string) { - return Component.literal(string); - } - /*?}*/ + public static MutableComponent green(String text) { + /*? if >=1.19 {*/ + return literal(text).withStyle(net.minecraft.ChatFormatting.GREEN); + /*?} else {*/ + return literal(text); + /*?}*/ + } + + public static MutableComponent bold(String text) { + /*? if >=1.19 {*/ + return literal(text).withStyle(net.minecraft.ChatFormatting.BOLD); + /*?} else {*/ + return literal(text); + /*?}*/ + } + + public static MutableComponent red(String text) { + /*? if >=1.19 {*/ + return literal(text).withStyle(net.minecraft.ChatFormatting.RED); + /*?} else {*/ + return literal(text); + /*?}*/ + } } \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedUtil.java b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedUtil.java new file mode 100644 index 000000000..8efd0eeb2 --- /dev/null +++ b/src/main/java/pl/skidam/automodpack/client/ui/versioned/VersionedUtil.java @@ -0,0 +1,13 @@ +package pl.skidam.automodpack.client.ui.versioned; + +import java.util.concurrent.Executor; + +public class VersionedUtil { + public static Executor getMainWorkerExecutor() { + /*? if >=1.19 {*/ + return net.minecraft.Util.backgroundExecutor(); + /*?} else {*/ + return net.minecraft.Util.ioPool(); + /*?}*/ + } +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/init/Common.java b/src/main/java/pl/skidam/automodpack/init/Common.java index b69d53471..18465d691 100644 --- a/src/main/java/pl/skidam/automodpack/init/Common.java +++ b/src/main/java/pl/skidam/automodpack/init/Common.java @@ -5,6 +5,7 @@ import pl.skidam.automodpack.loader.GameCall; import pl.skidam.automodpack.networking.ModPackets; import pl.skidam.automodpack_core.modpack.ModpackExecutor; +import pl.skidam.automodpack_core.modpack.FullServerPack; import pl.skidam.automodpack_core.loader.LoaderManagerService; import pl.skidam.automodpack_core.protocol.netty.NettyServer; @@ -19,21 +20,33 @@ public class Common { public static MinecraftServer server = null; public static void serverInit() { - if (serverConfig.generateModpackOnStart) { - LOGGER.info("Generating modpack..."); - long genStart = System.currentTimeMillis(); - if (modpackExecutor.generateNew()) { - LOGGER.info("Modpack generated! took " + (System.currentTimeMillis() - genStart) + "ms"); + for (String groupId : serverConfig.groups.keySet()) { + var groupDecl = serverConfig.groups.get(groupId); + if (groupDecl.generateModpackOnStart) { + LOGGER.info("Generating modpack..."); + long genStart = System.currentTimeMillis(); + if (modpackExecutor.generateNew(groupId)) { + LOGGER.info("Modpack generated! took " + (System.currentTimeMillis() - genStart) + "ms"); + } else { + LOGGER.error("Failed to generate modpack!"); + } } else { - LOGGER.error("Failed to generate modpack!"); + LOGGER.info("Loading last modpack..."); + long genStart = System.currentTimeMillis(); + if (modpackExecutor.loadLast(groupId)) { + LOGGER.info("Modpack loaded! took " + (System.currentTimeMillis() - genStart) + "ms"); + } else { + LOGGER.error("Failed to load modpack!"); + } } - } else { - LOGGER.info("Loading last modpack..."); + } + if (serverConfig.enableFullServerPack) { + LOGGER.info("Generating FullServerModpack..."); long genStart = System.currentTimeMillis(); - if (modpackExecutor.loadLast()) { - LOGGER.info("Modpack loaded! took " + (System.currentTimeMillis() - genStart) + "ms"); + if (fullpacks.generateNew()) { + LOGGER.info("FullServerModpack generated! took " + (System.currentTimeMillis() - genStart) + "ms"); } else { - LOGGER.error("Failed to load modpack!"); + LOGGER.error("Failed to generate fullservermodpack!"); } } @@ -43,7 +56,10 @@ public static void serverInit() { public static void init() { GAME_CALL = new GameCall(); hostServer = new NettyServer(); + modpackExecutor = new ModpackExecutor(); + fullpacks = new FullServerPack(modpackExecutor); + } public static void afterSetupServer() { @@ -60,7 +76,9 @@ public static void beforeShutdownServer() { } hostServer.stop(); + modpackExecutor.stop(); + fullpacks.shutdownExecutor(); } public static ResourceLocation id(String path) { diff --git a/src/main/java/pl/skidam/automodpack/modpack/Commands.java b/src/main/java/pl/skidam/automodpack/modpack/Commands.java index c804b1fdb..0aa3fccad 100644 --- a/src/main/java/pl/skidam/automodpack/modpack/Commands.java +++ b/src/main/java/pl/skidam/automodpack/modpack/Commands.java @@ -114,7 +114,7 @@ private static int connections(CommandContext context) { private static int reload(CommandContext context) { Util.backgroundExecutor().execute(() -> { - var tempServerConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV2.class); + var tempServerConfig = ConfigTools.load(serverConfigFile, Jsons.ServerConfigFieldsV3.class); if (tempServerConfig != null) { serverConfig = tempServerConfig; send(context, "AutoModpack server config reloaded!", ChatFormatting.GREEN, true); @@ -208,7 +208,19 @@ private static int generateModpack(CommandContext context) { } send(context, "Generating Modpack...", ChatFormatting.YELLOW, true); long start = System.currentTimeMillis(); - if (modpackExecutor.generateNew()) { + + // generate every group + boolean allGenerated = true; + for (String groupId : serverConfig.groups.keySet()) { + if (!modpackExecutor.generateNew(groupId)) { + allGenerated = false; + send(context, "Failed to generate modpack for group: " + groupId, ChatFormatting.RED, true); + } else { + send(context, "Modpack generated for group: " + groupId, ChatFormatting.GREEN, true); + } + } + + if (allGenerated) { send(context, "Modpack generated! took " + (System.currentTimeMillis() - start) + "ms", ChatFormatting.GREEN, true); } else { send(context, "Modpack generation failed! Check logs for more info.", ChatFormatting.RED, true); diff --git a/src/main/java/pl/skidam/automodpack/networking/packet/DataC2SPacket.java b/src/main/java/pl/skidam/automodpack/networking/packet/DataC2SPacket.java index 64dafbf0e..c984296b7 100644 --- a/src/main/java/pl/skidam/automodpack/networking/packet/DataC2SPacket.java +++ b/src/main/java/pl/skidam/automodpack/networking/packet/DataC2SPacket.java @@ -76,11 +76,15 @@ public static CompletableFuture receive(Minecraft Minecraft, Cl LOGGER.info("Modpack address: {}:{} Requires to follow magic protocol: {}", modpackAddress.getHostString(), modpackAddress.getPort(), requiresMagic); + // Create modpackAddresses object first + Jsons.ModpackAddresses modpackAddresses = new Jsons.ModpackAddresses(modpackAddress, serverAddress, requiresMagic); + Boolean needsDisconnecting = null; FriendlyByteBuf response = new FriendlyByteBuf(Unpooled.buffer()); - Path modpackDir = ModpackUtils.getModpackPath(modpackAddress, modpackName); - Jsons.ModpackAddresses modpackAddresses = new Jsons.ModpackAddresses(modpackAddress, serverAddress, requiresMagic); + // Now use modpackAddresses + Path modpackDir = ModpackUtils.getModpackPath(modpackAddresses, modpackName); + var optionalServerModpackContent = ModpackUtils.requestServerModpackContent(modpackAddresses, secret, true); if (optionalServerModpackContent.isPresent()) { @@ -88,7 +92,7 @@ public static CompletableFuture receive(Minecraft Minecraft, Cl if (update) { disconnectImmediately(handler); - new ModpackUpdater().prepareUpdate(optionalServerModpackContent.get(), modpackAddresses, secret, modpackDir); + new ModpackUpdater().prepareUpdate(optionalServerModpackContent.get(), modpackAddresses, secret); needsDisconnecting = true; } else { boolean selectedModpackChanged = ModpackUtils.selectModpack(modpackDir, modpackAddresses, Set.of()); @@ -130,4 +134,4 @@ public static CompletableFuture receive(Minecraft Minecraft, Cl private static void disconnectImmediately(ClientHandshakePacketListenerImpl clientLoginNetworkHandler) { ((ClientConnectionAccessor) ((ClientLoginNetworkHandlerAccessor) clientLoginNetworkHandler).getConnection()).getChannel().disconnect(); } -} +} \ No newline at end of file diff --git a/src/main/java/pl/skidam/automodpack/networking/packet/HandshakeS2CPacket.java b/src/main/java/pl/skidam/automodpack/networking/packet/HandshakeS2CPacket.java index d88c49e75..22fd99bd2 100644 --- a/src/main/java/pl/skidam/automodpack/networking/packet/HandshakeS2CPacket.java +++ b/src/main/java/pl/skidam/automodpack/networking/packet/HandshakeS2CPacket.java @@ -118,8 +118,11 @@ public static void handleHandshake(Connection connection, GameProfile profile, i LOGGER.info("Sending {} modpack host address: {}:{}", profile.getName(), addressToSend, portToSend); - DataPacket dataPacket = new DataPacket(addressToSend, portToSend, serverConfig.modpackName, secret, serverConfig.requireAutoModpackOnClient, requiresMagic); - String packetContentJson = dataPacket.toJson(); + String mainGroupName = "main"; // Standardwert + if (serverConfig.groups != null && serverConfig.groups.containsKey("main")) { + mainGroupName = serverConfig.groups.get("main").groupName; + } + DataPacket dataPacket = new DataPacket(addressToSend, portToSend, mainGroupName, secret, serverConfig.requireAutoModpackOnClient, requiresMagic); String packetContentJson = dataPacket.toJson(); FriendlyByteBuf outBuf = new FriendlyByteBuf(Unpooled.buffer()); outBuf.writeUtf(packetContentJson, Short.MAX_VALUE); diff --git a/src/main/resources/assets/automodpack/lang/de_de.json b/src/main/resources/assets/automodpack/lang/de_de.json index 2a24ed6cb..7dfeabe3f 100644 --- a/src/main/resources/assets/automodpack/lang/de_de.json +++ b/src/main/resources/assets/automodpack/lang/de_de.json @@ -1,8 +1,10 @@ { "automodpack.restart.full": "Das Modpack wurde heruntergeladen!", "automodpack.restart.update": "Es wurde ein Update für das Modpack heruntergeladen!", + "automodpack.restart.select": "Vom Server benötigtes Modpack wurde ausgewählt!", "automodpack.restart.automodpack": "AutoModpack wurde auf die vom Server benötigte Version aktualisiert!", + "automodpack.restart.description": "Um den Vorgang abzuschließen, musst du das Spiel neu starten.", "automodpack.restart.secDescription": "Möchtest du jetzt neu starten?", "automodpack.restart.confirm": "Ja, Spiel schließen", @@ -18,9 +20,19 @@ "automodpack.danger": "Dieser Server bietet ein externes Modpack an!", "automodpack.danger.description": "Möchtest du es herunterladen?", "automodpack.danger.secDescription": "Es könnte riskant sein! Lade es NICHT herunter, wenn du den Server-Betreibern nicht vertraust!", + "automodpack.danger.selection": "Version wählen", + "automodpack.danger.fullserverpack": "Server Package", "automodpack.danger.confirm": "Herunterladen", "automodpack.danger.cancel": "Nicht herunterladen", + "automodpack.ds": "Dieser Server stellt verschiedene Versionen bereit!", + "automodpack.ds.description": "Du kannst für dich die benötigte Version auswählen. Welche benötigst du?", + "automodpack.ds.secDescription": "Verschiedenen Versionen benötigen andere PC Systeme!", + "automodpack.ds.selected": "Ausgewähltes Modpack: ", + "automodpack.ds.fullserverpack": "Server Package", + "automodpack.ds.confirm": "Download", + "automodpack.ds.cancel": "Abbrechen", + "automodpack.changelog.view": "Änderungen anzeigen", "automodpack.changelog.noChanges": "Keine Änderungen gefunden.", "automodpack.changelog.openPage": "Projektseite öffnen", @@ -55,4 +67,4 @@ "automodpack.cancel": "Abbrechen", "automodpack.back": "Zurück", "automodpack.wait": "Bitte warten..." -} \ No newline at end of file +} diff --git a/src/main/resources/assets/automodpack/lang/en_us.json b/src/main/resources/assets/automodpack/lang/en_us.json index 2d7a725ce..1ea91ae42 100644 --- a/src/main/resources/assets/automodpack/lang/en_us.json +++ b/src/main/resources/assets/automodpack/lang/en_us.json @@ -55,4 +55,4 @@ "automodpack.cancel": "Cancel", "automodpack.back": "Back", "automodpack.wait": "Please wait..." -} \ No newline at end of file + } \ No newline at end of file