diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/PlugNManager.java b/PlugNManager/src/fr/zabricraft/plugnmanager/PlugNManager.java new file mode 100644 index 0000000..d7a847e --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/PlugNManager.java @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Scanner; + +import fr.zabricraft.plugnmanager.discord.DiscordListener; +import fr.zabricraft.plugnmanager.discord.DiscordStepper; +import fr.zabricraft.plugnmanager.minecraft.MinecraftServer; +import fr.zabricraft.plugnmanager.minecraft.ServerStatus; +import sx.blah.discord.api.ClientBuilder; +import sx.blah.discord.api.IDiscordClient; + +public class PlugNManager { + + private static PlugNManager instance; + + public static PlugNManager getInstance() { + return instance; + } + + public static void main(String[] args) { + new PlugNManager(); + } + + private boolean running; + private Connection connection; + private IDiscordClient discord; + private ArrayList minecraft; + private ArrayList stepper; + + public ArrayList getMinecraft() { + return minecraft; + } + + public ArrayList getDiscordStepper() { + return stepper; + } + + public PlugNManager() { + System.out.println("Starting PlugNManager server..."); + long start = System.currentTimeMillis(); + instance = this; + running = true; + if (initDatabase()) { + initConfigurations(); + long done = System.currentTimeMillis(); + System.out.println("Done ! (" + (done - start) + "ms)"); + new Thread(new Runnable() { + @Override + public void run() { + while (isRunning()) { + if (!serverStarted("hub1")) { + startServer("hub", 1); + } + try { + Statement state = getConnection().createStatement(); + ResultSet result = state.executeQuery("SELECT * FROM start"); + while (result.next()) { + startServer(result.getString("game"), result.getInt("map")); + } + result.close(); + state.close(); + Statement state3 = getConnection().createStatement(); + state3.executeUpdate("TRUNCATE start"); + state3.close(); + } catch (Exception e) { + e.printStackTrace(); + } + try { + Thread.sleep(5000L); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + }).start(); + new Thread(new Runnable() { + @Override + public void run() { + Scanner sc = new Scanner(System.in); + while (isRunning()) { + String s = sc.nextLine(); + String[] args = s.trim().split(" "); + if (args.length == 1 && args[0].equalsIgnoreCase("stop")) { + stop(); + } else if (args.length == 3 && args[0].equalsIgnoreCase("start")) { + startServer(args[1], Integer.parseInt(args[2])); + } else if (args.length > 2 && args[0].equalsIgnoreCase("exec")) { + MinecraftServer server = getMinecraftServer(args[1]); + if (server != null) { + String cmd = ""; + for (int i = 2; i < args.length; i++) { + cmd += args[i] + " "; + } + server.sendCommand(cmd.trim()); + } + } + } + sc.close(); + } + }).start(); + } + } + + public void clearDirectory(File directory) { + if (directory.isDirectory()) { + for (File f : directory.listFiles()) { + if (f.isDirectory()) { + clearDirectory(f); + } + f.delete(); + } + } + } + + public void cloneDirectory(File from, File to) { + if (!to.exists()) { + to.mkdirs(); + } + if (from.isDirectory()) { + for (File f : from.listFiles()) { + try { + File to2 = new File(to, f.getName()); + if (f.isDirectory()) { + cloneDirectory(f, to2); + } else { + Files.copy(f.toPath(), to2.toPath()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + } + + public boolean isRunning() { + return running; + } + + public void initConfigurations() { + try { + System.out.println("Loading configurations..."); + File servers = new File("servers"); + if (!servers.exists()) { + servers.mkdirs(); + } + clearDirectory(servers); + File templates = new File("templates"); + if (!templates.exists()) { + templates.mkdirs(); + } + File libs = new File("libs"); + if (!libs.exists()) { + libs.mkdirs(); + } + this.minecraft = new ArrayList(); + this.stepper = new ArrayList(); + getDiscord().getDispatcher().registerListener(new DiscordListener()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public boolean initDatabase() { + if (getConnection() != null) { + try { + Statement state = getConnection().createStatement(); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `players` (`uuid` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `grade` varchar(255) NOT NULL, `first_login` datetime NOT NULL, PRIMARY KEY (`uuid`))"); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `servers` (`id` varchar(255) NOT NULL, `type` varchar(255) NOT NULL, `port` int(11) NOT NULL, `status` varchar(255) NOT NULL, `map` int(11) NOT NULL, `players` int(11) NOT NULL, PRIMARY KEY (`id`))"); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `games` (`id` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `description` text NOT NULL, `min_players` int(11) NOT NULL, `max_players` int(11) NOT NULL, `slot` int(11) NOT NULL, `icon` varchar(255) NOT NULL, PRIMARY KEY (`id`))"); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `maps` (`id` int(11) NOT NULL AUTO_INCREMENT, `game` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `description` text NOT NULL, `map_hub` varchar(255) NOT NULL, `map_game` varchar(255) NOT NULL, `icon` varchar(255) NOT NULL, PRIMARY KEY (`id`))"); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `start` (`id` int(11) NOT NULL AUTO_INCREMENT, `game` varchar(255) NOT NULL, `map` int(11) NOT NULL, PRIMARY KEY (`id`))"); + state.executeUpdate( + "CREATE TABLE IF NOT EXISTS `ai_answers` (`id` int(11) NOT NULL AUTO_INCREMENT, `keywords` text NOT NULL, `answer` text NOT NULL, PRIMARY KEY (`id`))"); + state.executeUpdate("UPDATE servers SET status = 'OFFLINE'"); + state.close(); + return true; + } catch (SQLException e) { + e.printStackTrace(); + } + } + return false; + } + + public void stop() { + System.out.println("Stopping PlugNManager server..."); + running = false; + stopServers(); + getDiscord().logout(); + System.out.println("Bye !"); + } + + public MinecraftServer getMinecraftServer(String name) { + for (MinecraftServer s : minecraft) { + if (s.getName().equalsIgnoreCase(name)) { + return s; + } + } + return null; + } + + public void startServer(String template, int map) { + try { + PreparedStatement state3 = getConnection().prepareStatement( + "SELECT * FROM servers WHERE type = ? AND map = ? AND (status = ? OR status = ? OR status = ?)"); + state3.setString(1, template); + state3.setInt(2, map); + state3.setString(3, ServerStatus.WAITING.toString()); + state3.setString(4, ServerStatus.COUNTDOWN.toString()); + state3.setString(5, ServerStatus.STARTING.toString()); + ResultSet result3 = state3.executeQuery(); + if (!result3.next()) { + if (minecraft.size() < 12) { + boolean c = true; + for (int i = 1; c; i++) { + if (!serverStarted(template + i)) { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT 1 FROM servers WHERE id = ?"); + state.setString(1, template + i); + ResultSet result = state.executeQuery(); + if (result.next()) { + PreparedStatement state2 = PlugNManager.getInstance().getConnection() + .prepareStatement("UPDATE servers SET map = ?, status = ? WHERE id = ?"); + state2.setInt(1, map); + state2.setString(2, ServerStatus.STARTING.toString()); + state2.setString(3, template + i); + state2.executeUpdate(); + state2.close(); + } else { + PreparedStatement state2 = PlugNManager.getInstance().getConnection().prepareStatement( + "INSERT INTO servers (id, type, port, status, map, players) VALUES(?, ?, ?, ?, ?, ?)"); + state2.setString(1, template + i); + state2.setString(2, template); + state2.setInt(3, getFreePort()); + state2.setString(4, ServerStatus.STARTING.toString()); + state2.setInt(5, map); + state2.setInt(6, 0); + state2.executeUpdate(); + state2.close(); + } + result.close(); + state.close(); + minecraft.add(new MinecraftServer(template + i)); + c = false; + } + } + } + } + result3.close(); + state3.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public void stopServers() { + for (MinecraftServer mc : minecraft) { + mc.sendCommand("stop"); + } + } + + public void uninitServer(MinecraftServer server) { + if (minecraft.contains(server)) { + minecraft.remove(server); + File folder = new File(new File("servers"), server.getName()); + clearDirectory(folder); + folder.delete(); + } + } + + private boolean serverStarted(String name) { + for (MinecraftServer mc : minecraft) { + if (mc.getName().equals(name)) { + return true; + } + } + return false; + } + + private int getFreePort() { + int i; + for (i = 26000; !isFreePort(i); i++) { + } + return i; + } + + private boolean isFreePort(int i) { + boolean free = true; + try { + PreparedStatement state = getConnection().prepareStatement("SELECT port FROM servers WHERE port = ?"); + state.setInt(1, i); + ResultSet result = state.executeQuery(); + free = !result.next(); + result.close(); + state.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + return free; + } + + public DiscordStepper getStepper(long user, long channel) { + for (DiscordStepper s : stepper) { + if (s.isFor(user, channel)) { + return s; + } + } + return null; + } + + public Connection getConnection() { + try { + if (connection == null || connection.isClosed()) { + Class.forName("com.mysql.jdbc.Driver"); + + // Edit here the credentials for your MySQL database + + connection = DriverManager.getConnection("jdbc:mysql://192.168.0.5:3306/plugncraft", "root", ""); + } + } catch (SQLException | ClassNotFoundException e) { + System.out.println("Un probleme est survenue lors de la connexion au serveur MySQL, arret du serveur..."); + stop(); + return null; + } + return connection; + } + + public IDiscordClient getDiscord() { + try { + if (discord == null) { + ClientBuilder clientBuilder = new ClientBuilder(); + + // Fill the string with the token of your discord bot - see https://discordapp.com/developers/applications/ + + clientBuilder.withToken(""); + discord = clientBuilder.login(); + } + } catch (Exception e) { + System.out.println("Un probleme est survenue lors de la connexion au service Discord, arret du serveur..."); + stop(); + return null; + } + return discord; + } + + public String getCraftSearchAIAnswer(String request) { + String answer = ""; + request = request.toLowerCase(); + if (request.startsWith("dis plugncraft")) { + String[] removes = { "dis plugncraft", "\\?", "!", "¿", "¡", ",", ".", "-" }; + for (String remove : removes) { + if (request.contains(remove)) { + request = request.replaceAll(remove, " "); + } + } + request = request.trim(); + if (request.isEmpty()) { + request = "show help"; + } + try { + request = request.replaceAll(" ", "%"); + String query = "SELECT * FROM ai_answers WHERE (keywords LIKE ? "; + ArrayList param = new ArrayList(); + param.add("%" + request + "%"); + String keys[] = request.split("%"); + for (String key : keys) { + query += "OR keywords LIKE ? "; + param.add("%" + key + "%"); + } + query += ") ORDER BY "; + for (String key : keys) { + query += "(CASE WHEN keywords LIKE ? THEN " + (key.equals("broadcast") ? 99999 : 5 + key.length()) + + " ELSE 0 END) + "; + param.add("%" + key + "%"); + } + query += "0 DESC LIMIT 1"; + PreparedStatement state = getConnection().prepareStatement(query); + for (int i = 0; i < param.size(); i++) { + state.setString(i + 1, param.get(i)); + } + ResultSet result = state.executeQuery(); + if (result.next()) { + answer = result.getString("answer"); + } else { + answer = "Je ne trouve rien correspondant à votre requête... Essayez `Dis PlugNCraft, affiche l'aide`"; + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + answer = "Oups! Une erreur est survenue."; + } + return answer; + } + return answer; + } + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordListener.java b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordListener.java new file mode 100644 index 0000000..e628e8c --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordListener.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.discord; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import fr.zabricraft.plugnmanager.PlugNManager; +import fr.zabricraft.plugnmanager.minecraft.ServerStatus; +import sx.blah.discord.api.events.EventSubscriber; +import sx.blah.discord.handle.impl.events.guild.channel.message.MessageReceivedEvent; +import sx.blah.discord.handle.impl.events.guild.member.UserJoinEvent; +import sx.blah.discord.handle.obj.IGuild; +import sx.blah.discord.util.RequestBuffer; + +public class DiscordListener { + + @EventSubscriber + public void onMessageReceived(MessageReceivedEvent e) { + if (e.getAuthor().getLongID() != e.getClient().getOurUser().getLongID()) { + String request = e.getMessage().getContent().trim(); + + DiscordStepper stepper = PlugNManager.getInstance().getStepper(e.getAuthor().getLongID(), + e.getChannel().getLongID()); + if (stepper != null) { + stepper.giveData(request); + stepper.sendMessage(); + if (stepper.isDone()) { + PlugNManager.getInstance().getDiscordStepper().remove(stepper); + } + return; + } + + String answer = PlugNManager.getInstance().getCraftSearchAIAnswer(request); + if (e.getChannel().isPrivate() && answer.isEmpty()) { + answer = PlugNManager.getInstance().getCraftSearchAIAnswer("dis plugncraft " + request); + } + if (!answer.isEmpty()) { + if (answer.equals("startServer()")) { + answer = ""; + PlugNManager.getInstance().getDiscordStepper() + .add(new StartServerStepper(e.getAuthor().getLongID(), e.getChannel().getLongID())); + } + if (answer.equals("status()")) { + answer = "Voici les statuts des serveurs de PlugNCraft :\n"; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT * FROM servers WHERE status != ?"); + state.setString(1, ServerStatus.OFFLINE.toString()); + ResultSet result = state.executeQuery(); + while (result.next()) { + answer += "\n`" + result.getString("id") + "` est "; + switch (result.getString("status")) { + case "STARTING": + answer += "en cours de démarrage"; + break; + case "WAITING": + answer += "en attente, avec " + result.getInt("players") + " joueur(s) en ligne"; + break; + case "COUNTDOWN": + answer += "au compte à rebours, avec " + result.getInt("players") + + " joueur(s) en ligne"; + break; + case "PLAYING": + answer += "en cours, avec " + result.getInt("players") + " joueur(s) en ligne"; + break; + case "FINISHED": + answer += "terminé"; + break; + default: + answer += "de statut inconnu"; + } + answer += "."; + } + result.close(); + state.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + if (answer.contains("@player")) { + answer = answer.replaceAll("@player", e.getAuthor().mention()); + } + if (answer.contains("@discord_server_count")) { + answer = answer.replaceAll("@discord_server_count", e.getClient().getGuilds().size() + ""); + } + if (answer.contains("@discord_server_list")) { + String list = ""; + for (IGuild guild : e.getClient().getGuilds()) { + list += ", " + guild.getName() + " (" + guild.getLongID() + ")"; + } + answer = answer.replaceAll("@discord_server_list", list.substring(2)); + } + if (!answer.isEmpty()) { + String discord_msg = answer; + RequestBuffer.request(() -> e.getChannel().sendMessage(discord_msg)); + } + } + } + + } + + @EventSubscriber + public void onUserJoin(UserJoinEvent e) { + if (e.getGuild().getLongID() == 264703386127958024L) { + RequestBuffer.request(() -> e.getClient().getOrCreatePMChannel(e.getUser()) + .sendMessage("Bienvenue " + e.getUser().mention() + " sur le serveur Discord de " + + e.getGuild().getName() + "!\n\n" + + "PlugNCraft est le premier serveur automatisé sur demande.\n\n" + + "Tu n'as qu'à dire `Dis PlugNCraft` n'importe où où je suis présent.")); + } + } + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordStepper.java b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordStepper.java new file mode 100644 index 0000000..9319391 --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/DiscordStepper.java @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.discord; + +import fr.zabricraft.plugnmanager.PlugNManager; +import sx.blah.discord.util.RequestBuffer; + +public abstract class DiscordStepper { + + private long user; + private long channel; + protected int step; + private boolean done; + + public DiscordStepper(long user, long channel) { + this.user = user; + this.channel = channel; + this.step = 0; + this.done = false; + sendMessage(); + } + + public abstract String getMessage(); + + public abstract void giveData(String data); + + public boolean isFor(long user, long channel) { + return this.user == user && this.channel == channel; + } + + public void end() { + done = true; + } + + public boolean isDone() { + return done; + } + + public long getUser() { + return user; + } + + public void sendMessage() { + RequestBuffer.request( + () -> PlugNManager.getInstance().getDiscord().getChannelByID(channel).sendMessage(getMessage())); + } + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/discord/StartServerStepper.java b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/StartServerStepper.java new file mode 100644 index 0000000..e47b9f3 --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/discord/StartServerStepper.java @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.discord; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import fr.zabricraft.plugnmanager.PlugNManager; + +public class StartServerStepper extends DiscordStepper { + + private String game; + private int map; + + public StartServerStepper(long user, long channel) { + super(user, channel); + game = ""; + map = 0; + } + + public String getMessage() { + if (step == 0) { + try { + String message = "Choisissez un jeu pour le serveur à démarrer :\n"; + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT * FROM games WHERE id != ?"); + state.setString(1, "hub"); + ResultSet result = state.executeQuery(); + while (result.next()) { + message += "\nTapez `" + result.getString("id") + "` pour démarrer un serveur " + + result.getString("name"); + } + result.close(); + state.close(); + return message; + } catch (SQLException e) { + e.printStackTrace(); + } + } else if (step == 1) { + try { + String message = "Choisissez une carte pour le serveur à démarrer :\n"; + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT * FROM maps WHERE game = ?"); + state.setString(1, game); + ResultSet result = state.executeQuery(); + while (result.next()) { + message += "\nTapez `" + result.getInt("id") + "` pour choisir la carte " + + result.getString("name"); + } + result.close(); + state.close(); + return message; + } catch (SQLException e) { + e.printStackTrace(); + } + } else { + return "Très bien, je démarre le serveur !"; + } + end(); + return "Oups, une erreur est survenue !"; + } + + public void giveData(String data) { + if (step == 0) { + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT * FROM games WHERE id = ?"); + state.setString(1, data); + ResultSet result = state.executeQuery(); + if (result.next()) { + game = data; + step++; + } + result.close(); + state.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } else if (step == 1) { + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT * FROM maps WHERE game = ? AND id = ?"); + state.setString(1, game); + state.setInt(2, Integer.parseInt(data)); + ResultSet result = state.executeQuery(); + if (result.next()) { + map = Integer.parseInt(data); + step++; + PlugNManager.getInstance().startServer(game, map); + end(); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/MinecraftServer.java b/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/MinecraftServer.java new file mode 100644 index 0000000..92231be --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/MinecraftServer.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.minecraft; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.InputStreamReader; +import java.io.PrintStream; +import java.nio.file.Files; +import java.sql.PreparedStatement; +import java.sql.ResultSet; + +import fr.zabricraft.plugnmanager.PlugNManager; + +public class MinecraftServer { + + private String name; + private Process process; + private String logs; + + public MinecraftServer(String name) { + this.name = name; + this.logs = ""; + new Thread(new Runnable() { + @Override + public void run() { + try { + log("Starting minecraft server..."); + + Template template = new Template(getTemplate()); + Map map = new Map(getMap()); + + File launcher = new File("spigot.jar"); + if (!launcher.exists()) { + log("File spigot.jar not found, can not start server!"); + PlugNManager.getInstance().uninitServer(link()); + return; + } + + log("Creating folder..."); + File main = new File(new File("servers"), name); + if (!main.exists()) { + main.mkdirs(); + } + PlugNManager.getInstance().clearDirectory(main); + + log("Creating configuration files..."); + File eula = new File(main, "eula.txt"); + eula.createNewFile(); + FileWriter eula2 = new FileWriter(eula); + eula2.write("eula=true"); + eula2.close(); + + File properties = new File(main, "server.properties"); + properties.createNewFile(); + FileWriter properties2 = new FileWriter(properties); + properties2.write("server-name=" + name + "\n"); + properties2.write("server-port=" + getPort() + "\n"); + properties2.write("max-players=" + template.getMaxPlayers() + "\n"); + properties2.write("level-name=hub\n"); + properties2.write("online-mode=false\n"); + properties2.write("announce-player-achievements=false\n"); + properties2.close(); + + File spigot_conf = new File(main, "spigot.yml"); + spigot_conf.createNewFile(); + FileWriter spigot_conf2 = new FileWriter(spigot_conf); + spigot_conf2.write("settings:\n"); + spigot_conf2.write(" bungeecord: true\n"); + spigot_conf2.write(" restart-on-crash: false\n"); + spigot_conf2.close(); + + File plugins = new File(main, "plugins"); + plugins.mkdirs(); + + log("Copying libraries..."); + File libs = new File("libs"); + + for (File pl : libs.listFiles()) { + File to = new File(plugins, pl.getName()); + if (pl.isDirectory()) { + PlugNManager.getInstance().cloneDirectory(pl, to); + } else { + log("Copying lib " + pl.getName() + " to " + to.getAbsolutePath() + "..."); + Files.copy(pl.toPath(), to.toPath()); + } + } + + log("Copying plugins..."); + for (File pl : new File(new File(new File("templates"), template.getId()), "plugins").listFiles()) { + File to = new File(plugins, pl.getName()); + if (pl.isDirectory()) { + PlugNManager.getInstance().cloneDirectory(pl, to); + } else { + log("Copying plugin " + pl.getName() + " to " + to.getAbsolutePath() + "..."); + Files.copy(pl.toPath(), to.toPath()); + } + } + + log("Copying maps..."); + File map_hub = new File(new File(new File(new File("templates"), template.getId()), "maps"), + map.getMapHub()); + if (map_hub.exists() && map_hub.isDirectory()) { + File hub = new File(main, "hub"); + PlugNManager.getInstance().cloneDirectory(map_hub, hub); + log("Copying map " + map_hub.getAbsolutePath() + " for hub..."); + } + File map_game = new File(new File(new File(new File("templates"), template.getId()), "maps"), + map.getMapGame()); + if (map_game.exists() && map_game.isDirectory()) { + File game = new File(main, "game"); + PlugNManager.getInstance().cloneDirectory(map_game, game); + log("Copying map " + map_game.getAbsolutePath() + " for game..."); + } + + log("Launching server..."); + process = Runtime.getRuntime().exec("java -Xmx2G -jar " + launcher.getCanonicalPath(), null, main); + new Thread(new Runnable() { + @Override + public void run() { + try { + BufferedReader out = new BufferedReader( + new InputStreamReader(process.getInputStream())); + String line = ""; + while ((line = out.readLine()) != null) { + log(line); + } + } catch (Exception e) { + } + } + }).start(); + new Thread(new Runnable() { + @Override + public void run() { + try { + BufferedReader out = new BufferedReader( + new InputStreamReader(process.getErrorStream())); + String line = ""; + while ((line = out.readLine()) != null) { + log(line); + } + } catch (Exception e) { + } + } + }).start(); + new Thread(new Runnable() { + @Override + public void run() { + try { + process.waitFor(); + PlugNManager.getInstance().uninitServer(link()); + } catch (Exception e) { + } + } + }).start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }).start(); + } + + public String getName() { + return name; + } + + public String getLogs() { + return logs; + } + + public void log(String line) { + if (!line.equals(">")) { + logs += line + "\n"; + System.out.println("[" + name + "] " + line); + } + } + + public void sendCommand(String cmd) { + PrintStream in = new PrintStream(process.getOutputStream()); + in.println(cmd); + in.flush(); + } + + private MinecraftServer link() { + return this; + } + + public String getTemplate() { + String template = ""; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT type FROM servers WHERE id = ?"); + state.setString(1, name); + ResultSet result = state.executeQuery(); + if (result.next()) { + template = result.getString("type"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return template; + } + + public int getMap() { + int map = 0; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT map FROM servers WHERE id = ?"); + state.setString(1, name); + ResultSet result = state.executeQuery(); + if (result.next()) { + map = result.getInt("map"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return map; + } + + public int getPort() { + int port = 0; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT port FROM servers WHERE id = ?"); + state.setString(1, name); + ResultSet result = state.executeQuery(); + if (result.next()) { + port = result.getInt("port"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return port; + } + + public class Template { + + private String id; + + public Template(String id) { + this.id = id; + } + + public String getId() { + return id; + } + + public int getMinPlayers() { + int min_players = 0; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT min_players FROM games WHERE id = ?"); + state.setString(1, id); + ResultSet result = state.executeQuery(); + if (result.next()) { + min_players = result.getInt("min_players"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return min_players; + } + + public int getMaxPlayers() { + int max_players = 0; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT max_players FROM games WHERE id = ?"); + state.setString(1, id); + ResultSet result = state.executeQuery(); + if (result.next()) { + max_players = result.getInt("max_players"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return max_players; + } + + } + + public class Map { + + private int id; + + public Map(int id) { + this.id = id; + } + + public String getMapHub() { + String map_hub = ""; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT map_hub FROM maps WHERE id = ?"); + state.setInt(1, id); + ResultSet result = state.executeQuery(); + if (result.next()) { + map_hub = result.getString("map_hub"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return map_hub; + } + + public String getMapGame() { + String map_game = ""; + try { + PreparedStatement state = PlugNManager.getInstance().getConnection() + .prepareStatement("SELECT map_game FROM maps WHERE id = ?"); + state.setInt(1, id); + ResultSet result = state.executeQuery(); + if (result.next()) { + map_game = result.getString("map_game"); + } + result.close(); + state.close(); + } catch (Exception e) { + e.printStackTrace(); + } + return map_game; + } + + } + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/ServerStatus.java b/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/ServerStatus.java new file mode 100644 index 0000000..340b736 --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/minecraft/ServerStatus.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.minecraft; + +public enum ServerStatus { + + STARTING, OFFLINE, WAITING, COUNTDOWN, PLAYING, FINISHED; + +} diff --git a/PlugNManager/src/fr/zabricraft/plugnmanager/utils/MD5.java b/PlugNManager/src/fr/zabricraft/plugnmanager/utils/MD5.java new file mode 100644 index 0000000..a45f221 --- /dev/null +++ b/PlugNManager/src/fr/zabricraft/plugnmanager/utils/MD5.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2017 FALLET Nathan + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +package fr.zabricraft.plugnmanager.utils; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5 { + + public static String encode(String password) { + byte[] uniqueKey = password.getBytes(); + byte[] hash = null; + + try { + hash = MessageDigest.getInstance("MD5").digest(uniqueKey); + } catch (NoSuchAlgorithmException e) { + throw new Error("No MD5 support in this VM."); + } + + StringBuilder hashString = new StringBuilder(); + for (int i = 0; i < hash.length; i++) { + String hex = Integer.toHexString(hash[i]); + if (hex.length() == 1) { + hashString.append('0'); + hashString.append(hex.charAt(hex.length() - 1)); + } else + hashString.append(hex.substring(hex.length() - 2)); + } + return hashString.toString(); + } + +}