diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 1ff0c423..00000000 --- a/.gitattributes +++ /dev/null @@ -1,63 +0,0 @@ -############################################################################### -# Set default behavior to automatically normalize line endings. -############################################################################### -* text=auto - -############################################################################### -# Set default behavior for command prompt diff. -# -# This is need for earlier builds of msysgit that does not have it on by -# default for csharp files. -# Note: This is only used by command line -############################################################################### -#*.cs diff=csharp - -############################################################################### -# Set the merge driver for project and solution files -# -# Merging from the command prompt will add diff markers to the files if there -# are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following -# file extensions to fail to load in VS. An alternative would be to treat -# these files as binary and thus will always conflict and require user -# intervention with every merge. To do so, just uncomment the entries below -############################################################################### -#*.sln merge=binary -#*.csproj merge=binary -#*.vbproj merge=binary -#*.vcxproj merge=binary -#*.vcproj merge=binary -#*.dbproj merge=binary -#*.fsproj merge=binary -#*.lsproj merge=binary -#*.wixproj merge=binary -#*.modelproj merge=binary -#*.sqlproj merge=binary -#*.wwaproj merge=binary - -############################################################################### -# behavior for image files -# -# image files are treated as binary by default. -############################################################################### -#*.jpg binary -#*.png binary -#*.gif binary - -############################################################################### -# diff behavior for common document formats -# -# Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the -# entries below. -############################################################################### -#*.doc diff=astextplain -#*.DOC diff=astextplain -#*.docx diff=astextplain -#*.DOCX diff=astextplain -#*.dot diff=astextplain -#*.DOT diff=astextplain -#*.pdf diff=astextplain -#*.PDF diff=astextplain -#*.rtf diff=astextplain -#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore index 6d768083..985f1163 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,17 @@ -# SubServers 2 Ignored Files - -*.iml - -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates -*.userprefs - -## Directory-based project format: -.idea/ - -## File-based project format: -*.ipr -*.iws - -# IntelliJ +# Hide System and IDE Generated Files /out/ +.idea/ +*.iml +.DS_STORE -# mpeltonen/sbt-idea plugin -.idea_modules/ +# Hide Unfinished Projects +/SubServers.Test/ -# JIRA plugin -atlassian-ide-plugin.xml - -# Crashlytics plugin (for Android Studio and IntelliJ) -com_crashlytics_export_strings.xml -crashlytics.properties -crashlytics-build.properties - -# Hide Unfinished Project Files -/SubServers.Client/Windows/ -/Artifacts/SubServers.Web.jar -/SubServers.Velocity/ -/SubServers.Web/ - -# Hide Others -/Artifacts/-Maven/ -/Artifacts/-History/ -/Artifacts/-Icon/ -/Artifacts/-Lite/ -/Artifacts/*.jar +# Hide Compiled Artifacts +/Artifacts/* /BungeeCord/ /Javadoc/ -/SubServers.Test/ -/build.ant -/build.log -.DS_STORE + +# Show Interpreted Artifacts +!/Artifacts/Download/ +!/Artifacts/SubServers.Patcher.sh diff --git a/Artifacts/ServerContainer.class b/Artifacts/ServerContainer.class deleted file mode 100644 index 7d568835..00000000 Binary files a/Artifacts/ServerContainer.class and /dev/null differ diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubCreator.java index ace31faa..fde849b0 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubCreator.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/External/ExternalSubCreator.java @@ -14,6 +14,7 @@ import net.ME1312.Galaxi.Library.Config.YAMLConfig; import net.ME1312.Galaxi.Library.Map.ObjectMap; import net.ME1312.Galaxi.Library.Version.Version; import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger; +import net.ME1312.SubServers.Bungee.Library.ReplacementScanner; import net.ME1312.SubServers.Bungee.Network.Packet.PacketExConfigureHost; import net.ME1312.SubServers.Bungee.Network.Packet.PacketExCreateServer; import net.ME1312.SubServers.Bungee.Network.Packet.PacketExDownloadTemplates; @@ -103,24 +104,16 @@ public class ExternalSubCreator extends SubCreator { final SubCreateEvent event = new SubCreateEvent(player, host, name, template, version, port); host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { - Container address = new Container<>("$address$"); - ReturnCallback conversion = obj -> convert(obj, new NamedContainer<>("$player$", (player == null)?"":player.toString()), new NamedContainer<>("$name$", name), - new NamedContainer<>("$host$", host.getName()), new NamedContainer<>("$template$", template.getName()), new NamedContainer<>("$type$", template.getType().toString()), new NamedContainer<>("$version$", (version != null)?version.toString():""), - new NamedContainer<>("$address$", address.get()), new NamedContainer<>("$port$", Integer.toString(fport))); - logger.start(); - host.queue(new PacketExCreateServer(name, template, version, port, (template.getConfigOptions().contains("Directory"))?conversion.run(template.getConfigOptions().getRawString("Directory")).toString():name, logger.getExternalAddress(), data -> { + host.queue(new PacketExCreateServer(player, name, template, version, port, logger.getExternalAddress(), data -> { try { if (data.getInt(0x0001) == 0) { Logger.get(prefix).info("Saving..."); - address.set(data.getRawString(0x0003)); if (host.plugin.exServers.keySet().contains(name.toLowerCase())) host.plugin.exServers.remove(name.toLowerCase()); ObjectMap server = new ObjectMap(); - ObjectMap config = new ObjectMap((Map) conversion.run(data.getMap(0x0002).get())); - - config.remove("\033address"); + ObjectMap config = new ObjectMap((Map) data.getObject(0x0002)); server.set("Enabled", true); server.set("Display", ""); @@ -157,7 +150,7 @@ public class ExternalSubCreator extends SubCreator { host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, fport, subserver, false, true)); callback(origin, callback, subserver); } else { - Logger.get(prefix).info(data.getString(0x0004)); + Logger.get(prefix).info(data.getString(0x0003)); host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, template, version, fport, null, false, false)); callback(origin, callback, null); } @@ -174,28 +167,6 @@ public class ExternalSubCreator extends SubCreator { return false; } } else return false; - } private Object convert(Object value, NamedContainer... replacements) { - if (value instanceof Map) { - List list = new ArrayList(); - list.addAll(((Map) value).keySet()); - for (String key : list) ((Map) value).put(key, convert(((Map) value).get(key), replacements)); - return value; - } else if (value instanceof Collection) { - List list = new ArrayList(); - for (Object val : (Collection) value) list.add(convert(val, replacements)); - return list; - } else if (value.getClass().isArray()) { - List list = new ArrayList(); - for (int i = 0; i < ((Object[]) value).length; i++) list.add(convert(((Object[]) value)[i], replacements)); - return list; - } else if (value instanceof String) { - return replace((String) value, replacements); - } else { - return value; - } - } private String replace(String string, NamedContainer... replacements) { - for (NamedContainer replacement : replacements) string = string.replace(replacement.name(), replacement.get()); - return string; } private void callback(StackTraceElement[] origin, Callback callback, T value) { if (callback != null) try { callback.run(value); @@ -222,12 +193,12 @@ public class ExternalSubCreator extends SubCreator { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { logger.start(); - host.queue(new PacketExCreateServer(server, version, logger.getExternalAddress(), data -> { + host.queue(new PacketExCreateServer(player, server, version, logger.getExternalAddress(), data -> { Util.isException(() -> Util.reflect(SubServerImpl.class.getDeclaredField("updating"), server, false)); if (data.getInt(0x0001) == 0) { Logger.get(prefix).info("Saving..."); } else { - Logger.get(prefix).info(data.getString(0x0004)); + Logger.get(prefix).info(data.getString(0x0003)); } host.plugin.getPluginManager().callEvent(new SubCreatedEvent(player, host, name, server.getTemplate(), version, server.getAddress().getPort(), server, true, data.getInt(0x0001) == 0)); diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java index d5888f3f..1636d770 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java @@ -8,6 +8,7 @@ import net.ME1312.Galaxi.Library.Callback.ReturnCallback; import net.ME1312.Galaxi.Library.Config.YAMLSection; import net.ME1312.Galaxi.Library.Container.Container; import net.ME1312.Galaxi.Library.Container.NamedContainer; +import net.ME1312.Galaxi.Library.Map.ObjectMapValue; import net.ME1312.SubServers.Bungee.Event.SubCreateEvent; import net.ME1312.SubServers.Bungee.Event.SubCreatedEvent; import net.ME1312.SubServers.Bungee.Host.*; @@ -17,6 +18,7 @@ import net.ME1312.SubServers.Bungee.Library.Compatibility.Logger; import net.ME1312.SubServers.Bungee.Library.Exception.InvalidServerException; import net.ME1312.SubServers.Bungee.Library.Exception.SubCreatorException; import net.ME1312.Galaxi.Library.Version.Version; +import net.ME1312.SubServers.Bungee.Library.ReplacementScanner; import net.ME1312.SubServers.Bungee.SubAPI; import net.ME1312.SubServers.Bungee.SubProxy; import net.md_5.bungee.api.ChatColor; @@ -27,6 +29,9 @@ import java.net.InetSocketAddress; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; import java.util.*; import java.util.regex.Pattern; @@ -51,6 +56,7 @@ public class InternalSubCreator extends SubCreator { private final int port; private final String prefix; private final InternalSubLogger log; + private final HashMap replacements; private final Callback callback; private Process process; @@ -63,6 +69,7 @@ public class InternalSubCreator extends SubCreator { this.version = version; this.port = port; this.log = new InternalSubLogger(null, this, prefix = name + File.separator + "Creator", InternalSubCreator.this.log, null); + this.replacements = new HashMap(); this.callback = callback; } @@ -75,6 +82,7 @@ public class InternalSubCreator extends SubCreator { this.version = version; this.port = server.getAddress().getPort(); this.log = new InternalSubLogger(null, this, prefix = name + File.separator + "Updater", InternalSubCreator.this.log, null); + this.replacements = new HashMap(); this.callback = callback; } @@ -112,14 +120,24 @@ public class InternalSubCreator extends SubCreator { server.setAll(template.getConfigOptions()); try { Logger.get(prefix).info("Loading Template: " + template.getDisplayName()); - Util.copyDirectory(template.getDirectory(), dir); + if (template.getBuildOptions().getBoolean("Update-Files", false)) updateDirectory(template.getDirectory(), dir); + else Util.copyDirectory(template.getDirectory(), dir); + + for (ObjectMapValue replacement : template.getBuildOptions().getMap("Replacements").getValues()) if (!replacement.isNull()) { + replacements.put(replacement.getHandle().toLowerCase().replace('-', '_').replace(' ', '_'), replacement.asRawString()); + } + + var.putAll(replacements); var.put("java", System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); var.put("mode", (update == null)?"CREATE":"UPDATE"); + if (player != null) var.put("player", player.toString().toUpperCase()); + else var.remove("player"); var.put("name", name); var.put("host", host.getName()); var.put("template", template.getName()); var.put("type", template.getType().toString().toUpperCase()); if (version != null) var.put("version", version.toString()); + else var.remove("version"); var.put("address", host.getAddress().getHostAddress()); var.put("port", Integer.toString(port)); switch (template.getType()) { @@ -203,19 +221,26 @@ public class InternalSubCreator extends SubCreator { } public void run() { - ReturnCallback conversion = obj -> convert(obj, new NamedContainer<>("$player$", (player == null)?"":player.toString()), new NamedContainer<>("$name$", name), - new NamedContainer<>("$host$", host.getName()), new NamedContainer<>("$template$", template.getName()), new NamedContainer<>("$type$", template.getType().toString()), new NamedContainer<>("$version$", (version != null)?version.toString():""), - new NamedContainer<>("$address$", host.getAddress().getHostAddress()), new NamedContainer<>("$port$", Integer.toString(port))); + Runnable declaration = () -> { + replacements.put("player", (player == null)?"":player.toString()); + replacements.put("name", name); + replacements.put("host", host.getName()); + replacements.put("template", template.getName()); + replacements.put("type", template.getType().toString()); + replacements.put("version", (version != null)?version.toString():""); + replacements.put("address", host.getAddress().getHostAddress()); + replacements.put("port", Integer.toString(port)); + }; + declaration.run(); File dir = (update != null)?new File(update.getFullPath()):new File(host.getPath(), - (template.getConfigOptions().contains("Directory"))?conversion.run(template.getConfigOptions().getRawString("Directory")).toString():name); + (template.getConfigOptions().contains("Directory"))?new ReplacementScanner(replacements).replace(template.getConfigOptions().getRawString("Directory")).toString():name); dir.mkdirs(); + ObjectMap server = new ObjectMap(); ObjectMap config; try { config = build(dir, template, new LinkedList<>()); - generateProperties(dir, port); - generateClient(dir, template.getType(), name); } catch (SubCreatorException e) { config = null; } catch (Exception e) { @@ -223,6 +248,22 @@ public class InternalSubCreator extends SubCreator { e.printStackTrace(); } + declaration.run(); + ReplacementScanner replacements = new ReplacementScanner(this.replacements); + if (config != null) { + try { + if (template.getBuildOptions().getBoolean("Install-Client", true)) generateClient(dir, template.getType(), name); + + LinkedList masks = new LinkedList<>(); + masks.add("/server.properties"); + masks.addAll(template.getBuildOptions().getRawStringList("Replace", Collections.emptyList())); + replacements.replace(dir, masks.toArray(new String[0])); + } catch (Exception e) { + config = null; + e.printStackTrace(); + } + } + if (config != null) { try { Logger.get(prefix).info("Saving..."); @@ -231,7 +272,7 @@ public class InternalSubCreator extends SubCreator { if (host.plugin.exServers.keySet().contains(name.toLowerCase())) host.plugin.exServers.remove(name.toLowerCase()); - config = new ObjectMap((Map) conversion.run(config.get())); + config = new ObjectMap((Map) replacements.replace(config.get())); server.set("Enabled", true); server.set("Display", ""); @@ -281,28 +322,6 @@ public class InternalSubCreator extends SubCreator { callback.run(null); } InternalSubCreator.this.thread.remove(name.toLowerCase()); - } private Object convert(Object value, NamedContainer... replacements) { - if (value instanceof Map) { - List list = new ArrayList(); - list.addAll(((Map) value).keySet()); - for (String key : list) ((Map) value).put(key, convert(((Map) value).get(key), replacements)); - return value; - } else if (value instanceof Collection) { - List list = new ArrayList(); - for (Object val : (Collection) value) list.add(convert(val, replacements)); - return list; - } else if (value.getClass().isArray()) { - List list = new ArrayList(); - for (int i = 0; i < ((Object[]) value).length; i++) list.add(convert(((Object[]) value)[i], replacements)); - return list; - } else if (value instanceof String) { - return replace((String) value, replacements); - } else { - return value; - } - } private String replace(String string, NamedContainer... replacements) { - for (NamedContainer replacement : replacements) string = string.replace(replacement.name(), replacement.get()); - return string; } } @@ -528,7 +547,7 @@ public class InternalSubCreator extends SubCreator { } private static NamedContainer> subdata = null; - private Map getSubDataConfig() { + private Map getSubData() { if (subdata == null || host.plugin.config.get() != subdata.name()) { Map map = new HashMap(); map.put("Address", host.plugin.config.get().getMap("Settings").getMap("SubData").getRawString("Address", "127.0.0.1").replace("0.0.0.0", "127.0.0.1")); @@ -539,21 +558,24 @@ public class InternalSubCreator extends SubCreator { } private void generateClient(File dir, ServerType type, String name) throws IOException { - if (new UniversalFile(dir, "subservers.client").exists()) { - Files.delete(new UniversalFile(dir, "subservers.client").toPath()); - if (type == ServerType.SPIGOT) { - if (!new UniversalFile(dir, "plugins").exists()) new UniversalFile(dir, "plugins").mkdirs(); - if (!new UniversalFile(dir, "plugins:SubServers.Client.jar").exists()) - Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "plugins:SubServers.Client.jar").getPath()); - } else if (type == ServerType.FORGE || type == ServerType.SPONGE) { - if (!new UniversalFile(dir, "mods").exists()) new UniversalFile(dir, "mods").mkdirs(); - if (!new UniversalFile(dir, "mods:SubServers.Client.jar").exists()) - Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "mods:SubServers.Client.jar").getPath()); - } + boolean installed = false; + if (type == ServerType.SPIGOT) { + installed = true; + if (!new UniversalFile(dir, "plugins").exists()) new UniversalFile(dir, "plugins").mkdirs(); + if (!new UniversalFile(dir, "plugins:SubServers.Client.jar").exists()) + Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "plugins:SubServers.Client.jar").getPath()); + } else if (type == ServerType.FORGE || type == ServerType.SPONGE) { + installed = true; + if (!new UniversalFile(dir, "mods").exists()) new UniversalFile(dir, "mods").mkdirs(); + if (!new UniversalFile(dir, "mods:SubServers.Client.jar").exists()) + Util.copyFromJar(SubProxy.class.getClassLoader(), "net/ME1312/SubServers/Bungee/Library/Files/client.jar", new UniversalFile(dir, "mods:SubServers.Client.jar").getPath()); + } + + if (installed) { YAMLSection config = new YAMLSection(); FileWriter writer = new FileWriter(new UniversalFile(dir, "subdata.json"), false); config.set("Name", name); - config.setAll(getSubDataConfig()); + config.setAll(getSubData()); writer.write(config.toJSON().toString()); writer.close(); @@ -562,15 +584,46 @@ public class InternalSubCreator extends SubCreator { } } } - private void generateProperties(File dir, int port) throws IOException { - File file = new File(dir, "server.properties"); - if (!file.exists()) file.createNewFile(); - InputStream stream = new FileInputStream(file); - String content = Util.readAll(new BufferedReader(new InputStreamReader(stream))).replaceAll("server-port=.*(\r?\n)", "server-port=" + port + "$1").replaceAll("server-ip=.*(\r?\n)", "server-ip=" + host.getAddress().getHostAddress() + "$1"); - stream.close(); - file.delete(); - PrintWriter writer = new PrintWriter(file, "UTF-8"); - writer.write(content); - writer.close(); + + private void updateDirectory(File from, File to) { + if (from.isDirectory() && !Files.isSymbolicLink(from.toPath())) { + if (!to.exists()) { + to.mkdirs(); + } + + String files[] = from.list(); + + for (String file : files) { + File srcFile = new File(from, file); + File destFile = new File(to, file); + + updateDirectory(srcFile, destFile); + } + } else { + try { + if (!to.exists() || from.length() != to.length() || !Arrays.equals(generateSHA256(to), generateSHA256(from))) { + if (to.exists()) { + if (to.isDirectory()) Util.deleteDirectory(to); + else to.delete(); + } + Files.copy(from.toPath(), to.toPath(), LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } private byte[] generateSHA256(File file) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + FileInputStream fis = new FileInputStream(file); + byte[] dataBytes = new byte[1024]; + + int nread; + + while ((nread = fis.read(dataBytes)) != -1) { + md.update(dataBytes, 0, nread); + } + + fis.close(); + return md.digest(); } } \ No newline at end of file diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/RemotePlayer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/RemotePlayer.java index 138f597c..d781a5c4 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/RemotePlayer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/RemotePlayer.java @@ -76,7 +76,7 @@ public class RemotePlayer implements SubDataSerializable { } /** - * Get this connection's UUID, if set. + * Get the UUID of this player. * * @return the UUID */ diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ReplacementScanner.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ReplacementScanner.java new file mode 100644 index 00000000..fdd2a7ed --- /dev/null +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Library/ReplacementScanner.java @@ -0,0 +1,169 @@ +package net.ME1312.SubServers.Bungee.Library; + +import net.ME1312.Galaxi.Library.Util; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.regex.Pattern; + +/** + * File Replacement Scanner + */ +public class ReplacementScanner { + private final Map replacements = new LinkedHashMap<>(); + + public ReplacementScanner(Map replacements) { + TreeMap> order = new TreeMap>(Comparator.reverseOrder()); + for (String key : replacements.keySet()) { + int length = key.length(); + if (!order.keySet().contains(length)) order.put(length, new LinkedList<>()); + order.get(length).add(key); + } + + for (Integer length : order.keySet()) { + for (String key : order.get(length)) { + this.replacements.put(key, replacements.get(key)); + } + } + } + + /** + * Get the replacements + * + * @return Replacement Map + */ + public Map getReplacements() { + return new HashMap<>(replacements); + } + + /** + * Make replacements in a File or Directory + * + * @param dir File or Directory + * @param whitelist File Whitelist + */ + public void replace(File dir, String... whitelist) throws IOException { + List files; + try { + files = Util.reflect(Util.class.getDeclaredMethod("zipsearch", File.class, File.class), null, dir, dir); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new IllegalStateException("Cannot access zipsearch()", e); + } + + LinkedHashMap rules = new LinkedHashMap(); + for (String entry : whitelist) { + boolean mode = !entry.startsWith("!"); + if (!mode) entry = entry.substring(1); + if (entry.startsWith(".")) entry = entry.substring(1); + + StringBuilder rule = new StringBuilder(); + if (entry.startsWith("**")) { + entry = entry.substring(2); + rule.append("^.*"); + } else if (entry.startsWith("/")) { + rule.append("^"); + } + + boolean greedyEnding = false; + if (entry.endsWith("**")) { + entry = entry.substring(0, entry.length() - 2); + greedyEnding = true; + } else if (entry.endsWith("/")) { + greedyEnding = true; + } + + StringBuilder literal = new StringBuilder(); + for (PrimitiveIterator.OfInt i = entry.codePoints().iterator(); i.hasNext(); ) { + int c = i.next(); + if ((c == '*' || c == '?' || c == '[') && literal.length() > 0) { + rule.append(Pattern.quote(literal.toString())); + literal = new StringBuilder(); + } + switch (c) { + case '\\': + if (i.hasNext()) c = i.next(); + literal.appendCodePoint(c); + case '[': + for (boolean escaped = false; i.hasNext() && (c != ']' || escaped); c = i.next()) { + if (c == '\\') escaped = !escaped; + else escaped = false; + literal.appendCodePoint(c); + } + if (c == ']' && literal.length() > 1) { + literal.appendCodePoint(c); + rule.append(literal.toString()); + } + literal = new StringBuilder(); + break; + case '*': + rule.append("[^/]+"); + break; + case '?': + rule.append("[^/]"); + break; + default: + literal.appendCodePoint(c); + break; + } + } + if (literal.length() > 0) + rule.append(Pattern.quote(literal.toString())); + + if (greedyEnding) + rule.append(".*"); + rule.append("$"); + rules.put(Pattern.compile(rule.toString()), mode); + } + + for (String file : files) { + boolean act = false; + + for (Map.Entry rule : rules.entrySet()) { + if (rule.getKey().matcher('/' + file.replace(File.separatorChar, '/')).find()) act = rule.getValue(); + } + + if (act) replaceFile(new File(dir, file)); + } + } private void replaceFile(File file) throws IOException { + FileInputStream stream = new FileInputStream(file); + String string = Util.readAll(new InputStreamReader(stream)); + stream.close(); + + for (Map.Entry replacement : replacements.entrySet()) string = string.replace("SubServers::" + replacement.getKey(), replacement.getValue()); + FileWriter writer = new FileWriter(file, false); + writer.write(string); + writer.close(); + } + + + /** + * Make replacements in an Object + * + * @param value Map, Collection, Array, or String + * @return Object with replaced variables + */ + public Object replace(Object value) { + if (value instanceof Map) { + List list = new ArrayList(); + list.addAll(((Map) value).keySet()); + for (String key : list) ((Map) value).put(key, replace(((Map) value).get(key))); + return value; + } else if (value instanceof Collection) { + List list = new ArrayList(); + for (Object val : (Collection) value) list.add(replace(val)); + return list; + } else if (value.getClass().isArray()) { + List list = new ArrayList(); + for (int i = 0; i < ((Object[]) value).length; i++) list.add(replace(((Object[]) value)[i])); + return list; + } else if (value instanceof String) { + return replaceObj((String) value); + } else { + return value; + } + } private String replaceObj(String string) { + for (Map.Entry replacement : replacements.entrySet()) string = string.replace('$' + replacement.getKey() + '$', replacement.getValue()); + return string; + } +} diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Network/Packet/PacketExCreateServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Network/Packet/PacketExCreateServer.java index 9786476f..d4b9b196 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Network/Packet/PacketExCreateServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Network/Packet/PacketExCreateServer.java @@ -18,6 +18,7 @@ import java.util.UUID; */ public class PacketExCreateServer implements PacketObjectIn, PacketObjectOut { private static HashMap>[]> callbacks = new HashMap>[]>(); + private UUID player; private String name; private SubCreator.ServerTemplate template; private Version version; @@ -36,14 +37,16 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje /** * New PacketExCreateServer (Out) * + * @param player Player * @param server Server to Update * @param version Server Version * @param log Log Address * @param callback Callbacks */ @SafeVarargs - public PacketExCreateServer(SubServer server, Version version, UUID log, Callback>... callback) { + public PacketExCreateServer(UUID player, SubServer server, Version version, UUID log, Callback>... callback) { if (Util.isNull(server, log, callback)) throw new NullPointerException(); + this.player = player; this.name = server.getName(); this.template = server.getTemplate(); this.version = version; @@ -57,22 +60,22 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje /** * New PacketExCreateServer (Out) * + * @param player Player * @param name Server Name * @param template Server Template * @param version Server Version * @param port Server Port Number - * @param directory Server Directory * @param log Log Address * @param callback Callbacks */ @SafeVarargs - public PacketExCreateServer(String name, SubCreator.ServerTemplate template, Version version, int port, String directory, UUID log, Callback>... callback) { + public PacketExCreateServer(UUID player, String name, SubCreator.ServerTemplate template, Version version, int port, UUID log, Callback>... callback) { if (Util.isNull(name, template, port, log, callback)) throw new NullPointerException(); + this.player = player; this.name = name; this.template = template; this.version = version; this.port = port; - this.dir = directory; this.log = log; this.tracker = Util.getNew(callbacks.keySet(), UUID::randomUUID); callbacks.put(tracker, callback); @@ -89,8 +92,9 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje data.set(0x0003, template.getName()); data.set(0x0004, version); data.set(0x0005, port); - data.set(0x0006, dir); - data.set(0x0007, log); + data.set(0x0006, log); + if (player != null) + data.set(0x0007, player); } return data; } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java index bb1c076c..01dd9fe6 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/SubProxy.java @@ -137,28 +137,29 @@ public final class SubProxy extends BungeeCord implements Listener { Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/sponge.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Created ./SubServers/Templates/Sponge"); } else { - if (new UniversalFile(dir, "Templates:Vanilla:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Vanilla:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.15a+")) != 0) { - Files.move(new UniversalFile(dir, "Templates:Vanilla").toPath(), new UniversalFile(dir, "Templates:Vanilla.old" + Math.round(Math.random() * 100000) + ".x").toPath()); + long stamp = Math.round(Math.random() * 100000); + if (new UniversalFile(dir, "Templates:Vanilla:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Vanilla:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.16a+")) != 0) { + Files.move(new UniversalFile(dir, "Templates:Vanilla").toPath(), new UniversalFile(dir, "Templates:Vanilla." + stamp + ".x").toPath()); Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/vanilla.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Updated ./SubServers/Templates/Vanilla"); } - if (new UniversalFile(dir, "Templates:Spigot:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Spigot:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.15a+")) != 0) { - Files.move(new UniversalFile(dir, "Templates:Spigot").toPath(), new UniversalFile(dir, "Templates:Spigot.old" + Math.round(Math.random() * 100000) + ".x").toPath()); + if (new UniversalFile(dir, "Templates:Spigot:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Spigot:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.16a+")) != 0) { + Files.move(new UniversalFile(dir, "Templates:Spigot").toPath(), new UniversalFile(dir, "Templates:Spigot." + stamp + ".x").toPath()); Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/spigot.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Updated ./SubServers/Templates/Spigot"); } - if (new UniversalFile(dir, "Templates:Paper:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Paper:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.15a+")) != 0) { - Files.move(new UniversalFile(dir, "Templates:Paper").toPath(), new UniversalFile(dir, "Templates:Paper.old" + Math.round(Math.random() * 100000) + ".x").toPath()); - Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/spigot.zip"), new UniversalFile(dir, "Templates")); + if (new UniversalFile(dir, "Templates:Paper:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Paper:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.16a+")) != 0) { + Files.move(new UniversalFile(dir, "Templates:Paper").toPath(), new UniversalFile(dir, "Templates:Paper." + stamp + ".x").toPath()); + Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/paper.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Updated ./SubServers/Templates/Paper"); } - if (new UniversalFile(dir, "Templates:Forge:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Forge:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.15a+")) != 0) { - Files.move(new UniversalFile(dir, "Templates:Forge").toPath(), new UniversalFile(dir, "Templates:Forge.old" + Math.round(Math.random() * 100000) + ".x").toPath()); + if (new UniversalFile(dir, "Templates:Forge:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Forge:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.16a+")) != 0) { + Files.move(new UniversalFile(dir, "Templates:Forge").toPath(), new UniversalFile(dir, "Templates:Forge." + stamp + ".x").toPath()); Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/forge.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Updated ./SubServers/Templates/Forge"); } - if (new UniversalFile(dir, "Templates:Sponge:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Sponge:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.15a+")) != 0) { - Files.move(new UniversalFile(dir, "Templates:Sponge").toPath(), new UniversalFile(dir, "Templates:Sponge.old" + Math.round(Math.random() * 100000) + ".x").toPath()); + if (new UniversalFile(dir, "Templates:Sponge:template.yml").exists() && ((new YAMLConfig(new UniversalFile(dir, "Templates:Sponge:template.yml"))).get().getVersion("Version", new Version(0))).compareTo(new Version("2.16a+")) != 0) { + Files.move(new UniversalFile(dir, "Templates:Sponge").toPath(), new UniversalFile(dir, "Templates:Sponge." + stamp + ".x").toPath()); Util.unzip(SubProxy.class.getResourceAsStream("/net/ME1312/SubServers/Bungee/Library/Files/Templates/sponge.zip"), new UniversalFile(dir, "Templates")); Logger.get("SubServers").info("Updated ./SubServers/Templates/Sponge"); } diff --git a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/API/RemotePlayer.java b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/API/RemotePlayer.java index 8b495c1e..6634fd0c 100644 --- a/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/API/RemotePlayer.java +++ b/SubServers.Client/Bukkit/src/net/ME1312/SubServers/Client/Bukkit/Network/API/RemotePlayer.java @@ -47,7 +47,7 @@ public class RemotePlayer { } /** - * Get this connection's UUID, if set. + * Get the UUID of this player. * * @return the UUID */ diff --git a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Network/API/RemotePlayer.java b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Network/API/RemotePlayer.java index de97425a..ec0987e6 100644 --- a/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Network/API/RemotePlayer.java +++ b/SubServers.Client/Sponge/src/net/ME1312/SubServers/Client/Sponge/Network/API/RemotePlayer.java @@ -49,7 +49,7 @@ public class RemotePlayer { } /** - * Get this connection's UUID, if set. + * Get the UUID of this player. * * @return the UUID */ diff --git a/SubServers.Creator/src/Forge/subservers.client b/SubServers.Creator/src/Forge/subservers.client deleted file mode 100644 index 9e26dfee..00000000 --- a/SubServers.Creator/src/Forge/subservers.client +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/SubServers.Creator/src/Forge/template.yml b/SubServers.Creator/src/Forge/template.yml index 4015c0f9..406e4e3a 100644 --- a/SubServers.Creator/src/Forge/template.yml +++ b/SubServers.Creator/src/Forge/template.yml @@ -1,4 +1,4 @@ -Version: '2.15a+' +Version: '2.16a+' Template: Enabled: true Icon: 'anvil' diff --git a/SubServers.Creator/src/Paper/subservers.client b/SubServers.Creator/src/Paper/subservers.client deleted file mode 100644 index 9e26dfee..00000000 --- a/SubServers.Creator/src/Paper/subservers.client +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/SubServers.Creator/src/Paper/template.yml b/SubServers.Creator/src/Paper/template.yml index a6305ffc..b8b2bb51 100644 --- a/SubServers.Creator/src/Paper/template.yml +++ b/SubServers.Creator/src/Paper/template.yml @@ -1,4 +1,4 @@ -Version: '2.15a+' +Version: '2.16a+' Template: Enabled: true Icon: 'paper' diff --git a/SubServers.Creator/src/Spigot/subservers.client b/SubServers.Creator/src/Spigot/subservers.client deleted file mode 100644 index 9e26dfee..00000000 --- a/SubServers.Creator/src/Spigot/subservers.client +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/SubServers.Creator/src/Spigot/template.yml b/SubServers.Creator/src/Spigot/template.yml index 04a96c5e..6664802e 100644 --- a/SubServers.Creator/src/Spigot/template.yml +++ b/SubServers.Creator/src/Spigot/template.yml @@ -1,4 +1,4 @@ -Version: '2.15a+' +Version: '2.16a+' Template: Enabled: true Icon: 'lava_bucket' diff --git a/SubServers.Creator/src/Sponge/subservers.client b/SubServers.Creator/src/Sponge/subservers.client deleted file mode 100644 index 9e26dfee..00000000 --- a/SubServers.Creator/src/Sponge/subservers.client +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/SubServers.Creator/src/Sponge/template.yml b/SubServers.Creator/src/Sponge/template.yml index 8a09b0fd..0edd9091 100644 --- a/SubServers.Creator/src/Sponge/template.yml +++ b/SubServers.Creator/src/Sponge/template.yml @@ -1,4 +1,4 @@ -Version: '2.15a+' +Version: '2.16a+' Template: Enabled: true Icon: 'sponge' diff --git a/SubServers.Creator/src/Vanilla/template.yml b/SubServers.Creator/src/Vanilla/template.yml index d211917c..4bc078d1 100644 --- a/SubServers.Creator/src/Vanilla/template.yml +++ b/SubServers.Creator/src/Vanilla/template.yml @@ -1,4 +1,4 @@ -Version: '2.15a+' +Version: '2.16a+' Template: Enabled: true Icon: 'bukkit:grass' diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreatorImpl.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreatorImpl.java index 1193a033..05054218 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreatorImpl.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreatorImpl.java @@ -5,6 +5,7 @@ import net.ME1312.Galaxi.Library.Config.YAMLSection; import net.ME1312.Galaxi.Library.Container.NamedContainer; import net.ME1312.Galaxi.Library.Map.ObjectMap; import net.ME1312.Galaxi.Library.Container.Container; +import net.ME1312.Galaxi.Library.Map.ObjectMapValue; import net.ME1312.Galaxi.Library.UniversalFile; import net.ME1312.Galaxi.Library.Util; import net.ME1312.Galaxi.Library.Version.Version; @@ -13,6 +14,7 @@ import net.ME1312.SubServers.Host.ExHost; import net.ME1312.SubServers.Host.Library.Exception.InvalidServerException; import net.ME1312.SubServers.Host.Library.Exception.InvalidTemplateException; import net.ME1312.SubServers.Host.Library.Exception.SubCreatorException; +import net.ME1312.SubServers.Host.Library.ReplacementScanner; import net.ME1312.SubServers.Host.Network.API.SubCreator.ServerType; import net.ME1312.SubServers.Host.Network.Packet.PacketExCreateServer; import net.ME1312.SubServers.Host.Network.Packet.PacketOutExLogMessage; @@ -23,6 +25,9 @@ import java.io.*; import java.net.URL; import java.nio.charset.Charset; import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; import java.util.*; /** @@ -198,25 +203,27 @@ public class SubCreatorImpl { private class CreatorTask extends Thread { private final SubServerImpl update; + private final UUID player; private final String name; private final ServerTemplate template; private final Version version; private final int port; - private final File dir; private final UUID address; private final UUID tracker; private final SubLoggerImpl log; + private final HashMap replacements; private Process process; - private CreatorTask(String name, ServerTemplate template, Version version, int port, String dir, UUID address, UUID tracker) { + private CreatorTask(UUID player, String name, ServerTemplate template, Version version, int port, UUID address, UUID tracker) { super(SubAPI.getInstance().getAppInfo().getName() + "::SubCreator_Process_Handler(" + name + ')'); this.update = host.servers.getOrDefault(name.toLowerCase(), null); + this.player = player; this.name = name; this.template = template; this.version = version; this.port = port; - this.dir = new File(host.host.getRawString("Directory"), dir); this.log = new SubLoggerImpl(null, this, name + File.separator + ((update == null)?"Creator":"Updater"), address, new Container(true), null); + this.replacements = new HashMap(); this.address = address; this.tracker = tracker; } @@ -260,15 +267,25 @@ public class SubCreatorImpl { try { log.logger.info.println("Loading Template: " + template.getDisplayName()); ((SubDataClient) SubAPI.getInstance().getSubDataNetwork()[0]).sendPacket(new PacketOutExLogMessage(address, "Loading Template: " + template.getDisplayName())); - Util.copyDirectory(template.getDirectory(), dir); + if (template.getBuildOptions().getBoolean("Update-Files", false)) updateDirectory(template.getDirectory(), dir); + else Util.copyDirectory(template.getDirectory(), dir); + + for (ObjectMapValue replacement : template.getBuildOptions().getMap("Replacements").getValues()) if (!replacement.isNull()) { + replacements.put(replacement.getHandle().toLowerCase().replace('-', '_').replace(' ', '_'), replacement.asRawString()); + } + + var.putAll(replacements); var.put("java", System.getProperty("java.home") + File.separator + "bin" + File.separator + "java"); var.put("mode", (update == null)?"CREATE":"UPDATE"); + if (player != null) var.put("player", player.toString().toUpperCase()); + else var.remove("player"); var.put("name", name); - if (SubAPI.getInstance().getSubDataNetwork()[0] != null) var.put("host", SubAPI.getInstance().getName()); + var.put("host", SubAPI.getInstance().getName()); var.put("template", template.getName()); var.put("type", template.getType().toString().toUpperCase()); if (version != null) var.put("version", version.toString()); - var.put("address", host.config.get().getMap("Settings").getRawString("Server-Bind")); + else var.remove("version"); + var.put("address", getAddress()); var.put("port", Integer.toString(port)); switch (template.getType()) { case SPONGE: @@ -354,22 +371,51 @@ public class SubCreatorImpl { return server; } + @SuppressWarnings("unchecked") public void run() { + Runnable declaration = () -> { + replacements.put("player", (player == null)?"":player.toString()); + replacements.put("name", name); + replacements.put("host", SubAPI.getInstance().getName()); + replacements.put("template", template.getName()); + replacements.put("type", template.getType().toString()); + replacements.put("version", (version != null)?version.toString():""); + replacements.put("address", getAddress()); + replacements.put("port", Integer.toString(port)); + }; + declaration.run(); + File dir = (update != null)?new File(update.getFullPath()):new File(host.host.getRawString("Directory"), + (template.getConfigOptions().contains("Directory"))?new ReplacementScanner(replacements).replace(template.getConfigOptions().getRawString("Directory")).toString():name); dir.mkdirs(); - ObjectMap server; + + ObjectMap config; try { - server = build(dir, template, new LinkedList<>()); - generateProperties(dir, port); - generateClient(dir, template.getType(), name); + config = build(dir, template, new LinkedList<>()); } catch (SubCreatorException e) { - server = null; + config = null; } catch (Exception e) { - server = null; + config = null; log.logger.error.println(e); } - ObjectMap config = template.getConfigOptions().clone(); - if (server != null) { - ((SubDataClient) SubAPI.getInstance().getSubDataNetwork()[0]).sendPacket(new PacketExCreateServer(0, null, config, host.config.get().getMap("Settings").getRawString("Server-Bind"), tracker)); + + declaration.run(); + ReplacementScanner replacements = new ReplacementScanner(this.replacements); + if (config != null) { + try { + if (template.getBuildOptions().getBoolean("Install-Client", true)) generateClient(dir, template.getType(), name); + + LinkedList masks = new LinkedList<>(); + masks.add("/server.properties"); + masks.addAll(template.getBuildOptions().getRawStringList("Replace", Collections.emptyList())); + replacements.replace(dir, masks.toArray(new String[0])); + } catch (Exception e) { + config = null; + e.printStackTrace(); + } + } + + if (config != null) { + ((SubDataClient) SubAPI.getInstance().getSubDataNetwork()[0]).sendPacket(new PacketExCreateServer(0, null, (Map) replacements.replace(config.get()), tracker)); } else { log.logger.info.println("Couldn't build the server jar. Check the SubCreator logs for more detail."); ((SubDataClient) SubAPI.getInstance().getSubDataNetwork()[0]).sendPacket(new PacketExCreateServer(-1, "Couldn't build the server jar. Check the SubCreator logs for more detail.", tracker)); @@ -389,9 +435,9 @@ public class SubCreatorImpl { this.thread = new TreeMap<>(); } - public boolean create(String name, ServerTemplate template, Version version, int port, String dir, UUID address, UUID tracker) { - if (Util.isNull(name, template, port, dir, address)) throw new NullPointerException(); - CreatorTask task = new CreatorTask(name, template, version, port, dir, address, tracker); + public boolean create(UUID player, String name, ServerTemplate template, Version version, int port, UUID address, UUID tracker) { + if (Util.isNull(name, template, port, address)) throw new NullPointerException(); + CreatorTask task = new CreatorTask(player, name, template, version, port, address, tracker); this.thread.put(name.toLowerCase(), task); task.start(); return true; @@ -444,8 +490,16 @@ public class SubCreatorImpl { return this.thread.get(name).log; } + private static NamedContainer address = null; + private String getAddress() { + if (address == null || host.config.get() != address.name()) { + address = new NamedContainer<>(host.config.get(), host.config.get().getMap("Settings").getRawString("Server-Bind")); + } + return address.get(); + } + private static NamedContainer> subdata = null; - private Map getSubDataConfig() { + private Map getSubData() { if (subdata == null || host.config.get() != subdata.name()) { Map map = new HashMap(); map.put("Address", host.config.get().getMap("Settings").getMap("SubData").getRawString("Address")); @@ -456,21 +510,24 @@ public class SubCreatorImpl { } private void generateClient(File dir, ServerType type, String name) throws IOException { - if (new UniversalFile(dir, "subservers.client").exists()) { - Files.delete(new UniversalFile(dir, "subservers.client").toPath()); - if (type == ServerType.SPIGOT) { - if (!new UniversalFile(dir, "plugins").exists()) new UniversalFile(dir, "plugins").mkdirs(); - if (!new UniversalFile(dir, "plugins:SubServers.Client.jar").exists()) - Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/client.jar", new UniversalFile(dir, "plugins:SubServers.Client.jar").getPath()); - } else if (type == ServerType.FORGE || type == ServerType.SPONGE) { - if (!new UniversalFile(dir, "mods").exists()) new UniversalFile(dir, "mods").mkdirs(); - if (!new UniversalFile(dir, "mods:SubServers.Client.jar").exists()) - Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/client.jar", new UniversalFile(dir, "mods:SubServers.Client.jar").getPath()); - } + boolean installed = false; + if (type == ServerType.SPIGOT) { + installed = true; + if (!new UniversalFile(dir, "plugins").exists()) new UniversalFile(dir, "plugins").mkdirs(); + if (!new UniversalFile(dir, "plugins:SubServers.Client.jar").exists()) + Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/client.jar", new UniversalFile(dir, "plugins:SubServers.Client.jar").getPath()); + } else if (type == ServerType.FORGE || type == ServerType.SPONGE) { + installed = true; + if (!new UniversalFile(dir, "mods").exists()) new UniversalFile(dir, "mods").mkdirs(); + if (!new UniversalFile(dir, "mods:SubServers.Client.jar").exists()) + Util.copyFromJar(ExHost.class.getClassLoader(), "net/ME1312/SubServers/Host/Library/Files/client.jar", new UniversalFile(dir, "mods:SubServers.Client.jar").getPath()); + } + + if (installed) { YAMLSection config = new YAMLSection(); FileWriter writer = new FileWriter(new UniversalFile(dir, "subdata.json"), false); config.set("Name", name); - config.setAll(getSubDataConfig()); + config.setAll(getSubData()); writer.write(config.toJSON().toString()); writer.close(); @@ -479,15 +536,46 @@ public class SubCreatorImpl { } } } - private void generateProperties(File dir, int port) throws IOException { - File file = new File(dir, "server.properties"); - if (!file.exists()) file.createNewFile(); - FileInputStream is = new FileInputStream(file); - String content = Util.readAll(new BufferedReader(new InputStreamReader(is))).replaceAll("server-port=.*(\r?\n)", "server-port=" + port + "$1").replaceAll("server-ip=.*(\r?\n)", "server-ip=" + host.config.get().getMap("Settings").getRawString("Server-Bind") + "$1"); - is.close(); - file.delete(); - PrintWriter writer = new PrintWriter(file, "UTF-8"); - writer.write(content); - writer.close(); + + private void updateDirectory(File from, File to) { + if (from.isDirectory() && !Files.isSymbolicLink(from.toPath())) { + if (!to.exists()) { + to.mkdirs(); + } + + String files[] = from.list(); + + for (String file : files) { + File srcFile = new File(from, file); + File destFile = new File(to, file); + + updateDirectory(srcFile, destFile); + } + } else { + try { + if (!to.exists() || from.length() != to.length() || !Arrays.equals(generateSHA256(to), generateSHA256(from))) { + if (to.exists()) { + if (to.isDirectory()) Util.deleteDirectory(to); + else to.delete(); + } + Files.copy(from.toPath(), to.toPath(), LinkOption.NOFOLLOW_LINKS, StandardCopyOption.REPLACE_EXISTING); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } private byte[] generateSHA256(File file) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + FileInputStream fis = new FileInputStream(file); + byte[] dataBytes = new byte[1024]; + + int nread; + + while ((nread = fis.read(dataBytes)) != -1) { + md.update(dataBytes, 0, nread); + } + + fis.close(); + return md.digest(); } } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServerImpl.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServerImpl.java index 9c8dbaa2..5cdf6633 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServerImpl.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServerImpl.java @@ -283,14 +283,23 @@ public class SubServerImpl { } /** - * Get the Server Directory + * Get the Server Directory Path * - * @return Server Directory + * @return Server Directory Path */ - public String getDirectory() { + public String getPath() { return dir; } + /** + * Get the Full Server Directory Path + * + * @return Full Server Directory Path + */ + public String getFullPath() { + return directory.getPath(); + } + /** * Get the Server's Executable String * diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Library/ReplacementScanner.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/ReplacementScanner.java new file mode 100644 index 00000000..a4b07605 --- /dev/null +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Library/ReplacementScanner.java @@ -0,0 +1,169 @@ +package net.ME1312.SubServers.Host.Library; + +import net.ME1312.Galaxi.Library.Util; + +import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.util.*; +import java.util.regex.Pattern; + +/** + * File Replacement Scanner + */ +public class ReplacementScanner { + private final Map replacements = new LinkedHashMap<>(); + + public ReplacementScanner(Map replacements) { + TreeMap> order = new TreeMap>(Comparator.reverseOrder()); + for (String key : replacements.keySet()) { + int length = key.length(); + if (!order.keySet().contains(length)) order.put(length, new LinkedList<>()); + order.get(length).add(key); + } + + for (Integer length : order.keySet()) { + for (String key : order.get(length)) { + this.replacements.put(key, replacements.get(key)); + } + } + } + + /** + * Get the replacements + * + * @return Replacement Map + */ + public Map getReplacements() { + return new HashMap<>(replacements); + } + + /** + * Make replacements in a File or Directory + * + * @param dir File or Directory + * @param whitelist File Whitelist + */ + public void replace(File dir, String... whitelist) throws IOException { + List files; + try { + files = Util.reflect(Util.class.getDeclaredMethod("zipsearch", File.class, File.class), null, dir, dir); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + throw new IllegalStateException("Cannot access zipsearch()", e); + } + + LinkedHashMap rules = new LinkedHashMap(); + for (String entry : whitelist) { + boolean mode = !entry.startsWith("!"); + if (!mode) entry = entry.substring(1); + if (entry.startsWith(".")) entry = entry.substring(1); + + StringBuilder rule = new StringBuilder(); + if (entry.startsWith("**")) { + entry = entry.substring(2); + rule.append("^.*"); + } else if (entry.startsWith("/")) { + rule.append("^"); + } + + boolean greedyEnding = false; + if (entry.endsWith("**")) { + entry = entry.substring(0, entry.length() - 2); + greedyEnding = true; + } else if (entry.endsWith("/")) { + greedyEnding = true; + } + + StringBuilder literal = new StringBuilder(); + for (PrimitiveIterator.OfInt i = entry.codePoints().iterator(); i.hasNext(); ) { + int c = i.next(); + if ((c == '*' || c == '?' || c == '[') && literal.length() > 0) { + rule.append(Pattern.quote(literal.toString())); + literal = new StringBuilder(); + } + switch (c) { + case '\\': + if (i.hasNext()) c = i.next(); + literal.appendCodePoint(c); + case '[': + for (boolean escaped = false; i.hasNext() && (c != ']' || escaped); c = i.next()) { + if (c == '\\') escaped = !escaped; + else escaped = false; + literal.appendCodePoint(c); + } + if (c == ']' && literal.length() > 1) { + literal.appendCodePoint(c); + rule.append(literal.toString()); + } + literal = new StringBuilder(); + break; + case '*': + rule.append("[^/]+"); + break; + case '?': + rule.append("[^/]"); + break; + default: + literal.appendCodePoint(c); + break; + } + } + if (literal.length() > 0) + rule.append(Pattern.quote(literal.toString())); + + if (greedyEnding) + rule.append(".*"); + rule.append("$"); + rules.put(Pattern.compile(rule.toString()), mode); + } + + for (String file : files) { + boolean act = false; + + for (Map.Entry rule : rules.entrySet()) { + if (rule.getKey().matcher('/' + file.replace(File.separatorChar, '/')).find()) act = rule.getValue(); + } + + if (act) replaceFile(new File(dir, file)); + } + } private void replaceFile(File file) throws IOException { + FileInputStream stream = new FileInputStream(file); + String string = Util.readAll(new InputStreamReader(stream)); + stream.close(); + + for (Map.Entry replacement : replacements.entrySet()) string = string.replace("SubServers::" + replacement.getKey(), replacement.getValue()); + FileWriter writer = new FileWriter(file, false); + writer.write(string); + writer.close(); + } + + + /** + * Make replacements in an Object + * + * @param value Map, Collection, Array, or String + * @return Object with replaced variables + */ + public Object replace(Object value) { + if (value instanceof Map) { + List list = new ArrayList(); + list.addAll(((Map) value).keySet()); + for (String key : list) ((Map) value).put(key, replace(((Map) value).get(key))); + return value; + } else if (value instanceof Collection) { + List list = new ArrayList(); + for (Object val : (Collection) value) list.add(replace(val)); + return list; + } else if (value.getClass().isArray()) { + List list = new ArrayList(); + for (int i = 0; i < ((Object[]) value).length; i++) list.add(replace(((Object[]) value)[i])); + return list; + } else if (value instanceof String) { + return replaceObj((String) value); + } else { + return value; + } + } private String replaceObj(String string) { + for (Map.Entry replacement : replacements.entrySet()) string = string.replace('$' + replacement.getKey() + '$', replacement.getValue()); + return string; + } +} diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/API/RemotePlayer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/API/RemotePlayer.java index 911471e0..acdaa2ff 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/API/RemotePlayer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/API/RemotePlayer.java @@ -49,7 +49,7 @@ public class RemotePlayer { } /** - * Get this connection's UUID, if set. + * Get the UUID of this player. * * @return the UUID */ diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExAddServer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExAddServer.java index a79e5f2c..2b5eacea 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExAddServer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExAddServer.java @@ -80,7 +80,7 @@ public class PacketExAddServer implements PacketObjectIn, PacketObjectO if (host.servers.keySet().contains(name.toLowerCase())) { SubServerImpl server = host.servers.get(name.toLowerCase()); - if (server.getPort() == port && server.getExecutable().equals(exec) && server.getDirectory().equals(dir)) { + if (server.getPort() == port && server.getExecutable().equals(exec) && server.getPath().equals(dir)) { if (server.isEnabled() != enabled || server.getLogger().isLogging() != log || !server.getStopCommand().equals(stopcmd)) { server.setEnabled(enabled); server.setLogging(log); diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExCreateServer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExCreateServer.java index 3ac1c418..8ac114e8 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExCreateServer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExCreateServer.java @@ -8,6 +8,7 @@ import net.ME1312.SubData.Client.Protocol.PacketObjectOut; import net.ME1312.SubData.Client.SubDataSender; import net.ME1312.SubServers.Host.ExHost; +import java.util.Map; import java.util.UUID; /** @@ -17,8 +18,7 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje private ExHost host; private int response; private String message; - private ObjectMap info; - private String address; + private Map info; private UUID tracker; /** @@ -51,15 +51,13 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje * @param response Response ID * @param message Message * @param info Creator Info - * @param address Internal Server Address * @param tracker Receiver ID */ - public PacketExCreateServer(int response, String message, ObjectMap info, String address, UUID tracker) { + public PacketExCreateServer(int response, String message, Map info, UUID tracker) { if (Util.isNull(response)) throw new NullPointerException(); this.response = response; this.message = message; this.info = info; - this.address = address; this.tracker = tracker; } @@ -69,8 +67,7 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje if (tracker != null) data.set(0x0000, tracker); data.set(0x0001, response); if (info != null) data.set(0x0002, info); - if (address != null) data.set(0x0003, address); - if (message != null) data.set(0x0004, message); + if (message != null) data.set(0x0003, message); return data; } @@ -90,11 +87,10 @@ public class PacketExCreateServer implements PacketObjectIn, PacketObje String template = data.getRawString(0x0003); Version version = (data.contains(0x0004)?data.getVersion(0x0004):null); Integer port = data.getInt(0x0005); - String dir = data.getRawString(0x0006).replace("$address$", host.config.get().getMap("Settings").getRawString("Server-Bind")); - UUID log = data.getUUID(0x0007); + UUID log = data.getUUID(0x0006); + UUID player = (data.contains(0x0007)?data.getUUID(0x0007):null); - host.creator.create(name, host.templates.get(template.toLowerCase()), version, - port, dir, log, tracker); + host.creator.create(player, name, host.templates.get(template.toLowerCase()), version, port, log, tracker); } } catch (Throwable e) { host.log.error.println(e); diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExDeleteServer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExDeleteServer.java index 3774ccfc..b988af2c 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExDeleteServer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Network/Packet/PacketExDeleteServer.java @@ -78,7 +78,7 @@ public class PacketExDeleteServer implements PacketObjectIn, PacketObje new Thread(() -> { UniversalFile to = new UniversalFile(GalaxiEngine.getInstance().getRuntimeDirectory(), "Recently Deleted:" + server.getName().toLowerCase()); try { - File from = new File(host.host.getRawString("Directory"), server.getDirectory()); + File from = new File(host.host.getRawString("Directory"), server.getPath()); if (from.exists()) { log.info("Removing Files..."); if (recycle) { diff --git a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Network/API/RemotePlayer.java b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Network/API/RemotePlayer.java index ea5f7199..ff95cc01 100644 --- a/SubServers.Sync/src/net/ME1312/SubServers/Sync/Network/API/RemotePlayer.java +++ b/SubServers.Sync/src/net/ME1312/SubServers/Sync/Network/API/RemotePlayer.java @@ -49,7 +49,7 @@ public class RemotePlayer { } /** - * Get this connection's UUID, if set. + * Get the UUID of this player. * * @return the UUID */