Dieser Commit ist enthalten in:
Ursprung
fe67e5078f
Commit
fc02e77294
26
build.gradle
26
build.gradle
@ -21,19 +21,23 @@ plugins {
|
|||||||
id 'java'
|
id 'java'
|
||||||
id 'application'
|
id 'application'
|
||||||
|
|
||||||
id 'com.github.johnrengelman.shadow' version '5.0.0'
|
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
||||||
id 'de.steamwar.gradle' version 'RELEASE'
|
id 'de.steamwar.gradle' version 'RELEASE'
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'de.steamwar'
|
group 'de.steamwar'
|
||||||
version ''
|
version ''
|
||||||
|
|
||||||
mainClassName = ''
|
|
||||||
|
|
||||||
compileJava.options.encoding = 'UTF-8'
|
compileJava.options.encoding = 'UTF-8'
|
||||||
|
|
||||||
sourceCompatibility = 1.11
|
application {
|
||||||
targetCompatibility = 1.11
|
mainClassName = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
@ -50,6 +54,13 @@ sourceSets {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven {
|
||||||
|
name = 'papermc'
|
||||||
|
url = 'https://repo.papermc.io/repository/maven-public/'
|
||||||
|
}
|
||||||
|
maven {
|
||||||
|
url = 'https://repo.fvdh.dev/releases'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
@ -58,7 +69,10 @@ dependencies {
|
|||||||
annotationProcessor 'org.projectlombok:lombok:1.18.22'
|
annotationProcessor 'org.projectlombok:lombok:1.18.22'
|
||||||
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
|
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
|
||||||
|
|
||||||
compileOnly swdep("waterfall")
|
compileOnly 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT'
|
||||||
|
annotationProcessor 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT'
|
||||||
|
compileOnly 'com.velocitypowered:velocity-proxy:3.3.0-SNAPSHOT'
|
||||||
|
compileOnly 'net.frankheijden.serverutils:ServerUtils:3.5.4'
|
||||||
}
|
}
|
||||||
|
|
||||||
steamwar {
|
steamwar {
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -1,5 +1,5 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
@ -26,4 +26,4 @@ pluginManagement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = 'PersistentBungeeCore'
|
rootProject.name = 'PersistentVelocityCore'
|
||||||
|
@ -15,5 +15,4 @@ public class Arenaserver extends Subserver {
|
|||||||
this.map = map;
|
this.map = map;
|
||||||
this.allowMerge = allowMerge;
|
this.allowMerge = allowMerge;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -19,71 +19,62 @@
|
|||||||
|
|
||||||
package de.steamwar.bungeecore;
|
package de.steamwar.bungeecore;
|
||||||
|
|
||||||
import de.steamwar.persistent.Reflection;
|
import com.google.inject.Inject;
|
||||||
import net.md_5.bungee.api.CommandSender;
|
import com.velocitypowered.api.command.BrigadierCommand;
|
||||||
import de.steamwar.persistent.ModifiedPluginEventBus;
|
import com.velocitypowered.api.event.Subscribe;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
|
||||||
|
import com.velocitypowered.api.event.proxy.ProxyShutdownEvent;
|
||||||
|
import com.velocitypowered.api.plugin.Plugin;
|
||||||
|
import com.velocitypowered.api.proxy.ProxyServer;
|
||||||
import de.steamwar.persistent.PluginUtils;
|
import de.steamwar.persistent.PluginUtils;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import lombok.Getter;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.md_5.bungee.api.plugin.PluginDescription;
|
|
||||||
import net.md_5.bungee.api.plugin.PluginManager;
|
|
||||||
import net.md_5.bungee.event.EventBus;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.util.logging.Logger;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public class Persistent extends Plugin {
|
@Plugin(id = "persistentvelocitycore", name = "PersistentVelocityCore", version = "1.0", description = "PersistentVelocityCore", authors = {"SteamWar"})
|
||||||
|
public class Persistent {
|
||||||
|
|
||||||
public static final String PREFIX = "§eSteam§8War» ";
|
public static final Component PREFIX = Component.text("Steam").color(NamedTextColor.YELLOW)
|
||||||
|
.append(Component.text("War»").color(NamedTextColor.DARK_GRAY))
|
||||||
|
.appendSpace();
|
||||||
|
|
||||||
private static final Reflection.FieldAccessor<EventBus> eventBus = Reflection.getField(PluginManager.class, "eventBus", EventBus.class);
|
@Getter
|
||||||
|
private static Persistent instance;
|
||||||
|
|
||||||
@Override
|
@Inject
|
||||||
public void onLoad() {
|
public Persistent(ProxyServer proxyServer, Logger logger) {
|
||||||
eventBus.set(getProxy().getPluginManager(), new ModifiedPluginEventBus());
|
instance = this;
|
||||||
|
this.proxyServer = proxyServer;
|
||||||
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Getter
|
||||||
public void onEnable(){
|
private final ProxyServer proxyServer;
|
||||||
getProxy().getPluginManager().registerCommand(this, new Command("softreload", "bungeecore.softreload") {
|
|
||||||
@Override
|
@Getter
|
||||||
public void execute(CommandSender sender, String[] args) {
|
private final Logger logger;
|
||||||
softreload();
|
|
||||||
}
|
@Subscribe
|
||||||
});
|
public void onEnable(ProxyInitializeEvent event) {
|
||||||
|
proxyServer.getCommandManager().register(
|
||||||
|
new BrigadierCommand(
|
||||||
|
BrigadierCommand.literalArgumentBuilder("softreload")
|
||||||
|
.requires(commandSource -> commandSource.hasPermission("bungeecore.softreload"))
|
||||||
|
.executes(commandContext -> softreload())
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Subscribe
|
||||||
public void onDisable(){
|
public void onDisable(ProxyShutdownEvent event) {
|
||||||
Subserver.shutdown();
|
Subserver.shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void softreload() {
|
public int softreload() {
|
||||||
Map<String, Command> commandMap = PluginUtils.CommandMap.get(getProxy().getPluginManager());
|
PluginUtils.reloadPlugin();
|
||||||
Map<String, Plugin> plugins = PluginUtils.Plugins.get(getProxy().getPluginManager());
|
return 1;
|
||||||
Object libraryLoader = PluginUtils.LibraryLoader.get(getProxy().getPluginManager());
|
|
||||||
PluginDescription desc = PluginUtils.loadDescription(getProxy().getPluginManager(), new File(getProxy().getPluginsFolder(), "BungeeCore.jar"));
|
|
||||||
|
|
||||||
getProxy().getScheduler().runAsync(this, () -> {
|
|
||||||
getProxy().broadcast(TextComponent.fromLegacyText(PREFIX + "§eNetwork update is starting§8."));
|
|
||||||
try {
|
|
||||||
PluginUtils.unloadPlugin(getProxy(), commandMap, plugins, getProxy().getPluginManager().getPlugin("BungeeCore"));
|
|
||||||
PluginUtils.loadPlugin(plugins, libraryLoader, desc);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
getLogger().log(Level.SEVERE, "Errors during softreload", t);
|
|
||||||
getProxy().broadcast(TextComponent.fromLegacyText(PREFIX + "§cNetwork update failed§8, §cexpect network restart soon§8."));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProxy().broadcast(TextComponent.fromLegacyText(PREFIX + "§eNetwork update complete§8."));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static void setLobbyServer(String lobbyServer) {}
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public static void setChatPrefix(String prefix) {}
|
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
package de.steamwar.bungeecore;
|
package de.steamwar.bungeecore;
|
||||||
|
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import com.velocitypowered.api.proxy.Player;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import com.velocitypowered.api.proxy.player.TabListEntry;
|
||||||
import net.md_5.bungee.protocol.packet.PlayerListItem;
|
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||||
|
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -29,23 +29,23 @@ import java.util.*;
|
|||||||
public class Storage {
|
public class Storage {
|
||||||
private Storage(){}
|
private Storage(){}
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, List<ProxiedPlayer>> challenges = new HashMap<>();
|
public static final Map<Player, List<Player>> challenges = new HashMap<>();
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, ProxiedPlayer> lastChats = new HashMap<>();
|
public static final Map<Player, Player> lastChats = new HashMap<>();
|
||||||
|
|
||||||
public static final Map<Integer, List<Integer>> teamInvitations = new HashMap<>(); // UserID -> List<TeamIDs>
|
public static final Map<Integer, List<Integer>> teamInvitations = new HashMap<>(); // UserID -> List<TeamIDs>
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, Timestamp> sessions = new HashMap<>(); // Contains session start timestamp
|
public static final Map<Player, Timestamp> sessions = new HashMap<>(); // Contains session start timestamp
|
||||||
|
|
||||||
public static final Map<Integer, Subserver> eventServer = new HashMap<>(); // TeamID -> Subserver map
|
public static final Map<Integer, Subserver> eventServer = new HashMap<>(); // TeamID -> Subserver map
|
||||||
|
|
||||||
public static final Set<ProxiedPlayer> fabricPlayers = new HashSet<>();
|
public static final Set<Player> fabricPlayers = new HashSet<>();
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, Integer> fabricCheckedPlayers = new HashMap<>();
|
public static final Map<Player, Integer> fabricCheckedPlayers = new HashMap<>();
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, Long> fabricExpectPluginMessage = new HashMap<>();
|
public static final Map<Player, Long> fabricExpectPluginMessage = new HashMap<>();
|
||||||
|
|
||||||
public static final Map<Integer, ServerInfo> teamServers = new HashMap<>(); // TeamID -> ServerInfo map
|
public static final Map<Integer, ServerInfo> teamServers = new HashMap<>(); // TeamID -> ServerInfo map
|
||||||
|
|
||||||
public static final Map<ProxiedPlayer, Map<UUID, PlayerListItem.Item>> directTabItems = new HashMap<>();
|
public static final Map<Player, Map<UUID, TabListEntry>> directTabItems = new HashMap<>();
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,17 @@
|
|||||||
|
|
||||||
package de.steamwar.bungeecore;
|
package de.steamwar.bungeecore;
|
||||||
|
|
||||||
|
import com.velocitypowered.api.proxy.Player;
|
||||||
|
import com.velocitypowered.api.proxy.server.RegisteredServer;
|
||||||
|
import com.velocitypowered.api.proxy.server.ServerInfo;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.kyori.adventure.text.Component;
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.kyori.adventure.text.TextComponent;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.kyori.adventure.text.format.NamedTextColor;
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
import net.md_5.bungee.api.config.ServerInfo;
|
import org.jetbrains.annotations.Blocking;
|
||||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
import org.jetbrains.annotations.Contract;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
@ -39,17 +43,18 @@ import java.util.function.Predicate;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
public class Subserver {
|
public class Subserver {
|
||||||
private static final Logger logger = ProxyServer.getInstance().getLogger();
|
private static final Logger logger = Persistent.getInstance().getLogger();
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private static final List<Subserver> serverList = new LinkedList<>();
|
private static final List<Subserver> serverList = new LinkedList<>();
|
||||||
private static final Map<ServerInfo, Subserver> infoToServer = new HashMap<>();
|
private static final Map<ServerInfo, Subserver> infoToServer = new HashMap<>();
|
||||||
|
|
||||||
public static Subserver getSubserver(ProxiedPlayer p) {
|
public static @Nullable Subserver getSubserver(Player p) {
|
||||||
synchronized (serverList) {
|
synchronized (serverList) {
|
||||||
for(int i = serverList.size()-1; i >= 0; i--){
|
for (int i = serverList.size() - 1; i >= 0; i--) {
|
||||||
if(serverList.get(i).onServer(p))
|
if (serverList.get(i).onServer(p))
|
||||||
return serverList.get(i);
|
return serverList.get(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -62,7 +67,7 @@ public class Subserver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void shutdown(){
|
static void shutdown() {
|
||||||
while (!serverList.isEmpty()) {
|
while (!serverList.isEmpty()) {
|
||||||
Subserver server = serverList.get(0);
|
Subserver server = serverList.get(0);
|
||||||
server.stop();
|
server.stop();
|
||||||
@ -78,16 +83,19 @@ public class Subserver {
|
|||||||
@Getter
|
@Getter
|
||||||
private final ServerInfo server;
|
private final ServerInfo server;
|
||||||
@Getter
|
@Getter
|
||||||
|
@Nullable
|
||||||
|
private RegisteredServer registeredServer;
|
||||||
|
@Getter
|
||||||
private final Servertype type;
|
private final Servertype type;
|
||||||
private final Thread thread;
|
private final Thread thread;
|
||||||
@Getter
|
@Getter
|
||||||
private boolean started;
|
private boolean started;
|
||||||
|
|
||||||
private final List<ProxiedPlayer> cachedPlayers = new LinkedList<>();
|
private final List<Player> cachedPlayers = new LinkedList<>();
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<ProxiedPlayer, String> tablistNames = new HashMap<>();
|
private final Map<Player, String> tablistNames = new HashMap<>();
|
||||||
|
|
||||||
protected Subserver(Servertype type, String serverName, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback) {
|
protected Subserver(Servertype type, String serverName, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, @Nullable Consumer<Exception> failureCallback) {
|
||||||
this.started = false;
|
this.started = false;
|
||||||
this.serverName = serverName;
|
this.serverName = serverName;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
@ -95,32 +103,31 @@ public class Subserver {
|
|||||||
this.failureCallback = failureCallback == null ? this::fatalError : failureCallback;
|
this.failureCallback = failureCallback == null ? this::fatalError : failureCallback;
|
||||||
this.checkpoint = processBuilder.command().contains("criu");
|
this.checkpoint = processBuilder.command().contains("criu");
|
||||||
|
|
||||||
try{
|
try {
|
||||||
this.process = processBuilder.start();
|
this.process = processBuilder.start();
|
||||||
}catch(IOException e){
|
} catch (IOException e) {
|
||||||
throw new SecurityException("Server could not be started", e);
|
throw new SecurityException("Server could not be started", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
|
||||||
this.server = ProxyServer.getInstance().constructServerInfo(
|
this.server = new ServerInfo(serverName, address);
|
||||||
serverName, address, "SteamWar.de - Subserver", false);
|
|
||||||
this.writer = new PrintWriter(process.getOutputStream(), true);
|
this.writer = new PrintWriter(process.getOutputStream(), true);
|
||||||
|
|
||||||
this.thread = new Thread(this::run, "Subserver " + serverName);
|
this.thread = new Thread(this::run, "Subserver " + serverName);
|
||||||
this.thread.start();
|
this.thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated(forRemoval = true)
|
||||||
public boolean hasStarted(){
|
public boolean hasStarted() {
|
||||||
return started;
|
return started;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPlayer(ProxiedPlayer p) {
|
public void sendPlayer(Player p) {
|
||||||
if(!started){
|
if (!started) {
|
||||||
p.sendMessage(ChatMessageType.ACTION_BAR, generateBar(0));
|
p.sendActionBar(generateBar(0));
|
||||||
cachedPlayers.add(p);
|
cachedPlayers.add(p);
|
||||||
}else{
|
} else {
|
||||||
p.connect(server);
|
p.createConnectionRequest(registeredServer).connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,38 +138,40 @@ public class Subserver {
|
|||||||
public void stop() {
|
public void stop() {
|
||||||
try {
|
try {
|
||||||
long pid = process.pid();
|
long pid = process.pid();
|
||||||
if(checkpoint)
|
if (checkpoint)
|
||||||
pid = process.children().findAny().map(ProcessHandle::pid).orElse(pid);
|
pid = process.children().findAny().map(ProcessHandle::pid).orElse(pid);
|
||||||
|
|
||||||
Runtime.getRuntime().exec(new String[]{"kill", "-SIGUSR1", Long.toString(pid)});
|
Runtime.getRuntime().exec(new String[]{"kill", "-SIGUSR1", Long.toString(pid)});
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Failed to send SIGUSR1 to subserver.", e);
|
logger.log(Level.SEVERE, "Failed to send SIGUSR1 to subserver.", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if(!process.waitFor(1, TimeUnit.MINUTES)) {
|
if (!process.waitFor(1, TimeUnit.MINUTES)) {
|
||||||
logger.log(Level.SEVERE, () -> serverName + " did not stop correctly, forcibly stopping!");
|
logger.log(Level.SEVERE, () -> serverName + " did not stop correctly, forcibly stopping!");
|
||||||
process.destroyForcibly();
|
process.destroyForcibly();
|
||||||
}
|
}
|
||||||
|
|
||||||
thread.join();
|
thread.join();
|
||||||
}catch(InterruptedException e){
|
} catch (InterruptedException e) {
|
||||||
logger.log(Level.SEVERE, "Subserver stop interrupted!", e);
|
logger.log(Level.SEVERE, "Subserver stop interrupted!", e);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean onServer(ProxiedPlayer p){
|
private boolean onServer(Player p) {
|
||||||
return cachedPlayers.contains(p) || server.getPlayers().contains(p);
|
return cachedPlayers.contains(p) || (registeredServer != null && registeredServer.getPlayersConnected().contains(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fatalError(Exception e) {
|
private void fatalError(Exception e) {
|
||||||
logger.log(Level.SEVERE, e, () -> serverName + " did not run correctly!");
|
logger.log(Level.SEVERE, e, () -> serverName + " did not run correctly!");
|
||||||
|
|
||||||
for(ProxiedPlayer cached : cachedPlayers)
|
for (Player cached : cachedPlayers)
|
||||||
cached.sendMessage(TextComponent.fromLegacy(Persistent.PREFIX + "§cUnexpected error during server startup."));
|
cached.sendMessage(Persistent.PREFIX.append(Component.text("Unexpected error during server startup.").color(NamedTextColor.RED)));
|
||||||
for(ProxiedPlayer player : server.getPlayers())
|
if (registeredServer != null) {
|
||||||
player.sendMessage(TextComponent.fromLegacy(Persistent.PREFIX + "§cLost connection to server."));
|
for (Player player : registeredServer.getPlayersConnected())
|
||||||
|
player.sendMessage(Persistent.PREFIX.append(Component.text("Lost connection to server.").color(NamedTextColor.RED)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void start(InputStream stream, Predicate<String> test) throws IOException {
|
private void start(InputStream stream, Predicate<String> test) throws IOException {
|
||||||
@ -172,13 +181,13 @@ public class Subserver {
|
|||||||
started = test.test(line);
|
started = test.test(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(line == null)
|
if (line == null)
|
||||||
throw new IOException(serverName + " did not start correctly!");
|
throw new IOException(serverName + " did not start correctly!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void register() {
|
protected void register() {
|
||||||
if(ProxyServer.getInstance().getServers().containsKey(serverName)) {
|
if (Persistent.getInstance().getProxyServer().getAllServers().stream().anyMatch(rs -> rs.getServerInfo().getName().equals(serverName))) {
|
||||||
SecurityException e = new SecurityException("Server already registered: " + serverName);
|
SecurityException e = new SecurityException("Server already registered: " + serverName);
|
||||||
stop();
|
stop();
|
||||||
failureCallback.accept(e);
|
failureCallback.accept(e);
|
||||||
@ -186,17 +195,18 @@ public class Subserver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
synchronized (serverList) {
|
synchronized (serverList) {
|
||||||
ProxyServer.getInstance().getServers().put(serverName, server);
|
registeredServer = Persistent.getInstance().getProxyServer().registerServer(server);
|
||||||
serverList.add(this);
|
serverList.add(this);
|
||||||
infoToServer.put(server, this);
|
infoToServer.put(server, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void unregister() {
|
protected void unregister() {
|
||||||
synchronized (serverList){
|
synchronized (serverList) {
|
||||||
infoToServer.remove(server);
|
infoToServer.remove(server);
|
||||||
serverList.remove(this);
|
serverList.remove(this);
|
||||||
ProxyServer.getInstance().getServers().remove(serverName);
|
Persistent.getInstance().getProxyServer().unregisterServer(server);
|
||||||
|
registeredServer = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,21 +215,21 @@ public class Subserver {
|
|||||||
|
|
||||||
Exception ex = null;
|
Exception ex = null;
|
||||||
try {
|
try {
|
||||||
if(checkpoint) {
|
if (checkpoint) {
|
||||||
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
|
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
|
||||||
} else {
|
} else {
|
||||||
start(process.getInputStream(), line -> {
|
start(process.getInputStream(), line -> {
|
||||||
if(line.contains("Loading libraries, please wait"))
|
if (line.contains("Loading libraries, please wait"))
|
||||||
sendProgress(2);
|
sendProgress(2);
|
||||||
else if(line.contains("Starting Minecraft server on"))
|
else if (line.contains("Starting Minecraft server on"))
|
||||||
sendProgress(4);
|
sendProgress(4);
|
||||||
else if(line.contains("Preparing start region"))
|
else if (line.contains("Preparing start region"))
|
||||||
sendProgress(6);
|
sendProgress(6);
|
||||||
return line.contains("Finished mapping loading");
|
return line.contains("Finished mapping loading");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!started)
|
if (!started)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sendProgress(8);
|
sendProgress(8);
|
||||||
@ -227,32 +237,33 @@ public class Subserver {
|
|||||||
Thread.sleep(300);
|
Thread.sleep(300);
|
||||||
|
|
||||||
sendProgress(10);
|
sendProgress(10);
|
||||||
for(ProxiedPlayer cachedPlayer : cachedPlayers) {
|
for (Player cachedPlayer : cachedPlayers) {
|
||||||
sendPlayer(cachedPlayer);
|
sendPlayer(cachedPlayer);
|
||||||
}
|
}
|
||||||
cachedPlayers.clear();
|
cachedPlayers.clear();
|
||||||
|
|
||||||
process.waitFor();
|
process.waitFor();
|
||||||
} catch(IOException e) {
|
} catch (IOException e) {
|
||||||
ex = e;
|
ex = e;
|
||||||
} catch(InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
ex = e;
|
ex = e;
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
} finally {
|
} finally {
|
||||||
unregister();
|
unregister();
|
||||||
shutdownCallback.run();
|
shutdownCallback.run();
|
||||||
if(ex != null)
|
if (ex != null)
|
||||||
failureCallback.accept(ex);
|
failureCallback.accept(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseComponent generateBar(int progress) {
|
private Component generateBar(int progress) {
|
||||||
return TextComponent.fromLegacy("§e" + "⬛".repeat(Math.max(0, progress)) + "§8" + "⬛".repeat(Math.max(0, 10 - progress)));
|
return Component.text("⬛".repeat(Math.max(0, progress))).color(NamedTextColor.GOLD)
|
||||||
|
.append(Component.text("⬛".repeat(Math.max(0, 10 - progress))).color(NamedTextColor.DARK_GRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendProgress(int progress) {
|
private void sendProgress(int progress) {
|
||||||
BaseComponent tc = generateBar(progress);
|
Component tc = generateBar(progress);
|
||||||
for(ProxiedPlayer cached : cachedPlayers)
|
for (Player cached : cachedPlayers)
|
||||||
cached.sendMessage(ChatMessageType.ACTION_BAR, tc);
|
cached.sendActionBar(tc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is a part of the SteamWar software.
|
|
||||||
*
|
|
||||||
* Copyright (C) 2023 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.persistent;
|
|
||||||
|
|
||||||
import net.md_5.bungee.api.event.AsyncEvent;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
|
||||||
import net.md_5.bungee.event.EventBus;
|
|
||||||
import net.md_5.bungee.event.EventExceptionHandler;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
|
|
||||||
public final class ModifiedPluginEventBus extends EventBus {
|
|
||||||
|
|
||||||
private static final Set<AsyncEvent<?>> UNCOMPLETED_EVENTS = Collections.newSetFromMap(new WeakHashMap<>());
|
|
||||||
private static final Object LOCK = new Object();
|
|
||||||
|
|
||||||
public static void completeIntents(Plugin plugin) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
UNCOMPLETED_EVENTS.forEach(event -> {
|
|
||||||
try {
|
|
||||||
event.completeIntent(plugin);
|
|
||||||
} catch (Exception error) {
|
|
||||||
// Ignored
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> void post(T event, EventExceptionHandler<T> exceptionHandler) {
|
|
||||||
if (event instanceof AsyncEvent) {
|
|
||||||
synchronized (LOCK) {
|
|
||||||
UNCOMPLETED_EVENTS.add((AsyncEvent<?>) event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.post(event, exceptionHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -19,165 +19,13 @@
|
|||||||
|
|
||||||
package de.steamwar.persistent;
|
package de.steamwar.persistent;
|
||||||
|
|
||||||
import net.md_5.bungee.api.ProxyServer;
|
import net.frankheijden.serverutils.velocity.ServerUtils;
|
||||||
import net.md_5.bungee.api.plugin.Command;
|
|
||||||
import net.md_5.bungee.api.plugin.Plugin;
|
|
||||||
import net.md_5.bungee.api.plugin.PluginDescription;
|
|
||||||
import net.md_5.bungee.api.plugin.PluginManager;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URLClassLoader;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.jar.JarEntry;
|
|
||||||
import java.util.jar.JarFile;
|
|
||||||
import java.util.logging.Handler;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
public final class PluginUtils {
|
public final class PluginUtils {
|
||||||
//Adapted from https://github.com/Shevchik/BungeePluginManager/blob/master/src/bungeepluginmanager/PluginUtils.java
|
|
||||||
|
|
||||||
private static final Class<?> LibraryLoaderClass = Reflection.getClass("net.md_5.bungee.api.plugin.LibraryLoader");
|
|
||||||
private static final Reflection.MethodInvoker createLoader = Reflection.getTypedMethod(LibraryLoaderClass, "createLoader", ClassLoader.class, PluginDescription.class);
|
|
||||||
|
|
||||||
public static final Reflection.FieldAccessor<Map> CommandMap = Reflection.getField(PluginManager.class, "commandMap", Map.class);
|
|
||||||
public static final Reflection.FieldAccessor<Map> Plugins = Reflection.getField(PluginManager.class, "plugins", Map.class);
|
|
||||||
public static final Reflection.FieldAccessor<Yaml> Yaml = Reflection.getField(PluginManager.class, "yaml", Yaml.class);
|
|
||||||
public static final Reflection.FieldAccessor<?> LibraryLoader = Reflection.getField(PluginManager.class, "libraryLoader", LibraryLoaderClass);
|
|
||||||
public static final Reflection.FieldAccessor<ExecutorService> Service = Reflection.getField(Plugin.class, "service", ExecutorService.class);
|
|
||||||
|
|
||||||
private static final Class<?> PluginClassLoaderClass = Reflection.getClass("net.md_5.bungee.api.plugin.PluginClassloader");
|
|
||||||
private static final Reflection.ConstructorInvoker NewPluginClassLoader = Reflection.getConstructor(PluginClassLoaderClass, ProxyServer.class, PluginDescription.class, File.class, ClassLoader.class);
|
|
||||||
|
|
||||||
private static final Reflection.MethodInvoker init = Reflection.getMethod(Plugin.class, "init", ProxyServer.class, PluginDescription.class);
|
|
||||||
|
|
||||||
private static final Set<?> allLoaders = Reflection.getField(PluginClassLoaderClass, "allLoaders", Set.class).get(null);
|
|
||||||
|
|
||||||
private PluginUtils() {}
|
private PluginUtils() {}
|
||||||
|
|
||||||
public static void unloadPlugin(ProxyServer proxy, Map<String, Command> commandMap, Map<String, Plugin> plugins, Plugin plugin) {
|
public static void reloadPlugin() {
|
||||||
IllegalStateException error = new IllegalStateException();
|
ServerUtils.getInstance().getPlugin().getPluginManager().reloadPlugin("VelocityCore");
|
||||||
|
|
||||||
PluginManager pluginManager = proxy.getPluginManager();
|
|
||||||
ClassLoader pluginClassLoader = plugin.getClass().getClassLoader();
|
|
||||||
|
|
||||||
try {
|
|
||||||
plugin.onDisable();
|
|
||||||
} catch (Exception e) {
|
|
||||||
proxy.getLogger().log(Level.SEVERE, "Exception on disable", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
//unregister event handlers
|
|
||||||
pluginManager.unregisterListeners(plugin);
|
|
||||||
|
|
||||||
//unregister commands
|
|
||||||
pluginManager.unregisterCommands(plugin);
|
|
||||||
//remove incorrectly registered plugins
|
|
||||||
commandMap.entrySet().removeIf(entry -> entry.getValue().getClass().getClassLoader() == pluginClassLoader);
|
|
||||||
|
|
||||||
//cancel scheduled tasks
|
|
||||||
proxy.getScheduler().cancel(plugin);
|
|
||||||
|
|
||||||
//finish uncompleted intents
|
|
||||||
ModifiedPluginEventBus.completeIntents(plugin);
|
|
||||||
|
|
||||||
//shutdown internal executor
|
|
||||||
ExecutorService service = Service.get(plugin);
|
|
||||||
if(service != null)
|
|
||||||
service.shutdownNow();
|
|
||||||
|
|
||||||
//stop all still active threads that belong to a plugin
|
|
||||||
for(Thread thread : Thread.getAllStackTraces().keySet()) {
|
|
||||||
if(thread.getClass().getClassLoader() != pluginClassLoader)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
thread.interrupt();
|
|
||||||
try {
|
|
||||||
thread.join(100);
|
|
||||||
} catch (InterruptedException t) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (thread.isAlive())
|
|
||||||
proxy.getLogger().log(Level.WARNING, () -> "Could not stop thread " + thread.getName() + " of plugin " + plugin.getDescription().getName() + ". Still running");
|
|
||||||
}
|
|
||||||
|
|
||||||
//Clear resource bundle cache
|
|
||||||
ResourceBundle.clearCache(pluginClassLoader);
|
|
||||||
|
|
||||||
//close all log handlers
|
|
||||||
for (Handler handler : plugin.getLogger().getHandlers()) {
|
|
||||||
handler.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//cleanup internal listener and command maps from plugin refs
|
|
||||||
plugins.values().remove(plugin);
|
|
||||||
|
|
||||||
// Remove classloader
|
|
||||||
allLoaders.remove(pluginClassLoader);
|
|
||||||
|
|
||||||
//close classloader
|
|
||||||
if (pluginClassLoader instanceof URLClassLoader) {
|
|
||||||
try {
|
|
||||||
((URLClassLoader) pluginClassLoader).close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
proxy.getLogger().log(Level.SEVERE, "Exception while closing the classloader", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(error.getSuppressed().length > 0) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PluginDescription loadDescription(PluginManager pluginManager, File pluginFile) {
|
|
||||||
PluginDescription desc;
|
|
||||||
try (JarFile jar = new JarFile(pluginFile)) {
|
|
||||||
JarEntry pdf = jar.getJarEntry("bungee.yml");
|
|
||||||
|
|
||||||
if (pdf == null) {
|
|
||||||
pdf = jar.getJarEntry("plugin.yml");
|
|
||||||
}
|
|
||||||
|
|
||||||
try (InputStream in = jar.getInputStream(pdf)) {
|
|
||||||
//load description
|
|
||||||
desc = PluginUtils.Yaml.get(pluginManager).loadAs(in, PluginDescription.class);
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
desc.setFile(pluginFile);
|
|
||||||
|
|
||||||
//check depends
|
|
||||||
Map<String, Plugin> pluginsMap = PluginUtils.Plugins.get(pluginManager);
|
|
||||||
for (String dependency : desc.getDepends()) {
|
|
||||||
if (!pluginsMap.containsKey(dependency)) {
|
|
||||||
throw new IllegalStateException(dependency +" (required by " + desc.getName() + ") is unavailable");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void loadPlugin(Map<String, Plugin> plugins, Object libraryLoader, PluginDescription desc) {
|
|
||||||
URLClassLoader loader = (URLClassLoader)NewPluginClassLoader.invoke(ProxyServer.getInstance(), desc, desc.getFile(), libraryLoader != null ? createLoader.invoke(libraryLoader, desc) : null);
|
|
||||||
|
|
||||||
Plugin plugin;
|
|
||||||
try {
|
|
||||||
Class<?> mainclazz = loader.loadClass(desc.getMain());
|
|
||||||
plugin = (Plugin) Reflection.newInstance(mainclazz);
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
throw new IllegalStateException(e);
|
|
||||||
}
|
|
||||||
init.invoke(plugin, ProxyServer.getInstance(), desc);
|
|
||||||
|
|
||||||
plugins.put(desc.getName(), plugin);
|
|
||||||
plugin.onLoad();
|
|
||||||
plugin.onEnable();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import java.util.Arrays;
|
|||||||
*
|
*
|
||||||
* @author Kristian
|
* @author Kristian
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "VelocityCore")
|
||||||
public final class Reflection {
|
public final class Reflection {
|
||||||
/**
|
/**
|
||||||
* An interface for invoking a specific constructor.
|
* An interface for invoking a specific constructor.
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
name: PersistentBungeeCore
|
|
||||||
main: de.steamwar.bungeecore.Persistent
|
|
||||||
version: 1.0
|
|
||||||
author: Lixfel
|
|
In neuem Issue referenzieren
Einen Benutzer sperren