SubServers-2/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java

537 lines
27 KiB
Java

package net.ME1312.SubServers.Bungee.Host.Internal;
import net.ME1312.SubServers.Bungee.Event.SubCreateEvent;
import net.ME1312.SubServers.Bungee.Host.Executable;
import net.ME1312.SubServers.Bungee.Host.Host;
import net.ME1312.SubServers.Bungee.Host.SubCreator;
import net.ME1312.SubServers.Bungee.Library.Config.YAMLSection;
import net.ME1312.SubServers.Bungee.Library.Container;
import net.ME1312.SubServers.Bungee.Library.UniversalFile;
import net.ME1312.SubServers.Bungee.Library.Util;
import net.ME1312.SubServers.Bungee.Library.Version.Version;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.UUID;
public class InternalSubCreator extends SubCreator {
private InternalHost host;
private String gitBash;
private Thread thread = null;
public InternalSubCreator(Host host, String gitBash) {
this.host = (InternalHost) host;
this.gitBash = gitBash;
}
private void GenerateEULA(File dir) throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer = new PrintWriter(new File(dir, "eula.txt"), "UTF-8");
writer.println("#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://account.mojang.com/documents/minecraft_eula).");
writer.println("#" + new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy").format(Calendar.getInstance().getTime()));
writer.println("eula=true");
writer.close();
}
private void GenerateProperties(File dir, int port) throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer = new PrintWriter(new File(dir, "server.properties"), "UTF-8");
writer.println("#Minecraft server properties");
writer.println("#" + new SimpleDateFormat("EEE MMM d HH:mm:ss z yyyy").format(Calendar.getInstance().getTime()));
writer.println("generator-settings=");
writer.println("op-permission-level=4");
writer.println("allow-nether=true");
writer.println("resource-pack-hash=");
writer.println("level-name=world");
writer.println("enable-query=true");
writer.println("allow-flight=false");
writer.println("announce-player-achievements=false");
writer.println("server-port=" + port);
writer.println("max-world-size=29999984");
writer.println("level-type=DEFAULT");
writer.println("enable-rcon=false");
writer.println("level-seed=");
writer.println("force-gamemode=false");
writer.println("server-ip=" + host.getAddress().toString().substring(1));
writer.println("network-compression-threshold=-1");
writer.println("max-build-height=256");
writer.println("spawn-npcs=true");
writer.println("white-list=false");
writer.println("spawn-animals=true");
writer.println("snooper-enabled=true");
writer.println("online-mode=false");
writer.println("resource-pack=");
writer.println("pvp=true");
writer.println("difficulty=1");
writer.println("enable-command-block=true");
writer.println("gamemode=0");
writer.println("player-idle-timeout=0");
writer.println("max-players=20");
writer.println("max-tick-time=60000");
writer.println("spawn-monsters=true");
writer.println("generate-structures=true");
writer.println("view-distance=10");
writer.println("motd=A Generated SubServer");
writer.close();
}
private void GenerateSpigotYAML(File dir) throws FileNotFoundException, UnsupportedEncodingException {
PrintWriter writer = new PrintWriter(new File(dir, "spigot.yml"), "UTF-8");
writer.println("# This is the main configuration file for Spigot.");
writer.println("# As you can see, there's tons to configure. Some options may impact gameplay, so use");
writer.println("# with caution, and make sure you know what each option does before configuring.");
writer.println("# For a reference for any variable inside this file, check out the Spigot wiki at");
writer.println("# http://www.spigotmc.org/wiki/spigot-configuration/");
writer.println("#");
writer.println("# If you need help with the configuration or have any questions related to Spigot,");
writer.println("# join us at the IRC or drop by our forums and leave a post.");
writer.println("#");
writer.println("# IRC: #spigot @ irc.spi.gt ( http://www.spigotmc.org/pages/irc/ )");
writer.println("# Forums: http://www.spigotmc.org/");
writer.println();
writer.println("config-version: 8");
writer.println("settings:");
writer.println(" debug: false");
writer.println(" save-user-cache-on-stop-only: false");
writer.println(" bungeecord: true");
writer.println(" late-bind: false");
writer.println(" sample-count: 12");
writer.println(" player-shuffle: 0");
writer.println(" filter-creative-items: true");
writer.println(" user-cache-size: 1000");
writer.println(" int-cache-limit: 1024");
writer.println(" moved-wrongly-threshold: 0.0625");
writer.println(" moved-too-quickly-threshold: 100.0");
writer.println(" timeout-time: 60");
writer.println(" restart-on-crash: false");
writer.println(" restart-script: ./start.sh");
writer.println(" netty-threads: 4");
writer.println(" attribute:");
writer.println(" maxHealth:");
writer.println(" max: 2048.0");
writer.println(" movementSpeed:");
writer.println(" max: 2048.0");
writer.println(" attackDamage:");
writer.println(" max: 2048.0");
writer.println("commands:");
writer.println(" tab-complete: 0");
writer.println(" log: true");
writer.println(" spam-exclusions:");
writer.println(" - /skill");
writer.println(" silent-commandblock-console: true");
writer.println(" replace-commands:");
writer.println(" - setblock");
writer.println(" - summon");
writer.println(" - testforblock");
writer.println(" - tellraw");
writer.println("messages:");
writer.println(" whitelist: You are not whitelisted on this server!");
writer.println(" unknown-command: Unknown command. Type \"/help\" for help.");
writer.println(" server-full: The server is full!");
writer.println(" outdated-client: Outdated client! Please use {0}");
writer.println(" outdated-server: Outdated server! I'm still on {0}");
writer.println(" restart: Server is restarting");
writer.println("stats:");
writer.println(" disable-saving: false");
writer.println(" forced-stats: {}");
writer.println("world-settings:");
writer.println(" default:");
writer.println(" verbose: true");
writer.println(" wither-spawn-sound-radius: 0");
writer.println(" view-distance: 10");
writer.println(" item-despawn-rate: 6000");
writer.println(" merge-radius:");
writer.println(" item: 2.5");
writer.println(" exp: 3.0");
writer.println(" arrow-despawn-rate: 1200");
writer.println(" enable-zombie-pigmen-portal-spawns: true");
writer.println(" zombie-aggressive-towards-villager: true");
writer.println(" hanging-tick-frequency: 100");
writer.println(" max-bulk-chunks: 10");
writer.println(" max-entity-collisions: 8");
writer.println(" random-light-updates: false");
writer.println(" save-structure-info: true");
writer.println(" mob-spawn-range: 4");
writer.println(" anti-xray:");
writer.println(" enabled: true");
writer.println(" engine-mode: 1");
writer.println(" hide-blocks:");
writer.println(" - 14");
writer.println(" - 15");
writer.println(" - 16");
writer.println(" - 21");
writer.println(" - 48");
writer.println(" - 49");
writer.println(" - 54");
writer.println(" - 56");
writer.println(" - 73");
writer.println(" - 74");
writer.println(" - 82");
writer.println(" - 129");
writer.println(" - 130");
writer.println(" replace-blocks:");
writer.println(" - 1");
writer.println(" - 5");
writer.println(" dragon-death-sound-radius: 0");
writer.println(" seed-village: 10387312");
writer.println(" seed-feature: 14357617");
writer.println(" hunger:");
writer.println(" walk-exhaustion: 0.2");
writer.println(" sprint-exhaustion: 0.8");
writer.println(" combat-exhaustion: 0.3");
writer.println(" regen-exhaustion: 3.0");
writer.println(" max-tnt-per-tick: 100");
writer.println(" max-tick-time:");
writer.println(" tile: 50");
writer.println(" entity: 50");
writer.println(" entity-activation-range:");
writer.println(" animals: 32");
writer.println(" monsters: 32");
writer.println(" misc: 16");
writer.println(" entity-tracking-range:");
writer.println(" players: 48");
writer.println(" animals: 48");
writer.println(" monsters: 48");
writer.println(" misc: 32");
writer.println(" other: 64");
writer.println(" ticks-per:");
writer.println(" hopper-transfer: 8");
writer.println(" hopper-check: 8");
writer.println(" hopper-amount: 1");
writer.println(" growth:");
writer.println(" cactus-modifier: 100");
writer.println(" cane-modifier: 100");
writer.println(" melon-modifier: 100");
writer.println(" mushroom-modifier: 100");
writer.println(" pumpkin-modifier: 100");
writer.println(" sapling-modifier: 100");
writer.println(" wheat-modifier: 100");
writer.println(" netherwart-modifier: 100");
writer.println(" nerf-spawner-mobs: false");
writer.println(" chunks-per-tick: 650");
writer.println(" clear-tick-list: false");
writer.println();
writer.close();
}
private void GenerateSpongeConf(File dir) throws FileNotFoundException, UnsupportedEncodingException {
new File(dir, "config" + File.separator + "sponge").mkdirs();
PrintWriter writer = new PrintWriter(new File(dir, "config" + File.separator + "sponge" + File.separator + "global.conf"), "UTF-8");
writer.println("# 1.0");
writer.println("#");
writer.println("# # If you need help with the configuration or have any questions related to Sponge,");
writer.println("# # join us at the IRC or drop by our forums and leave a post.");
writer.println("#");
writer.println("# # IRC: #sponge @ irc.esper.net ( http://webchat.esper.net/?channel=sponge )");
writer.println("# # Forums: https://forums.spongepowered.org/");
writer.println("#");
writer.println();
writer.println("sponge {");
writer.println(" block-tracking {");
writer.println(" # If enabled, adds player tracking support for block positions. Note: This should only be disabled if you do not care who caused a block to change.");
writer.println(" enabled=true");
writer.println(" }");
writer.println(" bungeecord {");
writer.println(" # If enabled, allows BungeeCord to forward IP address, UUID, and Game Profile to this server");
writer.println(" ip-forwarding=true");
writer.println(" }");
writer.println(" commands {}");
writer.println(" debug {");
writer.println(" # Dump chunks in the event of a deadlock");
writer.println(" dump-chunks-on-deadlock=false");
writer.println(" # Dump the heap in the event of a deadlock");
writer.println(" dump-heap-on-deadlock=false");
writer.println(" # Dump the server thread on deadlock warning");
writer.println(" dump-threads-on-warn=false");
writer.println(" # Enable Java's thread contention monitoring for thread dumps");
writer.println(" thread-contention-monitoring=false");
writer.println(" }");
writer.println(" entity {");
writer.println(" # Number of colliding entities in one spot before logging a warning. Set to 0 to disable");
writer.println(" collision-warn-size=200");
writer.println(" # Number of entities in one dimension before logging a warning. Set to 0 to disable");
writer.println(" count-warn-size=0");
writer.println(" # Number of ticks before a painting is respawned on clients when their art is changed");
writer.println(" entity-painting-respawn-delay=2");
writer.println(" # Number of ticks before the fake player entry of a human is removed from the tab list (range of 0 to 100 ticks).");
writer.println(" human-player-list-remove-delay=10");
writer.println(" # Controls the time in ticks for when an item despawns.");
writer.println(" item-despawn-rate=6000");
writer.println(" # Max size of an entity's bounding box before removing it. Set to 0 to disable");
writer.println(" max-bounding-box-size=1000");
writer.println(" # Square of the max speed of an entity before removing it. Set to 0 to disable");
writer.println(" max-speed=100");
writer.println(" }");
writer.println(" entity-activation-range {");
writer.println(" ambient-activation-range=32");
writer.println(" aquatic-activation-range=32");
writer.println(" creature-activation-range=32");
writer.println(" minecraft {");
writer.println(" creature {");
writer.println(" entityhorse=true");
writer.println(" pig=true");
writer.println(" sheep=true");
writer.println(" }");
writer.println(" enabled=true");
writer.println(" misc {");
writer.println(" item=true");
writer.println(" minecartchest=true");
writer.println(" }");
writer.println(" monster {");
writer.println(" guardian=true");
writer.println(" }");
writer.println(" }");
writer.println(" misc-activation-range=16");
writer.println(" monster-activation-range=32");
writer.println(" }");
writer.println(" general {");
writer.println(" # Forces Chunk Loading on provide requests (speedup for mods that don't check if a chunk is loaded)");
writer.println(" chunk-load-override=false");
writer.println(" # Disable warning messages to server admins");
writer.println(" disable-warnings=false");
writer.println(" }");
writer.println(" logging {");
writer.println(" # Log when blocks are broken");
writer.println(" block-break=false");
writer.println(" # Log when blocks are modified");
writer.println(" block-modify=false");
writer.println(" # Log when blocks are placed");
writer.println(" block-place=false");
writer.println(" # Log when blocks are populated in a chunk");
writer.println(" block-populate=false");
writer.println(" # Log when blocks are placed by players and tracked");
writer.println(" block-tracking=false");
writer.println(" # Log when chunks are loaded");
writer.println(" chunk-load=false");
writer.println(" # Log when chunks are unloaded");
writer.println(" chunk-unload=false");
writer.println(" # Whether to log entity collision/count checks");
writer.println(" entity-collision-checks=false");
writer.println(" # Log when living entities are destroyed");
writer.println(" entity-death=false");
writer.println(" # Log when living entities are despawned");
writer.println(" entity-despawn=false");
writer.println(" # Log when living entities are spawned");
writer.println(" entity-spawn=false");
writer.println(" # Whether to log entity removals due to speed");
writer.println(" entity-speed-removal=false");
writer.println(" # Add stack traces to dev logging");
writer.println(" log-stacktraces=false");
writer.println(" }");
writer.println(" modules {");
writer.println(" bungeecord=true");
writer.println(" entity-activation-range=true");
writer.println(" timings=true");
writer.println(" }");
writer.println(" # Configuration options related to the Sql service, including connection aliases etc");
writer.println(" sql {}");
writer.println(" timings {");
writer.println(" enabled=true");
writer.println(" hidden-config-entries=[");
writer.println(" \"sponge.sql\"");
writer.println(" ]");
writer.println(" history-interval=300");
writer.println(" history-length=3600");
writer.println(" server-name-privacy=false");
writer.println(" verbose=false");
writer.println(" }");
writer.println(" world {");
writer.println(" # Lava behaves like vanilla water when source block is removed");
writer.println(" flowing-lava-decay=false");
writer.println(" # Vanilla water source behavior - is infinite");
writer.println(" infinite-water-source=false");
writer.println(" }");
writer.println("}");
writer.println();
writer.close();
}
private void run(UUID player, String name, ServerType type, Version version, int memory, int port) {
Executable exec = null;
UniversalFile dir = new UniversalFile(new File(host.getDirectory()), name);
dir.mkdirs();
if (type == ServerType.SPIGOT) {
exec = new Executable("java -Xmx" + memory + "M -Djline.terminal=jline.UnsupportedTerminal -Dcom.mojang.eula.agree=true -jar Spigot.jar");
try {
GenerateSpigotYAML(dir);
GenerateProperties(dir, port);
} catch (IOException e) {
e.printStackTrace();
}
} else if (type == ServerType.VANILLA) {
exec = new Executable("java -Xmx" + memory + "M -jar Vanilla.jar nogui");
try {
GenerateEULA(dir);
GenerateProperties(dir, port);
} catch (FileNotFoundException | UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (type == ServerType.SPONGE) {
try {
Document spongexml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(Util.readAll(new BufferedReader(new InputStreamReader(new URL("http://files.minecraftforge.net/maven/org/spongepowered/spongeforge/maven-metadata.xml").openStream(), Charset.forName("UTF-8")))))));
Document forgexml = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(new StringReader(Util.readAll(new BufferedReader(new InputStreamReader(new URL("http://files.minecraftforge.net/maven/net/minecraftforge/forge/maven-metadata.xml").openStream(), Charset.forName("UTF-8")))))));
NodeList spnodeList = spongexml.getElementsByTagName("version");
Version spversion = null;
for (int i = 0; i < spnodeList.getLength(); i++) {
Node node = spnodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getTextContent().startsWith(version.toString() + '-') && (spversion == null || new Version(node.getTextContent()).compareTo(spversion) >= 0)) {
spversion = new Version(node.getTextContent());
}
}
}
NodeList mcfnodeList = forgexml.getElementsByTagName("version");
Version mcfversion = null;
for (int i = 0; i < mcfnodeList.getLength(); i++) {
Node node = mcfnodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getTextContent().contains(spversion.toString().split("\\-")[1]) && (mcfversion == null || new Version(node.getTextContent()).compareTo(mcfversion) >= 0)) {
mcfversion = new Version(node.getTextContent());
}
}
}
exec = new Executable("java -Xmx" + memory + "M -jar Forge.jar");
version = new Version(mcfversion.toString() + "::" + spversion.toString());
GenerateEULA(dir);
GenerateProperties(dir, port);
GenerateSpongeConf(dir);
} catch (ParserConfigurationException | IOException | SAXException | NullPointerException e) {
e.printStackTrace();
}
}
try {
InputStream input = null;
OutputStream output = null;
try {
input = new FileInputStream(new UniversalFile(host.plugin.dir, "SubServers:build.sh"));
output = new FileOutputStream(new File(dir, "build-subserver.sh"));
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
output.write(buf, 0, bytesRead);
}
} finally {
if (input != null)
input.close();
if (output != null)
output.close();
}
if (!(new File(dir, "build-subserver.sh").exists())) {
System.out.println("SubCreator > Problem Copying build-subserver.sh!");
} else {
File gitBash = new File(this.gitBash, "bin" + File.separatorChar + "bash.exe");
if (!(System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)) {
Process process1 = Runtime.getRuntime().exec("chmod +x build-subserver.sh", null, dir);
try {
process1.waitFor();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (process1.exitValue() != 0) {
System.out.println("SubCreator > Problem Setting Executable Permissions for build-subserver.sh");
System.out.println("SubCreator > This may cause errors in the Build Process");
}
}
Process process2 = Runtime.getRuntime().exec((System.getProperty("os.name").toLowerCase().indexOf("win") >= 0)?
"\"" + gitBash + "\" --login -i -c \"bash build-subserver.sh " + version.toString() + " " + type.toString().toLowerCase() + "\""
:("bash build-subserver.sh " + version.toString() + " " + type.toString().toLowerCase() + " " + System.getProperty("user.home")), null, dir);
InternalSubLogger read = new InternalSubLogger(process2.getInputStream(), host.getName() + "/Creator", new Container<Boolean>(host.plugin.config.get().getSection("Settings").getBoolean("Log-Creator")), new File(dir, "SubCreator-" + type.toString() + "-" + version.toString().replace("::", "@") + ".log"));
read.start();
try {
process2.waitFor();
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (process2.exitValue() == 0) {
if (host.plugin.exServers.keySet().contains(name.toLowerCase())) host.plugin.exServers.remove(name.toLowerCase());
host.addSubServer(player, name, true, port, "&aThis is a SubServer", true, dir.getPath(), exec, "stop", true, false, false, false, false);
YAMLSection server = new YAMLSection();
server.set("Enabled", true);
server.set("Host", host.getName());
server.set("Port", port);
server.set("Motd", "&aThis is a SubServer");
server.set("Log", true);
server.set("Directory", dir.getPath());
server.set("Executable", exec.toString());
server.set("Stop-Command", "stop");
server.set("Run-On-Launch", false);
server.set("Auto-Restart", false);
server.set("Hidden", false);
server.set("Restricted", false);
host.plugin.config.get().getSection("Servers").set(name, server);
host.plugin.config.save();
} else {
System.out.println("SubCreator > build-subserver.sh exited with an errors. Please try again.");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public boolean create(UUID player, String name, ServerType type, Version version, int memory, int port) {
if (!isBusy()) {
final SubCreateEvent event = new SubCreateEvent(player, host, name, type, version, memory, port);
host.plugin.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
(thread = new Thread(() -> {
InternalSubCreator.this.run(player, name, event.getType(), event.getVersion(), event.getMemory(), port);
})).start();
return true;
} else return false;
} else return false;
}
@Override
public void waitFor() throws InterruptedException {
while (thread != null && thread.isAlive()) {
Thread.sleep(250);
}
}
@Override
public Host getHost() {
return host;
}
@Override
public String getGitBashDirectory() {
return gitBash;
}
@Override
public boolean isBusy() {
return thread != null && thread.isAlive();
}
}