From 908e54fedd364cbd244b6a6a0e4d3a1e54bc93a0 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 19 Mar 2022 16:10:09 +0100 Subject: [PATCH] Server start refactoring, tutorial system Signed-off-by: Lixfel --- src/de/steamwar/bungeecore/BungeeCore.java | 5 +- src/de/steamwar/bungeecore/EventStarter.java | 7 +- src/de/steamwar/bungeecore/ServerStarter.java | 272 ++++++++++++++++++ .../steamwar/bungeecore/SubserverSystem.java | 191 +----------- .../bungeecore/commands/BauCommand.java | 52 +--- .../bungeecore/commands/ChallengeCommand.java | 6 +- .../bungeecore/commands/CheckCommand.java | 5 +- .../bungeecore/commands/FightCommand.java | 3 +- .../bungeecore/commands/HistoricCommand.java | 8 +- .../bungeecore/commands/ReplayCommand.java | 16 +- .../bungeecore/commands/TutorialCommand.java | 91 +++++- .../comms/handlers/PrepareSchemHandler.java | 6 +- src/de/steamwar/bungeecore/sql/Tutorial.java | 31 +- .../steamwar/messages/BungeeCore.properties | 6 +- 14 files changed, 407 insertions(+), 292 deletions(-) create mode 100644 src/de/steamwar/bungeecore/ServerStarter.java diff --git a/src/de/steamwar/bungeecore/BungeeCore.java b/src/de/steamwar/bungeecore/BungeeCore.java index 5fdbecf..846dd5c 100644 --- a/src/de/steamwar/bungeecore/BungeeCore.java +++ b/src/de/steamwar/bungeecore/BungeeCore.java @@ -120,10 +120,10 @@ public class BungeeCore extends Plugin { new ListCommand(); new StatCommand(); new VerifyCommand(); - new ReplayCommand(); new GDPRQuery(); new PlaytimeCommand(); new ArenaCommand(); + new RankCommand(); // Punishment Commands: new PunishmentCommand("ban", Punishment.PunishmentType.Ban); @@ -140,7 +140,8 @@ public class BungeeCore extends Plugin { new ChallengeCommand(); new HistoricCommand(); new CheckCommand(); - new RankCommand(); + new ReplayCommand(); + new TutorialCommand(); new Broadcaster(); }else{ diff --git a/src/de/steamwar/bungeecore/EventStarter.java b/src/de/steamwar/bungeecore/EventStarter.java index e0e29af..98d75e3 100644 --- a/src/de/steamwar/bungeecore/EventStarter.java +++ b/src/de/steamwar/bungeecore/EventStarter.java @@ -64,12 +64,13 @@ public class EventStarter implements Runnable { Team blue = Team.get(next.getTeamBlue()); Team red = Team.get(next.getTeamRed()); - String serverName = blue.getTeamKuerzel() + " vs " + red.getTeamKuerzel(); - Subserver subserver = SubserverSystem.startEventArena(next, serverName); + ServerStarter starter = new ServerStarter().event(next); ProxiedPlayer leiter = ProxyServer.getInstance().getPlayer(SteamwarUser.get(next.getKampfleiter()).getUuid()); if(leiter != null) - SubserverSystem.sendPlayer(subserver, leiter); + starter.send(leiter); + + Subserver subserver = starter.start(); eventServer.put(blue.getTeamId(), subserver); eventServer.put(red.getTeamId(), subserver); diff --git a/src/de/steamwar/bungeecore/ServerStarter.java b/src/de/steamwar/bungeecore/ServerStarter.java new file mode 100644 index 0000000..39c1693 --- /dev/null +++ b/src/de/steamwar/bungeecore/ServerStarter.java @@ -0,0 +1,272 @@ +package de.steamwar.bungeecore; + +import de.steamwar.bungeecore.sql.EventFight; +import de.steamwar.bungeecore.sql.SteamwarUser; +import de.steamwar.bungeecore.sql.Team; +import de.steamwar.bungeecore.sql.Tutorial; +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.io.File; +import java.net.InetSocketAddress; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.function.BooleanSupplier; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class ServerStarter { + + private static final boolean MAIN_SERVER = ProxyServer.getInstance().getConfig().getListeners().stream().anyMatch(info -> ((InetSocketAddress) info.getSocketAddress()).getPort() == 25565); + private static final Portrange BAU_PORTS = MAIN_SERVER ? new Portrange(10100, 20000) : new Portrange(2100, 2200); + private static final Portrange ARENA_PORTS = MAIN_SERVER ? new Portrange(3000, 3100) : (BungeeCore.EVENT_MODE ? new Portrange(4000, 5000) : BAU_PORTS); + + private static final String BACKBONE = "/home/minecraft/"; + private static final String SERVER_PATH = BACKBONE + "server/"; + private static final String EVENT_PATH = BACKBONE + "event/"; + public static final String TEMP_WORLD_PATH = BACKBONE + "arenaserver/"; + public static final String TUTORIAL_PATH = BACKBONE + "tutorials/"; + + private File directory = null; + private String worldDir = null; + + private Node node = null; + private String serverJar = "spigot-1.15.2.jar"; + private String xmx = "768M"; + private Portrange portrange = BAU_PORTS; + private Function serverNameProvider = port -> node.getName() + port; + private BooleanSupplier startCondition = () -> true; + private ServerConstructor constructor = (serverName, port, builder, shutdownCallback) -> new Subserver(Servertype.ARENA, serverName, port, builder, shutdownCallback); + private Runnable worldSetup = () -> {}; + private String worldName = null; + private Runnable worldCleanup = () -> {}; + + private final Set playersToSend = new HashSet<>(); + private final Map arguments = new HashMap<>(); + + public ServerStarter arena(ArenaMode mode, String map) { + portrange = ARENA_PORTS; + serverNameProvider = port -> mode.getChatName() + (port - portrange.start); + serverJar = mode.serverJar(); + directory = new File(SERVER_PATH, mode.getFolder()); + arguments.put("config", mode.getConfig()); + tempWorld(SERVER_PATH + mode.getFolder() + "/arenas/" + map); + return this; + } + + public ServerStarter event(EventFight eventFight) { + arena(eventFight.getSpielmodus(), eventFight.getMap()); + node = Node.local; + worldDir = EVENT_PATH; + worldCleanup = () -> {}; + arguments.put("fightID", String.valueOf(eventFight.getFightID())); + + String serverName = Team.get(eventFight.getTeamBlue()).getTeamKuerzel() + " vs " + Team.get(eventFight.getTeamRed()).getTeamKuerzel(); + serverNameProvider = port -> serverName; + worldName = serverToWorldName(serverName + eventFight.getStartTime().toLocalDateTime().format(DateTimeFormatter.ISO_TIME)); + return this; + } + + public ServerStarter test(ArenaMode mode, String map, ProxiedPlayer owner) { + arena(mode, map); + buildWithTemp(owner); + portrange = BAU_PORTS; + arguments.put("fightID", String.valueOf(-1)); + return send(owner); + } + + public ServerStarter blueLeader(ProxiedPlayer player) { + arguments.put("blueLeader", player.getUniqueId().toString()); + return send(player); + } + + public ServerStarter redLeader(ProxiedPlayer player) { + arguments.put("redLeader", player.getUniqueId().toString()); + return send(player); + } + + public ServerStarter check(int schemID) { + arguments.put("checkSchemID", String.valueOf(schemID)); + return this; + } + + public ServerStarter prepare(int schemID) { + arguments.put("prepareSchemID", String.valueOf(schemID)); + return this; + } + + public ServerStarter replay(int replayID) { + arguments.put("replay", String.valueOf(replayID)); + return this; + } + + public ServerStarter build15(UUID owner) { + directory = new File(SERVER_PATH, "Bau15"); + worldDir = BungeeCore.USERWORLDS15; + worldName = String.valueOf(SteamwarUser.get(owner).getId()); + buildWithWorld(owner, BungeeCore.BAUWELT15); + return this; + } + + public ServerStarter build12(UUID owner) { + directory = new File(SERVER_PATH, "UserBau"); + serverJar = "spigot-1.12.2.jar"; + xmx = "256M"; + worldDir = BungeeCore.WORLD_FOLDER; + worldName = owner.toString(); + buildWithWorld(owner, BungeeCore.BAUWELT_PROTOTYP); + return this; + } + + public ServerStarter tutorial(ProxiedPlayer owner, Tutorial tutorial) { + directory = new File(SERVER_PATH, "Tutorial"); + buildWithTemp(owner); + tempWorld(TUTORIAL_PATH + tutorial.id()); + arguments.put("tutorial", String.valueOf(tutorial.id())); + return send(owner); + } + + private void tempWorld(String template) { + worldDir = TEMP_WORLD_PATH; + worldSetup = () -> copyWorld(node, template, worldDir + worldName); + worldCleanup = () -> SubserverSystem.deleteFolder(node, worldDir + worldName); + } + + private void buildWithWorld(UUID owner, String prototype) { + build(owner); + + worldSetup = () -> { + File world = new File(worldDir, worldName); + if (!world.exists()) + copyWorld(node, prototype, world.getPath()); + }; + + // Send players to existing server + startCondition = () -> { + for(Subserver subserver : Subserver.getServerList()) { + if(subserver.getType() == Servertype.BAUSERVER && ((Bauserver)subserver).getOwner().equals(owner)) { + for(ProxiedPlayer p : playersToSend) + SubserverSystem.sendPlayer(subserver, p); + return false; + } + } + return true; + }; + } + + private void buildWithTemp(ProxiedPlayer owner) { + build(owner.getUniqueId()); + + // Stop existing build server + startCondition = () -> { + if(startingBau(owner)) + return false; + + for (Subserver subserver : Subserver.getServerList()) { + if (subserver.getType() == Servertype.BAUSERVER && ((Bauserver) subserver).getOwner().equals(owner.getUniqueId()) && subserver.hasStarted()) { + subserver.stop(); + break; + } + } + + return !startingBau(owner); + }; + } + + private void build(UUID owner) { + constructor = (serverName, port, builder, shutdownCallback) -> new Bauserver(serverName, owner, port, builder, shutdownCallback); + serverNameProvider = port -> bauServerName(SteamwarUser.get(owner)); + } + + public ServerStarter send(ProxiedPlayer player) { + playersToSend.add(player); + return this; + } + + public Subserver start() { + if(!startCondition.getAsBoolean()) + return null; + + int port = portrange.freePort(); + String serverName = serverNameProvider.apply(port); + + if(node == null) + node = Node.getNode(); + if(worldName == null) + worldName = serverToWorldName(serverName); + + worldSetup.run(); + arguments.put("logPath", worldName); + + Subserver subserver = constructor.construct(serverName, port, node.startServer( + serverJar, directory, worldDir, worldName, port, xmx, (String[]) arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray() + ), worldCleanup); + + for(ProxiedPlayer p : playersToSend) + SubserverSystem.sendPlayer(subserver, p); + + return subserver; + } + + private static boolean startingBau(ProxiedPlayer p) { + for (Subserver subserver : Subserver.getServerList()) { + if (subserver.getType() == Servertype.BAUSERVER && ((Bauserver) subserver).getOwner().equals(p.getUniqueId()) && !subserver.hasStarted()) { + Message.send("BAU_START_ALREADY", p); + return true; + } + } + return false; + } + + public static String bauServerName(SteamwarUser user) { + return user.getUserName() + "s Bau"; + } + + public static String serverToWorldName(String serverName) { + return serverName.replace(' ', '_').replace("[", "").replace("]", ""); + } + + public static void copyWorld(Node node, String template, String target) { + node.execute("cp", "-r", template, target); + } + + private interface ServerConstructor { + Subserver construct(String serverName, int port, ProcessBuilder builder, Runnable shutdownCallback); + } + + private static class Portrange { + + private final int start; + private final int end; + private int current; + + private Portrange(int start, int end) { + this.start = start; + this.end = end; + current = start; + } + + private void increment() { + current++; + + if(current == end) + current = start; + } + + private synchronized int freePort() { + Set usedPorts; + + synchronized (Subserver.getServerList()) { + usedPorts = Subserver.getServerList().stream().map(server -> ((InetSocketAddress) server.getServer().getSocketAddress()).getPort()).collect(Collectors.toSet()); + } + + while(usedPorts.contains(current)) { + increment(); + } + + int result = current; + increment(); + return result; + } + } +} diff --git a/src/de/steamwar/bungeecore/SubserverSystem.java b/src/de/steamwar/bungeecore/SubserverSystem.java index b0085f0..2908acb 100644 --- a/src/de/steamwar/bungeecore/SubserverSystem.java +++ b/src/de/steamwar/bungeecore/SubserverSystem.java @@ -21,157 +21,21 @@ package de.steamwar.bungeecore; import de.steamwar.bungeecore.comms.handlers.FightInfoHandler; import de.steamwar.bungeecore.comms.packets.StartingServerPacket; -import de.steamwar.bungeecore.sql.EventFight; import de.steamwar.bungeecore.sql.IgnoreSystem; import de.steamwar.bungeecore.sql.SteamwarUser; import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.chat.ClickEvent; import net.md_5.bungee.api.connection.ProxiedPlayer; -import java.io.File; -import java.net.InetSocketAddress; -import java.time.format.DateTimeFormatter; -import java.util.Set; import java.util.UUID; -import java.util.stream.Collectors; public class SubserverSystem { private SubserverSystem(){} - private static final String BACKBONE = "/home/minecraft/"; - private static final String ARENA_PATH = BACKBONE + "arenaserver/"; - private static final String SERVER_PATH = BACKBONE + "server/"; - private static final String EVENT_PATH = BACKBONE + "event/"; - - private static final boolean MAIN_SERVER = ProxyServer.getInstance().getConfig().getListeners().stream().anyMatch(info -> ((InetSocketAddress) info.getSocketAddress()).getPort() == 25565); - private static final Portrange bauPorts = MAIN_SERVER ? new Portrange(10100, 20000) : new Portrange(2100, 2200); - private static final Portrange arenaPorts = MAIN_SERVER ? new Portrange(3000, 3100) : (BungeeCore.EVENT_MODE ? new Portrange(4000, 5000) : bauPorts); - - /** - * This function starts every arena (even test- and eventarenas). - * - * @param modus - * This has to be a valid arena mode - * - * @param map - * This String must be the internal map name of the selected map - * - * @param eventFightID - * For a normal arena: 0 - * For a test arena: -1 - * For an event arena: EventFightID of the fight - * - * @param replayID - * @param serverName - * The name of the server (for event and test arenas) - * or null (autogenerated arena name modus.getDisplayName() + number) - * - * @param mapName - * The name of the map copy the server runs on (for event and test arenas) - * or null (autogenerated map name equals server name) - * - * @param player1 - * For event and normal arenas: The UUID of the designated leader for the blue team - * or null (no designated leader). - * For test arenas: The owner's UUID of the test arena (disables normal function). - * - * @param player2 - * For event, test and normal arenas: The UUID of the designated leader for the red team - * or null (no designated leader). - * - * @return - * The new started subserver. - */ - public static synchronized Subserver startArena(ArenaMode modus, String map, int eventFightID, int checkSchemID, int prepareSchemID, int replayID, String serverName, String mapName, UUID player1, UUID player2){ - //Generate missing parameters - Node node = eventFightID > 0 ? Node.local : Node.getNode(); - int port = arenaPorts.freePort(); - - if(serverName == null){ - serverName = modus.getDisplayName() + (port - arenaPorts.start); - } - if(mapName == null) - mapName = serverName; - - mapName = mapName.replace(' ', '_').replace("[", "").replace("]", ""); - - String worldDir; - if(eventFightID > 0) - worldDir = EVENT_PATH; - else - worldDir = ARENA_PATH; - - //Copy world - node.execute("cp", "-r", SERVER_PATH + modus.getFolder() + "/arenas/" + map, worldDir + mapName); - - File directory = new File(SERVER_PATH, modus.getFolder()); - ProcessBuilder builder = node.startServer( - modus.serverJar(), directory, worldDir, mapName, port, "768M", - "logPath=" + mapName, "config=" + modus.getConfig(), - "fightID=" + eventFightID, - "checkSchemID=" + checkSchemID, "prepareSchemID=" + prepareSchemID, - "replay=" + replayID, - player1 != null && eventFightID != -1 ? "blueLeader=" + player1 : null, - player2 != null ? "redLeader=" + player2 : null - ); - - String finalMapName = mapName; - if(eventFightID == -1) - return new Bauserver(serverName, player1, port, builder, () -> deleteFolder(node, ARENA_PATH + finalMapName)); - else - return new Subserver(Servertype.ARENA, serverName, port, builder, () -> { - if(eventFightID > 0) - return; - deleteFolder(node, ARENA_PATH + finalMapName); - }); - } - - public static void deleteFolder(Node node, String worldName){ + public static void deleteFolder(Node node, String worldName) { node.execute("rm", "-r", worldName); } - public static Subserver startEventArena(EventFight eventFight, String serverName){ - return startArena( - eventFight.getSpielmodus(), - eventFight.getMap(), - eventFight.getFightID(), - 0, - 0, - 0, serverName, - serverName + eventFight.getStartTime().toLocalDateTime().format(DateTimeFormatter.ISO_TIME), - null, - null); - } - - public static void startTestServer(ProxiedPlayer p, ArenaMode m, String map, int checkSchemId, int prepareSchemId){ - sendPlayer(startArena(m, map, -1, checkSchemId, prepareSchemId, 0, p.getName() + "s Bau", p.getName(), p.getUniqueId(), null), p); - } - - private static synchronized void sendToBau(ProxiedPlayer p, UUID owner, String prototype, String worldFolder, String serverJar, String worldDir, String worldName, String xmx, String serverName){ - if(bauRunning(p, owner)) - return; - - copyBauweltIfRequired(prototype, worldFolder + worldName); - SteamwarUser user = SteamwarUser.get(owner); - File directory = new File(SERVER_PATH, serverName); - Node node = Node.getNode(); - int port = bauPorts.freePort(); - - - sendPlayer(new Bauserver(user.getUserName() + "s Bau", owner, port, node.startServer( - serverJar, directory, worldDir, worldName, port, xmx, "logPath=" + worldName - ), () -> {}), p); - } - - public static void sendToBauServer(ProxiedPlayer p, UUID owner){ - sendToBau(p, owner, BungeeCore.BAUWELT_PROTOTYP, BungeeCore.WORLD_FOLDER, "spigot-1.12.2.jar", "/home/minecraft/userworlds", owner.toString(), "256M", "UserBau"); - } - - public static void sendToBau15(ProxiedPlayer p, UUID owner){ - SteamwarUser user = SteamwarUser.get(owner); - sendToBau(p, owner, BungeeCore.BAUWELT15, BungeeCore.USERWORLDS15, "spigot-1.15.2.jar", "/home/minecraft/userworlds15", String.valueOf(user.getId()), "768M", "Bau15"); - } - public static void sendDeniedMessage(ProxiedPlayer p, UUID owner){ ProxiedPlayer o = ProxyServer.getInstance().getPlayer(owner); if(o == null) @@ -191,57 +55,4 @@ public class SubserverSystem { if(!subserver.hasStarted() && FightInfoHandler.onLobby(player)) new StartingServerPacket(SteamwarUser.get(player.getUniqueId())).send(player); } - - private static boolean bauRunning(ProxiedPlayer p, UUID owner){ - for(Subserver subserver : Subserver.getServerList()){ - if(subserver.getType() == Servertype.BAUSERVER && ((Bauserver)subserver).getOwner().equals(owner)){ - sendPlayer(subserver, p); - return true; - } - } - return false; - } - - private static void copyBauweltIfRequired(String sourcePath, String targetPath){ - File w = new File(targetPath); - if (!w.exists() || !w.isDirectory()) - Node.local.execute("cp", "-r", sourcePath, targetPath); - } - - - private static class Portrange { - - private final int start; - private final int end; - private int current; - - private Portrange(int start, int end) { - this.start = start; - this.end = end; - current = start; - } - - private void increment() { - current++; - - if(current == end) - current = start; - } - - private synchronized int freePort() { - Set usedPorts; - - synchronized (Subserver.getServerList()) { - usedPorts = Subserver.getServerList().stream().map(server -> ((InetSocketAddress) server.getServer().getSocketAddress()).getPort()).collect(Collectors.toSet()); - } - - while(usedPorts.contains(current)) { - increment(); - } - - int result = current; - increment(); - return result; - } - } } diff --git a/src/de/steamwar/bungeecore/commands/BauCommand.java b/src/de/steamwar/bungeecore/commands/BauCommand.java index cc9b8ef..5a58a73 100644 --- a/src/de/steamwar/bungeecore/commands/BauCommand.java +++ b/src/de/steamwar/bungeecore/commands/BauCommand.java @@ -45,20 +45,17 @@ public class BauCommand extends BasicCommand { ProxiedPlayer p = (ProxiedPlayer) sender; if(args.length == 0){ - if(bau15(p, args, 0)) - SubserverSystem.sendToBau15(p, p.getUniqueId()); - else - SubserverSystem.sendToBauServer(p, p.getUniqueId()); + (bau15(p, args, 0) ? new ServerStarter().build15(p.getUniqueId()) : new ServerStarter().build12(p.getUniqueId())).send(p).start(); return; } switch(args[0].toLowerCase()){ - case "ws": - case "warship": case "12": case "1.12": - SubserverSystem.sendToBauServer(p, p.getUniqueId()); + new ServerStarter().build12(p.getUniqueId()).send(p).start(); break; + case "ws": + case "warship": case "as": case "airship": case "mwg": @@ -67,7 +64,7 @@ public class BauCommand extends BasicCommand { case "wargear": case "15": case "1.15": - SubserverSystem.sendToBau15(p, p.getUniqueId()); + new ServerStarter().build15(p.getUniqueId()).send(p).start(); break; case "addmember": addmember(p, args); @@ -143,10 +140,7 @@ public class BauCommand extends BasicCommand { return; } - if(bau15(p, args, 2)) - SubserverSystem.sendToBau15(p, worldOwner.getUuid()); - else - SubserverSystem.sendToBauServer(p, worldOwner.getUuid()); + (bau15(p, args, 2) ? new ServerStarter().build15(worldOwner.getUuid()) : new ServerStarter().build12(worldOwner.getUuid())).send(p).start(); } private static boolean bau15(ProxiedPlayer p, String[] args, int pos){ @@ -259,40 +253,8 @@ public class BauCommand extends BasicCommand { }); } - private static boolean startingBau(ProxiedPlayer p) { - for (Subserver subserver : Subserver.getServerList()) { - if (subserver.getType() == Servertype.BAUSERVER && ((Bauserver) subserver).getOwner().equals(p.getUniqueId()) && !subserver.hasStarted()) { - Message.send("BAU_START_ALREADY", p); - return true; - } - } - return false; - } - - public static boolean stopBauserver(ProxiedPlayer p){ - if(startingBau(p)) - return false; - - for (Subserver subserver : Subserver.getServerList()) { - if (subserver.getType() == Servertype.BAUSERVER && ((Bauserver) subserver).getOwner().equals(p.getUniqueId()) && subserver.hasStarted()) { - subserver.stop(); - try { - Thread.sleep(200); // Wait until possible testarena-World has been deleted - } catch (InterruptedException e) { - throw new SecurityException("Subserver stop interrupted", e); - } - break; - } - } - - return !startingBau(p); - } - private static void testarena(ProxiedPlayer p, String[] args){ - FightCommand.createArena(p, "/bau testarena ", args, 1, false, (player, mode, map) -> ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> { - if(stopBauserver(p)) - SubserverSystem.startTestServer(p, mode, map, 0, 0); - })); + FightCommand.createArena(p, "/bau testarena ", args, 1, false, (player, mode, map) -> ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> new ServerStarter().test(mode, map, p).start())); } private static BauweltMember member(ProxiedPlayer p, SteamwarUser member){ diff --git a/src/de/steamwar/bungeecore/commands/ChallengeCommand.java b/src/de/steamwar/bungeecore/commands/ChallengeCommand.java index 27d9ba7..7f480c1 100644 --- a/src/de/steamwar/bungeecore/commands/ChallengeCommand.java +++ b/src/de/steamwar/bungeecore/commands/ChallengeCommand.java @@ -76,11 +76,7 @@ public class ChallengeCommand extends BasicCommand { challenges.remove(target); challenges.remove(player); - Subserver arena = SubserverSystem.startArena(mode, map, 0, 0, 0, 0, null, null, player.getUniqueId(), target.getUniqueId()); - - SubserverSystem.sendPlayer(arena, player); - SubserverSystem.sendPlayer(arena, target); - + Subserver arena = new ServerStarter().arena(mode, map).blueLeader(player).redLeader(target).start(); Message.broadcast("CHALLENGE_BROADCAST", "CHALLENGE_BROADCAST_HOVER", new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/arena " + arena.getServer().getName()), mode.getDisplayName(), player.getName(), target.getName()); }else{ diff --git a/src/de/steamwar/bungeecore/commands/CheckCommand.java b/src/de/steamwar/bungeecore/commands/CheckCommand.java index a74dc78..b65b1cc 100644 --- a/src/de/steamwar/bungeecore/commands/CheckCommand.java +++ b/src/de/steamwar/bungeecore/commands/CheckCommand.java @@ -228,13 +228,12 @@ public class CheckCommand extends BasicCommand { this.checkList = checkQuestions.get(schematic.getSchemtype()).listIterator(); ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> { - if(!BauCommand.stopBauserver(checker)){ + ArenaMode mode = ArenaMode.getBySchemType(schematic.getSchemtype().fightType()); + if(new ServerStarter().test(mode, mode.getRandomMap(), checker).check(schematic.getId()).start() == null) { remove(); return; } - ArenaMode mode = ArenaMode.getBySchemType(schematic.getSchemtype().fightType()); - SubserverSystem.startTestServer(checker, mode, FightCommand.getMap(checker, mode, "Random"), schematic.getId(), 0); currentCheckers.put(checker.getUniqueId(), this); currentSchems.put(schematic.getId(), this); for(CheckedSchematic previous : CheckedSchematic.previousChecks(schematic)) diff --git a/src/de/steamwar/bungeecore/commands/FightCommand.java b/src/de/steamwar/bungeecore/commands/FightCommand.java index 1d2e396..736d78d 100644 --- a/src/de/steamwar/bungeecore/commands/FightCommand.java +++ b/src/de/steamwar/bungeecore/commands/FightCommand.java @@ -164,8 +164,7 @@ public class FightCommand extends BasicCommand { @Override public void execute(CommandSender sender, String[] args) { createArena(sender, "/fight ", args, 0, false, (player, mode, map) -> { - Subserver arena = SubserverSystem.startArena(mode, map, 0, 0, 0, 0, null, null, player.getUniqueId(), null); - SubserverSystem.sendPlayer(arena, player); + Subserver arena = new ServerStarter().arena(mode, map).blueLeader(player).start(); Message.broadcast("FIGHT_BROADCAST", "FIGHT_BROADCAST_HOVER" , new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/arena " + arena.getServer().getName()), mode.getDisplayName(), player.getName()); }); diff --git a/src/de/steamwar/bungeecore/commands/HistoricCommand.java b/src/de/steamwar/bungeecore/commands/HistoricCommand.java index 6c9c070..f07a6a3 100644 --- a/src/de/steamwar/bungeecore/commands/HistoricCommand.java +++ b/src/de/steamwar/bungeecore/commands/HistoricCommand.java @@ -19,10 +19,7 @@ package de.steamwar.bungeecore.commands; -import de.steamwar.bungeecore.ArenaMode; -import de.steamwar.bungeecore.Message; -import de.steamwar.bungeecore.Subserver; -import de.steamwar.bungeecore.SubserverSystem; +import de.steamwar.bungeecore.*; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.chat.ClickEvent; @@ -36,8 +33,7 @@ public class HistoricCommand extends BasicCommand { @Override public void execute(CommandSender sender, String[] args) { FightCommand.createArena(sender, "/historic ", args, 0, true, (player, mode, map) -> { - Subserver arena = SubserverSystem.startArena(mode, map, 0, 0, 0, 0, null, null, player.getUniqueId(), null); - SubserverSystem.sendPlayer(arena, player); + Subserver arena = new ServerStarter().arena(mode, map).blueLeader(player).start(); Message.broadcast("HISTORIC_BROADCAST", "HISTORIC_BROADCAST_HOVER" , new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/arena " + arena.getServer().getName()), mode.getDisplayName(), player.getName()); }); diff --git a/src/de/steamwar/bungeecore/commands/ReplayCommand.java b/src/de/steamwar/bungeecore/commands/ReplayCommand.java index 9ca94b4..9ff3876 100644 --- a/src/de/steamwar/bungeecore/commands/ReplayCommand.java +++ b/src/de/steamwar/bungeecore/commands/ReplayCommand.java @@ -19,9 +19,7 @@ package de.steamwar.bungeecore.commands; -import de.steamwar.bungeecore.ArenaMode; -import de.steamwar.bungeecore.Message; -import de.steamwar.bungeecore.SubserverSystem; +import de.steamwar.bungeecore.*; import de.steamwar.bungeecore.inventory.SWItem; import de.steamwar.bungeecore.inventory.SWListInv; import de.steamwar.bungeecore.inventory.SWStreamInv; @@ -49,16 +47,16 @@ public class ReplayCommand extends BasicCommand { new SWStreamInv<>(player, Message.parse("REPLAY_TITLE", player), (click, fight) -> { SteamwarUser user = SteamwarUser.get(player.getUniqueId()); - boolean adminReplay = false; + ArenaMode mode = fight.getGameMode(); + ServerStarter starter = new ServerStarter().replay(fight.getFightID()).blueLeader(player); + if (user.getUserGroup().isAdminGroup() && click.isShiftClick() && fight.replayExists()) { - adminReplay = true; + starter.test(mode, mode.getRandomMap(), player).start(); } else if(!fight.replayAllowed()) { Message.send("REPLAY_UNAVAILABLE", player); - return; + } else { + starter.arena(mode, mode.getRandomMap()).start(); } - ArenaMode mode = fight.getGameMode(); - - SubserverSystem.sendPlayer(SubserverSystem.startArena(mode, mode.getRandomMap(), adminReplay ? -1 : 0, 0, 0, fight.getFightID(), null, null, null, null), player); }, page -> Fight.getPage(page, 45).stream().map(fight -> new SWListInv.SWListEntry<>(getFightItem(player, fight), fight)).collect(Collectors.toList())).open(); } diff --git a/src/de/steamwar/bungeecore/commands/TutorialCommand.java b/src/de/steamwar/bungeecore/commands/TutorialCommand.java index 253d889..3a5b07c 100644 --- a/src/de/steamwar/bungeecore/commands/TutorialCommand.java +++ b/src/de/steamwar/bungeecore/commands/TutorialCommand.java @@ -19,16 +19,20 @@ package de.steamwar.bungeecore.commands; -import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.*; import de.steamwar.bungeecore.inventory.SWItem; import de.steamwar.bungeecore.inventory.SWListInv; import de.steamwar.bungeecore.inventory.SWStreamInv; +import de.steamwar.bungeecore.sql.SteamwarUser; import de.steamwar.bungeecore.sql.Tutorial; import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.connection.ProxiedPlayer; +import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.logging.Level; import java.util.stream.Collectors; public class TutorialCommand extends BasicCommand { @@ -43,12 +47,47 @@ public class TutorialCommand extends BasicCommand { return; ProxiedPlayer player = (ProxiedPlayer) sender; - //TODO: Tutorial rating - //TODO: Tutorial creation + if(args.length != 0) { + switch(args[0]) { + case "rate": + if(args.length < 2) { + BungeeCore.get().getLogger().log(Level.SEVERE, "rate executed with missing argument"); + return; + } - new SWStreamInv<>(player, Message.parse("TUTORIAL_TITLE", player), (click, tutorial) -> { - //TODO: Tutorial start - }, page -> Tutorial.getPage(page, 45).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(player, tutorial), tutorial)).collect(Collectors.toList())).open(); + int id; + try { + id = Integer.parseInt(args[1]); + } catch (NumberFormatException e) { + BungeeCore.get().getLogger().log(Level.SEVERE, "rate executed with non number: " + args[1]); + return; + } + + Tutorial tutorial = Tutorial.get(id); + if(tutorial == null) { + BungeeCore.get().getLogger().log(Level.SEVERE, "rate executed with nonexistent id: " + id); + return; + } + + rate(player, tutorial); + break; + case "create": + if(args.length < 3) { + Message.send("TUTORIAL_CREATE_HELP", player); + return; + } + + String material = args[1].toUpperCase(); + String name = Arrays.stream(args).skip(2).collect(Collectors.joining(" ")); + create(player, name, material); + break; + default: + Message.send("TUTORIAL_CREATE_HELP", player); + } + return; + } + + new SWStreamInv<>(player, Message.parse("TUTORIAL_TITLE", player), (click, tutorial) -> new ServerStarter().tutorial(player, tutorial).start(), page -> Tutorial.getPage(page, 45).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(player, tutorial), tutorial)).collect(Collectors.toList())).open(); } private SWItem getTutorialItem(ProxiedPlayer player, Tutorial tutorial) { @@ -56,12 +95,44 @@ public class TutorialCommand extends BasicCommand { List lore = new ArrayList<>(); lore.add(Message.parse("TUTORIAL_BY", player, tutorial.creator().getUserName())); - lore.add(""); - lore.add(Message.parse("TUTORIAL_BASED_ON", player)); - lore.add(Message.parse("TUTORIAL_NAME", player, tutorial.parent().name())); - lore.add(Message.parse("TUTORIAL_BY", player, tutorial.parent().creator().getUserName())); item.setLore(lore); return item; } + + private void rate(ProxiedPlayer player, Tutorial tutorial) { + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + int[] rates = new int[]{1, 2, 3, 4, 5}; + + new SWListInv<>(player, Message.parse("TUTORIAL_RATE_TITLE", player), Arrays.stream(rates).mapToObj(rate -> new SWListInv.SWListEntry<>(new SWItem("NETHER_STAR", Message.parse("TUTORIAL_RATE", player, rate)), rate)).collect(Collectors.toList()), (click, rate) -> { + tutorial.rate(user, rate); + }).open(); + } + + private void create(ProxiedPlayer player, String name, String item) { + Subserver subserver = Subserver.getSubserver(player); + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + File tempWorld = new File(ServerStarter.TEMP_WORLD_PATH, ServerStarter.serverToWorldName(ServerStarter.bauServerName(user))); + + if(subserver == null || !subserver.hasStarted() || subserver.getType() != Servertype.BAUSERVER || !tempWorld.exists()) { + Message.send("TUTORIAL_CREATE_MISSING", player); + return; + } + + subserver.execute("save-all"); + try { + Thread.sleep(500); + } catch (InterruptedException e) { + BungeeCore.get().getLogger().log(Level.WARNING, "Tutorial creation interrupted", e); + Thread.currentThread().interrupt(); + } + + Tutorial tutorial = Tutorial.create(user, name, item); + File tutorialWorld = new File(ServerStarter.TUTORIAL_PATH, String.valueOf(tutorial.id())); + + if (tutorialWorld.exists()) + SubserverSystem.deleteFolder(Node.local, tutorialWorld.getPath()); + ServerStarter.copyWorld(Node.local, tempWorld.getPath(), tutorialWorld.getPath()); + Message.send("TUTORIAL_CREATED", player); + } } diff --git a/src/de/steamwar/bungeecore/comms/handlers/PrepareSchemHandler.java b/src/de/steamwar/bungeecore/comms/handlers/PrepareSchemHandler.java index 14171c5..d968178 100644 --- a/src/de/steamwar/bungeecore/comms/handlers/PrepareSchemHandler.java +++ b/src/de/steamwar/bungeecore/comms/handlers/PrepareSchemHandler.java @@ -21,8 +21,7 @@ package de.steamwar.bungeecore.comms.handlers; import com.google.common.io.ByteArrayDataInput; import de.steamwar.bungeecore.ArenaMode; -import de.steamwar.bungeecore.SubserverSystem; -import de.steamwar.bungeecore.commands.BauCommand; +import de.steamwar.bungeecore.ServerStarter; import de.steamwar.bungeecore.comms.SpigotHandler; import de.steamwar.bungeecore.sql.SchematicType; import de.steamwar.bungeecore.sql.SteamwarUser; @@ -37,7 +36,6 @@ public class PrepareSchemHandler implements SpigotHandler { int schematicID = in.readInt(); ArenaMode mode = ArenaMode.getBySchemType(SchematicType.fromDB(in.readUTF())); - BauCommand.stopBauserver(player); - SubserverSystem.startTestServer(player, mode, mode.getRandomMap(), 0, schematicID); + new ServerStarter().test(mode, mode.getRandomMap(), player).prepare(schematicID).start(); } } diff --git a/src/de/steamwar/bungeecore/sql/Tutorial.java b/src/de/steamwar/bungeecore/sql/Tutorial.java index f9b49f1..8249d47 100644 --- a/src/de/steamwar/bungeecore/sql/Tutorial.java +++ b/src/de/steamwar/bungeecore/sql/Tutorial.java @@ -24,13 +24,14 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; -import java.util.stream.Stream; public class Tutorial { - private static final Statement by_popularity = new Statement("SELECT t.TutorialID, t.Creator, t.Name, t.Item, AVG(r.Stars) AS Stars, p.TutorialID AS ParentID, p.Creator AS ParentCreator, p.Name AS ParentName FROM Tutorial t INNER JOIN Tutorial p ON t.Parent = p.TutorialID LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?"); + private static final Statement by_popularity = new Statement("SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?"); + private static final Statement by_creator_name = new Statement("SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Creator = ? AND t.Name = ? GROUP BY t.TutorialID"); + private static final Statement by_id = new Statement("SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.TutorialID = ? GROUP BY t.TutorialID"); private static final Statement rate = new Statement("INSERT INTO TutorialRating (TutorialID, UserID, Stars) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Stars = VALUES(Stars)"); - private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item, Parent) VALUES (?, ?, ?, ?)"); + private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item)"); public static List getPage(int page, int elementsPerPage) { List tutorials = by_popularity.select(rs -> { @@ -40,24 +41,34 @@ public class Tutorial { return t; }, page * elementsPerPage, elementsPerPage); - SteamwarUser.batchCache(tutorials.stream().flatMap(tutorial -> Stream.of(tutorial.creator, tutorial.parent.creator)).collect(Collectors.toSet())); + SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet())); return tutorials; } - public static void create(SteamwarUser creator, String name, Tutorial parent) { - create.update(creator.getId(), name, parent.id); + public static Tutorial create(SteamwarUser creator, String name, String item) { + create.update(creator.getId(), name, item); + return by_creator_name.select(rs -> { + rs.next(); + return new Tutorial(rs); + }, creator.getId(), name); + } + + public static Tutorial get(int id) { + return by_id.select(rs -> { + if(rs.next()) + return new Tutorial(rs); + return null; + }, id); } private final int id; private final int creator; private final String name; private final String item; - private Tutorial parent; private final int stars; public Tutorial(ResultSet rs) throws SQLException { this(rs.getInt("TutorialID"), rs.getInt("Creator"), rs.getString("Name"), rs.getString("Item"), rs.getInt("Stars")); - parent = new Tutorial(rs.getInt("ParentID"), rs.getInt("ParentCreator"), rs.getString("ParentName"), "", 0); } private Tutorial(int id, int creator, String name, String item, int stars) { @@ -72,10 +83,6 @@ public class Tutorial { return SteamwarUser.get(creator); } - public Tutorial parent() { - return parent; - } - public int stars() { return stars; } diff --git a/src/de/steamwar/messages/BungeeCore.properties b/src/de/steamwar/messages/BungeeCore.properties index 60b69c3..016aaf0 100644 --- a/src/de/steamwar/messages/BungeeCore.properties +++ b/src/de/steamwar/messages/BungeeCore.properties @@ -337,7 +337,11 @@ REPLAY_SERVER=§7{0} TUTORIAL_TITLE=Tutorials TUTORIAL_NAME=§e{0} TUTORIAL_BY=§8von §7{0} -TUTORIAL_BASED_ON=§8Basierend auf +TUTORIAL_RATE_TITLE=Tutorial bewerten +TUTORIAL_RATE=§e{0} §7Stern(e) +TUTORIAL_CREATE_HELP=§8/§7tutorial create §8[§eMaterial§8] §8[§eName§8] +TUTORIAL_CREATE_MISSING=§cEin Tutorial kann nur von einem Tutorialserver aus erstellt werden! +TUTORIAL_CREATED=§7Das Tutorial wurde erstellt§8. #ServerTeamchatCommand STC_USAGE=§8/§7stc §8[§eNachricht an das Team§8]