SteamWar/BungeeCore
Archiviert
13
2

Merge pull request 'Server start refactoring, Tutorial system' (#317) from tutorial into master
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Reviewed-on: #317
Reviewed-by: YoyoNow <jwsteam@nidido.de>
Dieser Commit ist enthalten in:
Lixfel 2022-03-22 09:28:15 +01:00
Commit 95ed6925da
15 geänderte Dateien mit 632 neuen und 269 gelöschten Zeilen

Datei anzeigen

@ -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{

Datei anzeigen

@ -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);

Datei anzeigen

@ -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<Integer, String> 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<ProxiedPlayer> playersToSend = new HashSet<>();
private final Map<String, String> 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, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new)
), 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<Integer> 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;
}
}
}

Datei anzeigen

@ -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<Integer> 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;
}
}
}

Datei anzeigen

@ -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){

Datei anzeigen

@ -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{

Datei anzeigen

@ -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))

Datei anzeigen

@ -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());
});

Datei anzeigen

@ -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());
});

Datei anzeigen

@ -1,8 +1,25 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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;
@ -30,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();
}

Datei anzeigen

@ -0,0 +1,173 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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;
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 {
public TutorialCommand() {
super("tutorial", null);
}
@Override
public void execute(CommandSender sender, String[] args) {
if(!(sender instanceof ProxiedPlayer))
return;
ProxiedPlayer player = (ProxiedPlayer) sender;
if(args.length != 0) {
switch(args[0].toLowerCase()) {
case "rate":
if(args.length < 2) {
BungeeCore.get().getLogger().log(Level.SEVERE, "rate executed with missing argument");
return;
}
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;
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;
}
openInventory(player, true, false);
}
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<String> 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;
}
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);
SWInventory.close(player);
}).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(1000);
} 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);
}
}

Datei anzeigen

@ -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();
}
}

Datei anzeigen

@ -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);
}

Datei anzeigen

@ -0,0 +1,122 @@
/*
* 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 <https://www.gnu.org/licenses/>.
*/
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;
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 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), Released = 0");
private static final Statement release = new Statement("UPDATE Tutorial SET Released = 1 WHERE TutorialID = ?");
public static List<Tutorial> getPage(int page, int elementsPerPage, boolean released) {
List<Tutorial> tutorials = by_popularity.select(rs -> {
List<Tutorial> t = new ArrayList<>();
while(rs.next())
t.add(new Tutorial(rs));
return t;
}, released, page * elementsPerPage, elementsPerPage);
SteamwarUser.batchCache(tutorials.stream().map(tutorial -> tutorial.creator).collect(Collectors.toSet()));
return tutorials;
}
public static List<Tutorial> getOwn(SteamwarUser user, int page, int elementsPerPage) {
return own.select(rs -> {
List<Tutorial> 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 -> {
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 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");
}
public SteamwarUser creator() {
return SteamwarUser.get(creator);
}
public double stars() {
return stars;
}
public int id() {
return id;
}
public String name() {
return name;
}
public String item() {
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);
}
}

Datei anzeigen

@ -333,6 +333,18 @@ 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_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]
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]
STC_FORMAT=§8STC §e{0}» §r{1}