From 87dbca480e158fc3dc20bae1f492c500a670a58a Mon Sep 17 00:00:00 2001 From: Lixfel Date: Wed, 16 Mar 2022 12:32:52 +0100 Subject: [PATCH 1/4] Tutorial first steps Signed-off-by: Lixfel --- .../bungeecore/commands/ReplayCommand.java | 19 ++++ .../bungeecore/commands/TutorialCommand.java | 67 +++++++++++++ src/de/steamwar/bungeecore/sql/Tutorial.java | 98 +++++++++++++++++++ .../steamwar/messages/BungeeCore.properties | 6 ++ 4 files changed, 190 insertions(+) create mode 100644 src/de/steamwar/bungeecore/commands/TutorialCommand.java create mode 100644 src/de/steamwar/bungeecore/sql/Tutorial.java diff --git a/src/de/steamwar/bungeecore/commands/ReplayCommand.java b/src/de/steamwar/bungeecore/commands/ReplayCommand.java index a999d721..9ca94b4c 100644 --- a/src/de/steamwar/bungeecore/commands/ReplayCommand.java +++ b/src/de/steamwar/bungeecore/commands/ReplayCommand.java @@ -1,3 +1,22 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + package de.steamwar.bungeecore.commands; import de.steamwar.bungeecore.ArenaMode; diff --git a/src/de/steamwar/bungeecore/commands/TutorialCommand.java b/src/de/steamwar/bungeecore/commands/TutorialCommand.java new file mode 100644 index 00000000..253d8890 --- /dev/null +++ b/src/de/steamwar/bungeecore/commands/TutorialCommand.java @@ -0,0 +1,67 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.commands; + +import de.steamwar.bungeecore.Message; +import de.steamwar.bungeecore.inventory.SWItem; +import de.steamwar.bungeecore.inventory.SWListInv; +import de.steamwar.bungeecore.inventory.SWStreamInv; +import de.steamwar.bungeecore.sql.Tutorial; +import net.md_5.bungee.api.CommandSender; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public class TutorialCommand extends BasicCommand { + + public TutorialCommand() { + super("tutorial", null); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if(!(sender instanceof ProxiedPlayer)) + return; + ProxiedPlayer player = (ProxiedPlayer) sender; + + //TODO: Tutorial rating + //TODO: Tutorial creation + + 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(); + } + + private SWItem getTutorialItem(ProxiedPlayer player, Tutorial tutorial) { + SWItem item = new SWItem(tutorial.item(), Message.parse("TUTORIAL_NAME", player, tutorial.name())); + + 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; + } +} diff --git a/src/de/steamwar/bungeecore/sql/Tutorial.java b/src/de/steamwar/bungeecore/sql/Tutorial.java new file mode 100644 index 00000000..f9b49f15 --- /dev/null +++ b/src/de/steamwar/bungeecore/sql/Tutorial.java @@ -0,0 +1,98 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2022 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.bungeecore.sql; + +import java.sql.ResultSet; +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 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 (?, ?, ?, ?)"); + + public static List getPage(int page, int elementsPerPage) { + List tutorials = by_popularity.select(rs -> { + List t = new ArrayList<>(); + while(rs.next()) + t.add(new Tutorial(rs)); + return t; + }, page * elementsPerPage, elementsPerPage); + + SteamwarUser.batchCache(tutorials.stream().flatMap(tutorial -> Stream.of(tutorial.creator, tutorial.parent.creator)).collect(Collectors.toSet())); + return tutorials; + } + + public static void create(SteamwarUser creator, String name, Tutorial parent) { + create.update(creator.getId(), name, parent.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) { + this.id = id; + this.creator = creator; + this.name = name; + this.item = item; + this.stars = stars; + } + + public SteamwarUser creator() { + return SteamwarUser.get(creator); + } + + public Tutorial parent() { + return parent; + } + + public int stars() { + return stars; + } + + public int id() { + return id; + } + + public String name() { + return name; + } + + public String item() { + return item; + } + + public void rate(SteamwarUser user, int rating) { + rate.update(id, user.getId(), rating); + } +} diff --git a/src/de/steamwar/messages/BungeeCore.properties b/src/de/steamwar/messages/BungeeCore.properties index e7116508..60b69c35 100644 --- a/src/de/steamwar/messages/BungeeCore.properties +++ b/src/de/steamwar/messages/BungeeCore.properties @@ -333,6 +333,12 @@ REPLAY_LOSER=§e{0} §7+§e{1} REPLAY_TIME=§7{0} REPLAY_SERVER=§7{0} +#TutorialCommand +TUTORIAL_TITLE=Tutorials +TUTORIAL_NAME=§e{0} +TUTORIAL_BY=§8von §7{0} +TUTORIAL_BASED_ON=§8Basierend auf + #ServerTeamchatCommand STC_USAGE=§8/§7stc §8[§eNachricht an das Team§8] STC_FORMAT=§8STC §e{0}» §r{1} From 908e54fedd364cbd244b6a6a0e4d3a1e54bc93a0 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 19 Mar 2022 16:10:09 +0100 Subject: [PATCH 2/4] 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 5fdbecfc..846dd5c9 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 e0e29af9..98d75e39 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 00000000..39c1693f --- /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 b0085f07..2908acb1 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 cc9b8ef6..5a58a738 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 27d9ba73..7f480c1b 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 a74dc788..b65b1cc4 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 1d2e396f..736d78dc 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 6c9c0709..f07a6a3e 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 9ca94b4c..9ff3876f 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 253d8890..3a5b07c4 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 14171c57..d9681781 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 f9b49f15..8249d479 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 60b69c35..016aaf03 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] From e2fd1754ce5639efd8ca5e33d4555eb463320d0e Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sun, 20 Mar 2022 19:08:55 +0100 Subject: [PATCH 3/4] Fix some bugs + minor improvements Signed-off-by: Lixfel --- src/de/steamwar/bungeecore/ServerStarter.java | 2 +- .../bungeecore/commands/TutorialCommand.java | 5 ++++- .../bungeecore/inventory/SWInventory.java | 4 ++++ src/de/steamwar/bungeecore/sql/Tutorial.java | 18 +++++++----------- src/de/steamwar/messages/BungeeCore.properties | 1 + 5 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/de/steamwar/bungeecore/ServerStarter.java b/src/de/steamwar/bungeecore/ServerStarter.java index 39c1693f..622b7a42 100644 --- a/src/de/steamwar/bungeecore/ServerStarter.java +++ b/src/de/steamwar/bungeecore/ServerStarter.java @@ -199,7 +199,7 @@ public class ServerStarter { 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() + serverJar, directory, worldDir, worldName, port, xmx, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new) ), worldCleanup); for(ProxiedPlayer p : playersToSend) diff --git a/src/de/steamwar/bungeecore/commands/TutorialCommand.java b/src/de/steamwar/bungeecore/commands/TutorialCommand.java index 3a5b07c4..340a0fdd 100644 --- a/src/de/steamwar/bungeecore/commands/TutorialCommand.java +++ b/src/de/steamwar/bungeecore/commands/TutorialCommand.java @@ -20,6 +20,7 @@ package de.steamwar.bungeecore.commands; import de.steamwar.bungeecore.*; +import de.steamwar.bungeecore.inventory.SWInventory; import de.steamwar.bungeecore.inventory.SWItem; import de.steamwar.bungeecore.inventory.SWListInv; import de.steamwar.bungeecore.inventory.SWStreamInv; @@ -95,6 +96,7 @@ public class TutorialCommand extends BasicCommand { List lore = new ArrayList<>(); lore.add(Message.parse("TUTORIAL_BY", player, tutorial.creator().getUserName())); + lore.add(Message.parse("TUTORIAL_STARS", player, tutorial.stars())); item.setLore(lore); return item; @@ -106,6 +108,7 @@ public class TutorialCommand extends BasicCommand { 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); + SWInventory.close(player); }).open(); } @@ -121,7 +124,7 @@ public class TutorialCommand extends BasicCommand { subserver.execute("save-all"); try { - Thread.sleep(500); + Thread.sleep(1000); } catch (InterruptedException e) { BungeeCore.get().getLogger().log(Level.WARNING, "Tutorial creation interrupted", e); Thread.currentThread().interrupt(); diff --git a/src/de/steamwar/bungeecore/inventory/SWInventory.java b/src/de/steamwar/bungeecore/inventory/SWInventory.java index 31cb89ed..b827e884 100644 --- a/src/de/steamwar/bungeecore/inventory/SWInventory.java +++ b/src/de/steamwar/bungeecore/inventory/SWInventory.java @@ -116,6 +116,10 @@ public class SWInventory { } public void close() { + close(player); + } + + public static void close(ProxiedPlayer player) { new CloseInventoryPacket(SteamwarUser.get(player).getId()).send(player); } diff --git a/src/de/steamwar/bungeecore/sql/Tutorial.java b/src/de/steamwar/bungeecore/sql/Tutorial.java index 8249d479..92272825 100644 --- a/src/de/steamwar/bungeecore/sql/Tutorial.java +++ b/src/de/steamwar/bungeecore/sql/Tutorial.java @@ -65,25 +65,21 @@ public class Tutorial { private final int creator; private final String name; private final String item; - private final int stars; + private final double stars; public Tutorial(ResultSet rs) throws SQLException { - this(rs.getInt("TutorialID"), rs.getInt("Creator"), rs.getString("Name"), rs.getString("Item"), rs.getInt("Stars")); - } - - private Tutorial(int id, int creator, String name, String item, int stars) { - this.id = id; - this.creator = creator; - this.name = name; - this.item = item; - this.stars = stars; + this.id = rs.getInt("TutorialID"); + this.creator = rs.getInt("Creator"); + this.name = rs.getString("Name"); + this.item = rs.getString("Item"); + this.stars = rs.getDouble("Stars"); } public SteamwarUser creator() { return SteamwarUser.get(creator); } - public int stars() { + public double stars() { return stars; } diff --git a/src/de/steamwar/messages/BungeeCore.properties b/src/de/steamwar/messages/BungeeCore.properties index 016aaf03..ff51762a 100644 --- a/src/de/steamwar/messages/BungeeCore.properties +++ b/src/de/steamwar/messages/BungeeCore.properties @@ -337,6 +337,7 @@ REPLAY_SERVER=§7{0} TUTORIAL_TITLE=Tutorials TUTORIAL_NAME=§e{0} TUTORIAL_BY=§8von §7{0} +TUTORIAL_STARS=§e{0} §7Sterne TUTORIAL_RATE_TITLE=Tutorial bewerten TUTORIAL_RATE=§e{0} §7Stern(e) TUTORIAL_CREATE_HELP=§8/§7tutorial create §8[§eMaterial§8] §8[§eName§8] From 364422af2f9722b6f5c6b680bccf3db9b80b5ec5 Mon Sep 17 00:00:00 2001 From: Lixfel Date: Tue, 22 Mar 2022 09:21:15 +0100 Subject: [PATCH 4/4] Tutorial release mechanism Signed-off-by: Lixfel --- .../bungeecore/commands/TutorialCommand.java | 38 +++++++++++++++++-- src/de/steamwar/bungeecore/sql/Tutorial.java | 29 ++++++++++++-- .../steamwar/messages/BungeeCore.properties | 1 + 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/de/steamwar/bungeecore/commands/TutorialCommand.java b/src/de/steamwar/bungeecore/commands/TutorialCommand.java index 340a0fdd..c4d6ee3c 100644 --- a/src/de/steamwar/bungeecore/commands/TutorialCommand.java +++ b/src/de/steamwar/bungeecore/commands/TutorialCommand.java @@ -49,7 +49,7 @@ public class TutorialCommand extends BasicCommand { ProxiedPlayer player = (ProxiedPlayer) sender; if(args.length != 0) { - switch(args[0]) { + switch(args[0].toLowerCase()) { case "rate": if(args.length < 2) { BungeeCore.get().getLogger().log(Level.SEVERE, "rate executed with missing argument"); @@ -82,23 +82,55 @@ public class TutorialCommand extends BasicCommand { String name = Arrays.stream(args).skip(2).collect(Collectors.joining(" ")); create(player, name, material); break; + case "own": + openInventory(player, false, true); + break; + + case "unreleased": + if (SteamwarUser.get(player.getUniqueId()).getUserGroup().isTeamGroup()) { + openInventory(player, false, false); + break; + } default: Message.send("TUTORIAL_CREATE_HELP", player); + Message.send("TUTORIAL_OWN_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(); + openInventory(player, true, false); } - private SWItem getTutorialItem(ProxiedPlayer player, Tutorial tutorial) { + private void openInventory(ProxiedPlayer player, boolean released, boolean own) { + SteamwarUser user = SteamwarUser.get(player.getUniqueId()); + + new SWStreamInv<>( + player, + Message.parse("TUTORIAL_TITLE", player), + (click, tutorial) -> { + if(!released && click.isShiftClick() && user.getUserGroup().isTeamGroup() && user != tutorial.creator()) { + tutorial.release(); + return; + } + + new ServerStarter().tutorial(player, tutorial).start(); + }, + page -> (own ? Tutorial.getOwn(user, page, 45) : Tutorial.getPage(page, 45, released)).stream().map(tutorial -> new SWListInv.SWListEntry<>(getTutorialItem(player, tutorial, own), tutorial)).collect(Collectors.toList()) + ).open(); + } + + private SWItem getTutorialItem(ProxiedPlayer player, Tutorial tutorial, boolean highlightReleased) { SWItem item = new SWItem(tutorial.item(), Message.parse("TUTORIAL_NAME", player, tutorial.name())); + item.setHideAttributes(true); List lore = new ArrayList<>(); lore.add(Message.parse("TUTORIAL_BY", player, tutorial.creator().getUserName())); lore.add(Message.parse("TUTORIAL_STARS", player, tutorial.stars())); item.setLore(lore); + if (highlightReleased && tutorial.released()) + item.setEnchanted(true); + return item; } diff --git a/src/de/steamwar/bungeecore/sql/Tutorial.java b/src/de/steamwar/bungeecore/sql/Tutorial.java index 92272825..4bbe7c43 100644 --- a/src/de/steamwar/bungeecore/sql/Tutorial.java +++ b/src/de/steamwar/bungeecore/sql/Tutorial.java @@ -27,24 +27,35 @@ import java.util.stream.Collectors; public class Tutorial { - 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_popularity = new Statement("SELECT t.*, AVG(r.Stars) AS Stars FROM Tutorial t LEFT OUTER JOIN TutorialRating r ON t.TutorialID = r.TutorialID WHERE t.Released = ? GROUP BY t.TutorialID ORDER BY SUM(r.Stars) DESC LIMIT ?, ?"); + private static final Statement own = 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 = ? GROUP BY t.TutorialID ORDER BY t.TutorialID ASC 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) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item)"); + private static final Statement create = new Statement("INSERT INTO Tutorial (Creator, Name, Item) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE Item = VALUES(Item), Released = 0"); + private static final Statement release = new Statement("UPDATE Tutorial SET Released = 1 WHERE TutorialID = ?"); - public static List getPage(int page, int elementsPerPage) { + public static List getPage(int page, int elementsPerPage, boolean released) { List tutorials = by_popularity.select(rs -> { List t = new ArrayList<>(); while(rs.next()) t.add(new Tutorial(rs)); return t; - }, page * elementsPerPage, elementsPerPage); + }, released, page * elementsPerPage, elementsPerPage); SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet())); return tutorials; } + public static List getOwn(SteamwarUser user, int page, int elementsPerPage) { + return own.select(rs -> { + List t = new ArrayList<>(); + while(rs.next()) + t.add(new Tutorial(rs)); + return t; + }, user.getId(), page * elementsPerPage, elementsPerPage); + } + public static Tutorial create(SteamwarUser creator, String name, String item) { create.update(creator.getId(), name, item); return by_creator_name.select(rs -> { @@ -66,12 +77,14 @@ public class Tutorial { private final String name; private final String item; private final double stars; + private final boolean released; public Tutorial(ResultSet rs) throws SQLException { this.id = rs.getInt("TutorialID"); this.creator = rs.getInt("Creator"); this.name = rs.getString("Name"); this.item = rs.getString("Item"); + this.released = rs.getBoolean("Released"); this.stars = rs.getDouble("Stars"); } @@ -95,6 +108,14 @@ public class Tutorial { return item; } + public boolean released() { + return released; + } + + public void release() { + release.update(id); + } + public void rate(SteamwarUser user, int rating) { rate.update(id, user.getId(), rating); } diff --git a/src/de/steamwar/messages/BungeeCore.properties b/src/de/steamwar/messages/BungeeCore.properties index ff51762a..4d66ebb2 100644 --- a/src/de/steamwar/messages/BungeeCore.properties +++ b/src/de/steamwar/messages/BungeeCore.properties @@ -343,6 +343,7 @@ 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. +TUTORIAL_OWN_HELP=§8/§7tutorial own §8- §7Liste der eigenen Tutorials #ServerTeamchatCommand STC_USAGE=§8/§7stc §8[§eNachricht an das Team§8]