SteamWar/BungeeCore
Archiviert
13
2

Checkpoint support #506

Zusammengeführt
Lixfel hat 2 Commits von checkpoint nach master 2024-01-18 01:23:11 +01:00 zusammengeführt
Nur Änderungen aus Commit 510fed73d3 werden angezeigt - Alle Commits anzeigen

Datei anzeigen

@ -1,12 +1,14 @@
package de.steamwar.bungeecore;
import de.steamwar.messages.ChatSender;
import de.steamwar.sql.EventFight;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.Team;
import de.steamwar.sql.Tutorial;
import de.steamwar.messages.ChatSender;
import lombok.Getter;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
@ -14,6 +16,7 @@ import java.nio.file.Files;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -46,7 +49,9 @@ public class ServerStarter {
private boolean allowMerge = false;
private String fightMap = null;
private String gameMode = null;
private ServerConstructor constructor = (serverName, port, builder, shutdownCallback) -> new Arenaserver(serverName, gameMode, fightMap, allowMerge, port, builder, shutdownCallback);
private boolean checkpoint = false;
private ServerConstructor constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Arenaserver(serverName, gameMode, fightMap, allowMerge, port, builder, shutdownCallback);
private Consumer<Subserver> callback = subserver -> {};
private final Set<ProxiedPlayer> playersToSend = new HashSet<>();
private final Map<String, String> arguments = new HashMap<>();
@ -117,6 +122,7 @@ public class ServerStarter {
serverJar = version.getServerJar();
worldDir = version.getWorldFolder(WORLDS_BASE_PATH);
worldName = version != Version.SPIGOT_12 ? String.valueOf(SteamwarUser.get(owner).getId()) : owner.toString();
checkpoint = true;
build(owner);
@ -128,12 +134,11 @@ public class ServerStarter {
// 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;
}
Bauserver subserver = Bauserver.get(owner);
if(subserver != null) {
for(ProxiedPlayer p : playersToSend)
SubserverSystem.sendPlayer(subserver, p);
return false;
}
return true;
};
@ -163,19 +168,16 @@ public class ServerStarter {
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;
}
}
Bauserver subserver = Bauserver.get(owner.getUniqueId());
if(subserver != null && subserver.isStarted())
subserver.stop();
return !startingBau(owner);
};
}
private void build(UUID owner) {
constructor = (serverName, port, builder, shutdownCallback) -> new Bauserver(serverName, owner, port, builder, shutdownCallback);
constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Bauserver(serverName, owner, port, builder, shutdownCallback, failureCallback);
serverNameProvider = port -> bauServerName(SteamwarUser.get(owner));
}
@ -185,16 +187,16 @@ public class ServerStarter {
worldDir = version.getWorldFolder(BUILDER_BASE_PATH);
worldName = map;
serverNameProvider = port -> "" + map;
constructor = (serverName, port, builder, shutdownCallback) -> new Builderserver(serverName, worldName, port, builder, shutdownCallback);
checkpoint = true;
constructor = (serverName, port, builder, shutdownCallback, failureCallback) -> new Builderserver(serverName, worldName, port, builder, shutdownCallback, failureCallback);
// Send players to existing server
startCondition = () -> {
for(Subserver subserver : Subserver.getServerList()) {
if(subserver.getType() == Servertype.BUILDER && ((Builderserver)subserver).getMap().equals(worldName)) {
for(ProxiedPlayer p : playersToSend)
SubserverSystem.sendPlayer(subserver, p);
return false;
}
Builderserver subserver = Builderserver.get(worldName);
if(subserver != null) {
for(ProxiedPlayer p : playersToSend)
SubserverSystem.sendPlayer(subserver, p);
return false;
}
return true;
};
@ -218,9 +220,14 @@ public class ServerStarter {
return this;
}
public Subserver start() {
public ServerStarter callback(Consumer<Subserver> callback) {
this.callback = callback;
return this;
}
public boolean start() {
if(!startCondition.getAsBoolean())
return null;
return false;
int port = portrange.freePort();
String serverName = serverNameProvider.apply(port);
@ -231,7 +238,7 @@ public class ServerStarter {
for (ProxiedPlayer p : playersToSend)
ChatSender.of(p).system("SERVER_START_OVERLOAD");
return null;
return false;
}
}
if(worldName == null)
@ -240,22 +247,45 @@ public class ServerStarter {
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);
File checkpointDir = new File("/tmp/" + System.getProperty("user.name") + ".checkpoints/" + directory.getName() + "/" + worldName);
if(checkpoint)
arguments.put("checkpoint", checkpointDir.getPath());
if(checkpoint && checkpointDir.exists()) {
try {
new DataOutputStream(Files.newOutputStream(new File(checkpointDir, "port").toPath())).writeInt(port);
} catch (IOException e) {
throw new SecurityException(e);
}
postStart(constructor.construct(serverName, port, node.prepareExecution(
"criu", "restore", "-D", checkpointDir.getPath(), "--auto-dedup", "--shell-job", "-v"
), worldCleanup, e -> regularStart(serverName, port)));
} else {
regularStart(serverName, port);
}
return true;
}
private void regularStart(String serverName, int port) {
postStart(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, null));
}
private void postStart(Subserver subserver) {
for(ProxiedPlayer p : playersToSend)
SubserverSystem.sendPlayer(subserver, p);
return subserver;
callback.accept(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;
}
Bauserver subserver = Bauserver.get(p.getUniqueId());
if(subserver != null && !subserver.isStarted()) {
ChatSender.of(p).system("BAU_START_ALREADY");
return true;
}
return false;
}
@ -273,7 +303,7 @@ public class ServerStarter {
}
private interface ServerConstructor {
Subserver construct(String serverName, int port, ProcessBuilder builder, Runnable shutdownCallback);
Subserver construct(String serverName, int port, ProcessBuilder builder, Runnable shutdownCallback, Consumer<Exception> failureCallback);
}
private static class Portrange {
@ -312,6 +342,7 @@ public class ServerStarter {
}
}
@Getter
public enum Version {
SPIGOT_12("spigot-1.12.2.jar", 12),
SPIGOT_15("spigot-1.15.2.jar", 15),
@ -326,14 +357,6 @@ public class ServerStarter {
this.versionSuffix = versionSuffix;
}
public String getServerJar() {
return serverJar;
}
public int getVersionSuffix() {
return versionSuffix;
}
public String getWorldFolder(String base) {
return base + versionSuffix + "/";
}