1
0

Commits vergleichen

..

1 Commits

Autor SHA1 Nachricht Datum
yoyosource
24524036a8 Add Initial setup 2023-02-20 12:15:03 +01:00
16 geänderte Dateien mit 773 neuen und 689 gelöschten Zeilen

Datei anzeigen

@ -17,33 +17,50 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import org.apache.tools.ant.taskdefs.condition.Os
plugins {
id 'java'
id 'application'
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'de.steamwar.gradle' version 'RELEASE'
id 'com.github.johnrengelman.shadow' version '5.0.0'
}
group 'de.steamwar'
version ''
mainClassName = ''
Properties steamwarProperties = new Properties()
if (file("steamwar.properties").exists()) {
steamwarProperties.load(file("steamwar.properties").newDataInputStream())
}
ext {
buildName = 'PersistentBungeeCore'
artifactName = 'persistentbungeecore'
uberJarName = "${buildName}-all.jar"
jarName = "${artifactName}.jar"
libs = "${buildDir}/libs"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
operatingSystem = "windows"
} else {
operatingSystem = "unix"
}
}
compileJava.options.encoding = 'UTF-8'
application {
mainClassName = ''
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
sourceSets {
main {
java {
srcDirs = ['src/']
include '**/*.java', '**/*.kt'
}
resources {
srcDirs = ['src/']
@ -54,12 +71,9 @@ sourceSets {
repositories {
mavenCentral()
maven {
name = 'papermc'
url = 'https://repo.papermc.io/repository/maven-public/'
}
maven {
url = 'https://repo.fvdh.dev/releases'
url = uri('https://steamwar.de/maven')
}
}
@ -69,12 +83,153 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok:1.18.22'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.22'
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'
compileOnly 'de.steamwar:waterfall:RELEASE'
}
steamwar {
publishing = true
task buildProject {
description 'Build this project'
group "Steamwar"
dependsOn build
}
task finalizeProject {
description 'Finalize this project'
group "Steamwar"
doLast {
if ("${buildDir}" == null) {
return
}
delete fileTree("${libs}").matching {
exclude("${uberJarName}")
}
file(libs + "/" + uberJarName).renameTo(file(libs + "/" + jarName))
}
}
build.finalizedBy(finalizeProject)
if (steamwarProperties.containsKey("hostname")) {
String hostname = steamwarProperties.get("hostname")
String uploadPath = steamwarProperties.getOrDefault("uploadPath", "~")
String server = steamwarProperties.getOrDefault("server", "Dev1.15")
String serverStartFlags = steamwarProperties.getOrDefault("serverStartFlags", "")
task uploadProject {
description 'Upload this project'
group "Steamwar"
doLast {
await(shell("scp ${libs}/${jarName} ${hostname}:${uploadPath}/${server}/plugins"))
if (steamwarProperties.getOrDefault("directStart", "false") == "false" && !answer("Start ${server} server?")) {
return
}
serverStart(server, serverStartFlags, hostname)
}
}
uploadProject.dependsOn(buildProject)
task startDevServer {
description 'Start the DevServer'
group "Steamwar"
doLast {
serverStart(server, serverStartFlags, hostname)
}
}
}
private def await(Process proc) {
def out = new StringBuilder()
def err = new StringBuilder()
proc.waitForProcessOutput(out, err)
return [out, err, proc.exitValue()]
}
private def shell(String command) {
if (operatingSystem == "unix") {
return ['bash', '-c', command].execute()
} else {
return ["cmd", "/c", command].execute()
}
}
private def serverStart(String serverName, String serverFlags, String hostname) {
def proc = shell("ssh -t ${hostname} \"./mc ${serverFlags} ${serverName}\"")
Set<String> strings = new HashSet<>()
File file = new File("${projectDir}/ignoredlog");
if (file.exists()) {
new BufferedReader(new InputStreamReader(new FileInputStream(file))).readLines().forEach({ s ->
strings.add(s)
})
}
Thread outputThread = new Thread({
Reader reader = proc.getInputStream().newReader();
Writer writer = System.out.newWriter();
try {
while (proc.alive) {
String s = reader.readLine()
if (s == null) {
return
}
if (strings.stream().anyMatch({check -> s.contains(check)})) {
continue
}
writer.write(s + "\n")
writer.flush()
}
} catch (IOException e) {
// Ignored
}
})
outputThread.setName("${serverName} - OutputThread")
outputThread.start()
Writer writer
Thread inputThread = new Thread({
Reader reader = System.in.newReader()
writer = proc.getOutputStream().newWriter()
try {
while (proc.alive) {
String s = reader.readLine()
writer.write(s + "\n")
writer.flush()
}
} catch (IOException e) {
// Ignored
}
})
inputThread.setName("${serverName} - InputThread")
inputThread.start()
gradle.buildFinished { buildResult ->
if (!proc.alive) {
return
}
writer = proc.getOutputStream().newWriter()
writer.write("stop\n")
writer.flush()
awaitClose(proc, outputThread, inputThread)
}
awaitClose(proc, outputThread, inputThread)
};
private static def awaitClose(Process proc, Thread outputThread, Thread inputThread) {
while (proc.alive) {
Thread.sleep(10)
}
proc.closeStreams()
outputThread.interrupt()
inputThread.interrupt()
}
private def answer(String question) {
while (System.in.available() > 0) System.in.read()
println(question)
boolean valid = "Yy".contains(((char) System.in.read()).toString())
while (System.in.available() > 0) System.in.read()
return valid
}

Datei anzeigen

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

Datei anzeigen

@ -17,13 +17,4 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
pluginManagement {
repositories {
gradlePluginPortal()
maven {
url = uri("https://steamwar.de/maven/")
}
}
}
rootProject.name = 'PersistentVelocityCore'
rootProject.name = 'PersistentBungeeCore'

Datei anzeigen

@ -1,8 +1,5 @@
package de.steamwar.bungeecore;
import lombok.Getter;
@Getter
public class Arenaserver extends Subserver {
private final String mode;
@ -10,9 +7,21 @@ public class Arenaserver extends Subserver {
private final boolean allowMerge;
public Arenaserver(String serverName, String mode, String map, boolean allowMerge, int port, ProcessBuilder processBuilder, Runnable shutdownCallback) {
super(Servertype.ARENA, serverName, port, processBuilder, shutdownCallback, null);
super(Servertype.ARENA, serverName, port, processBuilder, shutdownCallback);
this.mode = mode;
this.map = map;
this.allowMerge = allowMerge;
}
public String getMode() {
return mode;
}
public String getMap() {
return map;
}
public boolean isAllowMerge() {
return allowMerge;
}
}

Datei anzeigen

@ -19,47 +19,26 @@
package de.steamwar.bungeecore;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.function.Consumer;
@Getter
public class Bauserver extends Subserver {
private static final Map<UUID, Bauserver> servers = new HashMap<>();
public static Bauserver get(UUID owner) {
synchronized (servers) {
return servers.get(owner);
}
}
private final UUID owner;
public Bauserver(String serverName, UUID owner, int port, String... command) {
this(serverName, owner, port, () -> {}, command);
}
public Bauserver(String serverName, UUID owner, int port, Runnable shutdownCallback, String... command) {
this(serverName, owner, port, new ProcessBuilder(command), shutdownCallback);
}
public Bauserver(String serverName, UUID owner, int port, ProcessBuilder processBuilder, Runnable shutdownCallback){
this(serverName, owner, port, processBuilder, shutdownCallback, null);
}
public Bauserver(String serverName, UUID owner, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback){
super(Servertype.BAUSERVER, serverName, port, processBuilder, shutdownCallback, failureCallback);
super(Servertype.BAUSERVER, serverName, port, processBuilder, shutdownCallback);
this.owner = owner;
synchronized (servers) {
servers.put(owner, this);
}
}
@Override
protected void register() {
super.register();
}
@Override
protected void unregister() {
synchronized (servers) {
servers.remove(owner);
}
super.unregister();
public UUID getOwner(){
return owner;
}
}

Datei anzeigen

@ -19,46 +19,16 @@
package de.steamwar.bungeecore;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
@Getter
public class Builderserver extends Subserver {
private static final Map<String, Builderserver> servers = new HashMap<>();
public static Builderserver get(String map) {
synchronized (servers) {
return servers.get(map);
}
}
private final String map;
public Builderserver(String serverName, String map, int port, ProcessBuilder processBuilder, Runnable shutdownCallback){
this(serverName, map, port, processBuilder, shutdownCallback, null);
}
public Builderserver(String serverName, String map, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, Consumer<Exception> failureCallback){
super(Servertype.BUILDER, serverName, port, processBuilder, shutdownCallback, failureCallback);
super(Servertype.BUILDER, serverName, port, processBuilder, shutdownCallback);
this.map = map;
synchronized (servers) {
servers.put(map, this);
}
}
@Override
protected void register() {
super.register();
}
@Override
protected void unregister() {
synchronized (servers) {
servers.remove(map);
}
super.unregister();
public String getMap() {
return map;
}
}

Datei anzeigen

@ -19,62 +19,65 @@
package de.steamwar.bungeecore;
import com.google.inject.Inject;
import com.velocitypowered.api.command.BrigadierCommand;
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 lombok.Getter;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.bungeepluginmanager.ModifiedPluginEventBus;
import net.md_5.bungee.api.bungeepluginmanager.PluginUtils;
import net.md_5.bungee.api.bungeepluginmanager.ReflectionUtils;
import net.md_5.bungee.api.plugin.Command;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.plugin.PluginManager;
import java.util.logging.Logger;
import java.io.File;
@Plugin(id = "persistentvelocitycore", name = "PersistentVelocityCore", version = "1.0", description = "PersistentVelocityCore", authors = {"SteamWar"})
public class Persistent {
public class Persistent extends Plugin {
public static final Component PREFIX = Component.text("Steam").color(NamedTextColor.YELLOW)
.append(Component.text("War»").color(NamedTextColor.DARK_GRAY))
.appendSpace();
@Getter
private static Persistent instance;
private static String chatPrefix = "";
private static String lobbyServer = "";
@Inject
public Persistent(ProxyServer proxyServer, Logger logger) {
@Override
public void onLoad() {
ReflectionUtils.setFieldValue(getProxy().getPluginManager(), "eventBus", new ModifiedPluginEventBus());
}
@Override
public void onEnable(){
instance = this;
this.proxyServer = proxyServer;
this.logger = logger;
getProxy().getPluginManager().registerCommand(this, new Command("softreload", "bungeecore.softreload"){
@Override
public void execute(CommandSender sender, String[] args) {
// Copied from https://www.spigotmc.org/resources/bungeepluginmanager-manage-your-bungee-plugin-at-runtime.63861/
PluginManager pluginManager = getProxy().getPluginManager();
Plugin bungeecore = pluginManager.getPlugin("BungeeCore");
PluginUtils.unloadPlugin(bungeecore);
PluginUtils.loadPlugin(new File(getProxy().getPluginsFolder(), "BungeeCore.jar"));
}
});
}
@Getter
private final ProxyServer proxyServer;
@Getter
private final Logger logger;
@Subscribe
public void onEnable(ProxyInitializeEvent event) {
proxyServer.getCommandManager().register(
new BrigadierCommand(
BrigadierCommand.literalArgumentBuilder("softreload")
.requires(commandSource -> commandSource.hasPermission("bungeecore.softreload"))
.executes(commandContext -> softreload())
.build()
)
);
}
@Subscribe
public void onDisable(ProxyShutdownEvent event) {
@Override
public void onDisable(){
Subserver.shutdown();
}
public int softreload() {
PluginUtils.reloadPlugin();
return 1;
public static void setLobbyServer(String lobbyServer) {
Persistent.lobbyServer = lobbyServer;
}
public static void setChatPrefix(String prefix){
chatPrefix = prefix;
}
static String getLobbyServer() {
return lobbyServer;
}
static String getPrefix(){
return chatPrefix;
}
static Persistent getInstance() {
return instance;
}
}

Datei anzeigen

@ -19,9 +19,9 @@
package de.steamwar.bungeecore;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.player.TabListEntry;
import com.velocitypowered.api.proxy.server.ServerInfo;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.protocol.packet.PlayerListItem;
import java.sql.Timestamp;
import java.util.*;
@ -29,23 +29,29 @@ import java.util.*;
public class Storage {
private Storage(){}
public static final Map<Player, List<Player>> challenges = new HashMap<>();
public static final Map<ProxiedPlayer, List<ProxiedPlayer>> challenges = new HashMap<>();
public static final Map<Player, Player> lastChats = new HashMap<>();
public static final Map<ProxiedPlayer, ProxiedPlayer> lastChats = new HashMap<>();
public static final Map<Integer, List<Integer>> teamInvitations = new HashMap<>(); // UserID -> List<TeamIDs>
public static final Map<Player, Timestamp> sessions = new HashMap<>(); // Contains session start timestamp
public static final Map<ProxiedPlayer, Timestamp> sessions = new HashMap<>(); // Contains session start timestamp
public static final Map<Integer, Subserver> eventServer = new HashMap<>(); // TeamID -> Subserver map
public static final Set<Player> fabricPlayers = new HashSet<>();
public static final Set<ProxiedPlayer> fabricPlayers = new HashSet<>();
public static final Map<Player, Integer> fabricCheckedPlayers = new HashMap<>();
public static final Map<ProxiedPlayer, Integer> fabricCheckedPlayers = new HashMap<>();
public static final Map<Player, Long> fabricExpectPluginMessage = new HashMap<>();
public static final Map<ProxiedPlayer, Long> fabricExpectPluginMessage = new HashMap<>();
public static final Map<Integer, ServerInfo> teamServers = new HashMap<>(); // TeamID -> ServerInfo map
public static final Map<Player, Map<UUID, TabListEntry>> directTabItems = new HashMap<>();
public static final Map<ProxiedPlayer, Map<UUID, PlayerListItem.Item>> directTabItems = new HashMap<>();
public static final Map<Subserver, String> serverToNodeMap = new HashMap<>();
public static final Map<String, List<Subserver>> nodeToServerMap = new HashMap<>();
public static final Map<Subserver, Long> timeOfServerEmpty = new HashMap<>();
}

Datei anzeigen

@ -19,115 +19,114 @@
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 net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.jetbrains.annotations.Blocking;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.Nullable;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
@SuppressWarnings("unused")
public class Subserver {
private static final Logger logger = Persistent.getInstance().getLogger();
@SuppressWarnings("deprecation")
public class Subserver implements Runnable {
@Getter
private static final List<Subserver> serverList = new LinkedList<>();
private static final Map<ServerInfo, Subserver> infoToServer = new HashMap<>();
private static final Logger logger = ProxyServer.getInstance().getLogger();
public static @Nullable Subserver getSubserver(Player p) {
public static Subserver getSubserver(ProxiedPlayer p){
synchronized (serverList) {
for (int i = serverList.size() - 1; i >= 0; i--) {
if (serverList.get(i).onServer(p))
for(int i = serverList.size()-1; i >= 0; i--){
if(serverList.get(i).onServer(p))
return serverList.get(i);
}
}
return null;
}
public static Subserver getSubserver(ServerInfo server) {
public static Subserver getSubserver(ServerInfo server){
synchronized (serverList) {
return infoToServer.get(server);
for(Subserver s : serverList)
if(s.server == server)
return s;
}
return null;
}
static void shutdown() {
while (!serverList.isEmpty()) {
Subserver server = serverList.get(0);
server.stop();
}
public static List<Subserver> getServerList(){
return serverList;
}
private final String serverName;
private final boolean checkpoint;
private final Runnable shutdownCallback;
private final Consumer<Exception> failureCallback;
private final Process process;
private final PrintWriter writer;
@Getter
private final ServerInfo server;
@Getter
@Nullable
private RegisteredServer registeredServer;
@Getter
private final Servertype type;
private final Thread thread;
@Getter
private boolean started;
private final List<Player> cachedPlayers = new LinkedList<>();
@Getter
private final Map<Player, String> tablistNames = new HashMap<>();
private final List<ProxiedPlayer> cachedPlayers = new LinkedList<>();
private final Map<ProxiedPlayer, String> tablistNames = new HashMap<>();
protected Subserver(Servertype type, String serverName, int port, ProcessBuilder processBuilder, Runnable shutdownCallback, @Nullable Consumer<Exception> failureCallback) {
public Subserver(Servertype type, String serverName, int port, String... command){
this(type, serverName, port, () -> {}, command);
}
public Subserver(Servertype type, String serverName, int port, Runnable shutdownCallback, String... command){
this(type, serverName, port, new ProcessBuilder(command), shutdownCallback);
}
public Subserver(Servertype type, String serverName, int port, ProcessBuilder processBuilder, Runnable shutdownCallback){
this.started = false;
this.serverName = serverName;
this.type = type;
this.shutdownCallback = shutdownCallback;
this.failureCallback = failureCallback == null ? this::fatalError : failureCallback;
this.checkpoint = processBuilder.command().contains("criu");
try {
try{
this.process = processBuilder.start();
} catch (IOException e) {
}catch(IOException e){
throw new SecurityException("Server could not be started", e);
}
InetSocketAddress address = new InetSocketAddress("127.0.0.1", port);
this.server = new ServerInfo(serverName, address);
this.server = ProxyServer.getInstance().constructServerInfo(
serverName, address, "SteamWar.de - Subserver", false);
this.writer = new PrintWriter(process.getOutputStream(), true);
this.thread = new Thread(this::run, "Subserver " + serverName);
this.thread = new Thread(this, "Subserver " + serverName);
this.thread.start();
}
@Deprecated(forRemoval = true)
public boolean hasStarted() {
public ServerInfo getServer(){
return server;
}
public Servertype getType(){
return type;
}
public Map<ProxiedPlayer, String> getTablistNames(){
return tablistNames;
}
public boolean hasStarted(){
return started;
}
public void sendPlayer(Player p) {
if (!started) {
p.sendActionBar(generateBar(0));
public void sendPlayer(ProxiedPlayer p){
if(!started){
p.sendMessage(Persistent.getPrefix() + "§7Der Server wird gestartet, einen Moment bitte...");
cachedPlayers.add(p);
} else {
p.createConnectionRequest(registeredServer).connect();
}else{
p.connect(server);
}
}
@ -135,135 +134,127 @@ public class Subserver {
writer.println(command);
}
public void stop() {
public void stop(){
execute("stop");
try {
long pid = process.pid();
if (checkpoint)
pid = process.children().findAny().map(ProcessHandle::pid).orElse(pid);
Runtime.getRuntime().exec(new String[]{"kill", "-SIGUSR1", Long.toString(pid)});
} catch (IOException e) {
logger.log(Level.SEVERE, "Failed to send SIGUSR1 to subserver.", e);
}
try {
if (!process.waitFor(1, TimeUnit.MINUTES)) {
logger.log(Level.SEVERE, () -> serverName + " did not stop correctly, forcibly stopping!");
if(!process.waitFor(1, TimeUnit.MINUTES))
process.destroyForcibly();
}
thread.join();
} catch (InterruptedException e) {
cleanup();
}catch(InterruptedException e){
logger.log(Level.SEVERE, "Subserver stop interrupted!", e);
Thread.currentThread().interrupt();
}
}
private boolean onServer(Player p) {
return cachedPlayers.contains(p) || (registeredServer != null && registeredServer.getPlayersConnected().contains(p));
}
private void fatalError(Exception e) {
logger.log(Level.SEVERE, e, () -> serverName + " did not run correctly!");
for (Player cached : cachedPlayers)
cached.sendMessage(Persistent.PREFIX.append(Component.text("Unexpected error during server startup.").color(NamedTextColor.RED)));
if (registeredServer != null) {
for (Player player : registeredServer.getPlayersConnected())
player.sendMessage(Persistent.PREFIX.append(Component.text("Lost connection to server.").color(NamedTextColor.RED)));
public void waitForTermination(){
try {
if(!process.waitFor(5, TimeUnit.MINUTES) && server.getPlayers().isEmpty()){
process.destroy();
}
thread.join();
cleanup();
}catch(InterruptedException e){
logger.log(Level.SEVERE, "Subserver stop interrupted!", e);
Thread.currentThread().interrupt();
}
}
private void start(InputStream stream, Predicate<String> test) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
private void cleanup() {
String nodeName = Storage.serverToNodeMap.remove(this);
if (nodeName != null) {
Storage.nodeToServerMap.computeIfPresent(nodeName, (s, list) -> {
list.remove(this);
if (list.isEmpty()) return null;
return list;
});
}
}
static void shutdown(){
while (!serverList.isEmpty()) {
Subserver server = serverList.get(0);
server.stop();
}
}
private boolean onServer(ProxiedPlayer p){
return cachedPlayers.contains(p) || server.getPlayers().contains(p);
}
private void fatalError(){
for(ProxiedPlayer cached : cachedPlayers)
cached.sendMessage(Persistent.getPrefix() + "§cUnerwarteter Fehler beim Serverstart.");
for(ProxiedPlayer player : server.getPlayers())
player.sendMessage(Persistent.getPrefix() + "§cUnerwarteter Fehler im Server.");
}
private void sendProgress(int progress){
StringBuilder sb = new StringBuilder("§e");
for(int i = 0; i < progress; i++)
sb.append('⬛');
sb.append("§8");
for(int i = progress; i < 10; i++)
sb.append('⬛');
BaseComponent[] tc = TextComponent.fromLegacyText(sb.toString());
for(ProxiedPlayer cached : cachedPlayers)
cached.sendMessage(ChatMessageType.ACTION_BAR, tc);
}
public void run(){
ProxyServer.getInstance().getServers().put(serverName, server);
synchronized (serverList) {
serverList.add(this);
}
try(BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))){
String line = "";
while (!started && (line = reader.readLine()) != null) {
started = test.test(line);
started = line.contains("ViaVersion detected server version");
if(line.contains("Loading libraries, please wait"))
sendProgress(0);
else if(line.contains("Starting Minecraft server on"))
sendProgress(3);
else if(line.contains("Preparing start region"))
sendProgress(6);
}
if (line == null)
throw new IOException(serverName + " did not start correctly!");
}
}
protected void register() {
if (Persistent.getInstance().getProxyServer().getAllServers().stream().anyMatch(rs -> rs.getServerInfo().getName().equals(serverName))) {
SecurityException e = new SecurityException("Server already registered: " + serverName);
stop();
failureCallback.accept(e);
throw e;
}
synchronized (serverList) {
registeredServer = Persistent.getInstance().getProxyServer().registerServer(server);
serverList.add(this);
infoToServer.put(server, this);
}
}
protected void unregister() {
synchronized (serverList) {
infoToServer.remove(server);
serverList.remove(this);
Persistent.getInstance().getProxyServer().unregisterServer(server);
registeredServer = null;
}
}
private void run() {
register();
Exception ex = null;
try {
if (checkpoint) {
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
} else {
start(process.getInputStream(), line -> {
if (line.contains("Loading libraries, please wait"))
sendProgress(2);
else if (line.contains("Starting Minecraft server on"))
sendProgress(4);
else if (line.contains("Preparing start region"))
sendProgress(6);
return line.contains("Finished mapping loading");
});
}
if (!started)
if(line == null){
logger.log(Level.SEVERE, "Subserver {0} stopped to early!", serverName);
fatalError();
return;
}
sendProgress(8);
sendProgress(9);
Thread.sleep(300);
sendProgress(10);
for (Player cachedPlayer : cachedPlayers) {
for(ProxiedPlayer cachedPlayer : cachedPlayers){
sendPlayer(cachedPlayer);
}
cachedPlayers.clear();
reader.close(); // Prevent stdout clogging up
process.waitFor();
} catch (IOException e) {
ex = e;
} catch (InterruptedException e) {
ex = e;
} catch(IOException e) {
logger.log(Level.SEVERE, "Server " + serverName + " was interrupted!", e);
fatalError();
} catch(InterruptedException e) {
logger.log(Level.SEVERE, "Server " + serverName + " was interrupted!", e);
fatalError();
Thread.currentThread().interrupt();
} finally {
unregister();
synchronized (serverList){
serverList.remove(this);
}
ProxyServer.getInstance().getServers().remove(serverName);
shutdownCallback.run();
if (ex != null)
failureCallback.accept(ex);
}
}
private Component generateBar(int 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) {
Component tc = generateBar(progress);
for (Player cached : cachedPlayers)
cached.sendActionBar(tc);
public long getPID() {
return process.pid();
}
}

Datei anzeigen

@ -1,31 +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.frankheijden.serverutils.velocity.ServerUtils;
public final class PluginUtils {
private PluginUtils() {}
public static void reloadPlugin() {
ServerUtils.getInstance().getPlugin().getPluginManager().reloadPlugin("VelocityCore");
}
}

Datei anzeigen

@ -1,343 +0,0 @@
package de.steamwar.persistent;
import java.lang.reflect.*;
import java.util.Arrays;
/**
* An utility class that simplifies reflection in Bukkit plugins.
*
* @author Kristian
*/
@Deprecated(forRemoval = true, since = "VelocityCore")
public final class Reflection {
/**
* An interface for invoking a specific constructor.
*/
public interface ConstructorInvoker {
/**
* Invoke a constructor for a specific class.
*
* @param arguments - the arguments to pass to the constructor.
* @return The constructed object.
*/
Object invoke(Object... arguments);
}
/**
* An interface for invoking a specific method.
*/
public interface MethodInvoker {
/**
* Invoke a method on a specific target object.
*
* @param target - the target object, or NULL for a static method.
* @param arguments - the arguments to pass to the method.
* @return The return value, or NULL if is void.
*/
Object invoke(Object target, Object... arguments);
}
/**
* An interface for retrieving the field content.
*
* @param <T> - field type.
*/
public interface FieldAccessor<T> {
/**
* Retrieve the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @return The value of the field.
*/
T get(Object target);
/**
* Set the content of a field.
*
* @param target - the target object, or NULL for a static field.
* @param value - the new value of the field.
*/
void set(Object target, Object value);
/**
* Determine if the given object has this field.
*
* @param target - the object to test.
* @return TRUE if it does, FALSE otherwise.
*/
boolean hasField(Object target);
}
private Reflection() {
// Seal class
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType) {
return getField(target, name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param name - the name of the field, or NULL to ignore.
* @param fieldType - a compatible field type.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, String name, Class<T> fieldType) {
return getField(getClass(className), name, fieldType, 0);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param target - the target type.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index) {
return getField(target, null, fieldType, index);
}
/**
* Retrieve a field accessor for a specific field type and name.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param fieldType - a compatible field type.
* @param index - the number of compatible fields to skip.
* @return The field accessor.
*/
public static <T> FieldAccessor<T> getField(String className, Class<T> fieldType, int index) {
return getField(getClass(className), fieldType, index);
}
public static <T> FieldAccessor<T> getField(Class<?> target, Class<T> fieldType, int index, Class<?>... parameters) {
return getField(target, null, fieldType, index, parameters);
}
private static <T> FieldAccessor<T> getField(Class<?> target, String name, Class<T> fieldType, int index, Class<?>... parameters) {
for (final Field field : target.getDeclaredFields()) {
if(matching(field, name, fieldType, parameters) && index-- <= 0) {
field.setAccessible(true);
return new FieldAccessor<T>() {
@Override
@SuppressWarnings("unchecked")
public T get(Object target) {
try {
return (T) field.get(target);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot access reflection.", e);
}
}
@Override
public void set(Object target, Object value) {
try {
field.set(target, value);
} catch (IllegalAccessException e) {
throw new IllegalArgumentException("Cannot access reflection.", e);
}
}
@Override
public boolean hasField(Object target) {
// target instanceof DeclaringClass
return field.getDeclaringClass().isAssignableFrom(target.getClass());
}
};
}
}
// Search in parent classes
if (target.getSuperclass() != null)
return getField(target.getSuperclass(), name, fieldType, index);
throw new IllegalArgumentException("Cannot find field with type " + fieldType);
}
private static <T> boolean matching(Field field, String name, Class<T> fieldType, Class<?>... parameters) {
if(name != null && !field.getName().equals(name))
return false;
if(!fieldType.isAssignableFrom(field.getType()))
return false;
if(parameters.length > 0) {
Type[] arguments = ((ParameterizedType)field.getGenericType()).getActualTypeArguments();
for(int i = 0; i < parameters.length; i++) {
if(arguments[i] instanceof ParameterizedType ? ((ParameterizedType) arguments[i]).getRawType() != parameters[i] : arguments[i] != parameters[i])
return false;
}
}
return true;
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(String className, String methodName, Class<?>... params) {
return getTypedMethod(getClass(className), methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getMethod(Class<?> clazz, String methodName, Class<?>... params) {
return getTypedMethod(clazz, methodName, null, params);
}
/**
* Search for the first publicly and privately defined method of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param methodName - the method name, or NULL to skip.
* @param returnType - the expected return type, or NULL to ignore.
* @param params - the expected parameters.
* @return An object that invokes this specific method.
* @throws IllegalStateException If we cannot find this method.
*/
public static MethodInvoker getTypedMethod(Class<?> clazz, String methodName, Class<?> returnType, Class<?>... params) {
for (final Method method : clazz.getDeclaredMethods()) {
if ((methodName == null || method.getName().equals(methodName))
&& (returnType == null || method.getReturnType().equals(returnType))
&& Arrays.equals(method.getParameterTypes(), params)) {
method.setAccessible(true);
return (target, arguments) -> {
try {
return method.invoke(target, arguments);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot invoke method " + method, e);
}
};
}
}
// Search in every superclass
if (clazz.getSuperclass() != null)
return getTypedMethod(clazz.getSuperclass(), methodName, returnType, params);
throw new IllegalStateException(String.format("Unable to find method %s (%s).", methodName, Arrays.asList(params)));
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param className - lookup name of the class, see {@link #getClass(String)}.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(String className, Class<?>... params) {
return getConstructor(getClass(className), params);
}
/**
* Search for the first publically and privately defined constructor of the given name and parameter count.
*
* @param clazz - a class to start with.
* @param params - the expected parameters.
* @return An object that invokes this constructor.
* @throws IllegalStateException If we cannot find this method.
*/
public static ConstructorInvoker getConstructor(Class<?> clazz, Class<?>... params) {
for (final Constructor<?> constructor : clazz.getDeclaredConstructors()) {
if (Arrays.equals(constructor.getParameterTypes(), params)) {
constructor.setAccessible(true);
return arguments -> {
try {
return constructor.newInstance(arguments);
} catch (Exception e) {
throw new IllegalArgumentException("Cannot invoke constructor " + constructor, e);
}
};
}
}
throw new IllegalStateException(String.format("Unable to find constructor for %s (%s).", clazz, Arrays.asList(params)));
}
/**
* Retrieve a class from its full name, without knowing its type on compile time.
* <p>
* This is useful when looking up fields by a NMS or OBC type.
* <p>
*
* @param lookupName - the class name with variables.
* @return The class.
*/
public static Class<Object> getUntypedClass(String lookupName) {
@SuppressWarnings({ "rawtypes", "unchecked" })
Class<Object> clazz = (Class) getClass(lookupName);
return clazz;
}
/**
* Retrieve a class from its full name.
* <p>
* Strings enclosed with curly brackets - such as {TEXT} - will be replaced according to the following table:
* <p>
* <table border="1">
* <tr>
* <th>Variable</th>
* <th>Content</th>
* </tr>
* <tr>
* <td>{nms}</td>
* <td>Actual package name of net.minecraft.server.VERSION</td>
* </tr>
* <tr>
* <td>{obc}</td>
* <td>Actual pacakge name of org.bukkit.craftbukkit.VERSION</td>
* </tr>
* <tr>
* <td>{version}</td>
* <td>The current Minecraft package VERSION, if any.</td>
* </tr>
* </table>
*
* @param lookupName - the class name with variables.
* @return The looked up class.
* @throws IllegalArgumentException If a variable or class could not be found.
*/
public static Class<?> getClass(String lookupName) {
try {
return Class.forName(lookupName);
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Cannot find " + lookupName, e);
}
}
@SuppressWarnings("deprecation")
public static Object newInstance(Class<?> clazz) {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new SecurityException("Could not create object", e);
}
}
}

Datei anzeigen

@ -0,0 +1,58 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 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 net.md_5.bungee.api.bungeepluginmanager;
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();
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);
}
}

Datei anzeigen

@ -0,0 +1,203 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 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 net.md_5.bungee.api.bungeepluginmanager;
import com.google.common.base.Preconditions;
import com.google.common.collect.Multimap;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.plugin.*;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.Constructor;
import org.yaml.snakeyaml.representer.Representer;
import java.io.File;
import java.io.InputStream;
import java.net.URLClassLoader;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Handler;
import java.util.logging.Level;
public final class PluginUtils {
private PluginUtils() {
throw new IllegalStateException("Utility class");
}
@SuppressWarnings("deprecation")
public static void unloadPlugin(Plugin plugin) {
PluginManager pluginManager = ProxyServer.getInstance().getPluginManager();
ClassLoader pluginClassLoader = plugin.getClass().getClassLoader();
try {
//call onDisable
plugin.onDisable();
//close all log handlers
for (Handler handler : plugin.getLogger().getHandlers()) {
handler.close();
}
} catch (Exception t) {
severe("Exception disabling plugin", t, plugin.getDescription().getName());
}
//unregister event handlers
pluginManager.unregisterListeners(plugin);
//unregister commands
pluginManager.unregisterCommands(plugin);
//cancel tasks
ProxyServer.getInstance().getScheduler().cancel(plugin);
//shutdown internal executor
plugin.getExecutorService().shutdownNow();
//stop all still active threads that belong to a plugin
Thread.getAllStackTraces().keySet().stream()
.filter(thread -> (thread.getClass().getClassLoader() == pluginClassLoader))
.forEach(thread -> {
try {
thread.interrupt();
thread.join(100);
if (thread.isAlive()) {
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Could not stop thread " + thread.getName() + " of plugin " + plugin.getDescription().getName() + ". Still running");
}
} catch (InterruptedException t) {
Thread.currentThread().interrupt();
}
});
//finish uncompleted intents
ModifiedPluginEventBus.completeIntents(plugin);
//remove commands that were registered by plugin not through normal means
try {
Map<String, Command> commandMap = ReflectionUtils.getFieldValue(pluginManager, "commandMap");
if (checkReflectionNotNull(commandMap, "commandMap")) {
commandMap.entrySet().removeIf(entry -> entry.getValue().getClass().getClassLoader() == pluginClassLoader);
}
} catch (Exception t) {
severe("Failed to cleanup commandMap", t, plugin.getDescription().getName());
}
//cleanup internal listener and command maps from plugin refs
try {
Map<String, Plugin> pluginsMap = ReflectionUtils.getFieldValue(pluginManager, "plugins");
Multimap<Plugin, Command> commands = ReflectionUtils.getFieldValue(pluginManager, "commandsByPlugin");
Multimap<Plugin, Listener> listeners = ReflectionUtils.getFieldValue(pluginManager, "listenersByPlugin");
if (checkReflectionNotNull(pluginsMap, "plugin")
&& checkReflectionNotNull(commands, "commandByPlugin")
&& checkReflectionNotNull(listeners, "listenersByPlugin")) {
pluginsMap.values().remove(plugin);
commands.removeAll(plugin);
listeners.removeAll(plugin);
}
} catch (Exception t) {
severe("Failed to cleanup bungee internal maps from plugin refs", t, plugin.getDescription().getName());
}
ResourceBundle.clearCache(pluginClassLoader);
//close classloader
if (pluginClassLoader instanceof URLClassLoader) {
try {
((URLClassLoader) pluginClassLoader).close();
} catch (Exception t) {
severe("Failed to close the classloader for plugin", t, plugin.getDescription().getName());
}
}
// Remove classloader
try {
Class<?> PluginClassLoader = Class.forName("net.md_5.bungee.api.plugin.PluginClassloader");
Set<?> allLoaders = ReflectionUtils.getStaticFieldValue(PluginClassLoader, "allLoaders");
Preconditions.checkNotNull(allLoaders);
allLoaders.remove(pluginClassLoader);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private static boolean checkReflectionNotNull(Object obj, String field) {
if (obj == null) {
ProxyServer.getInstance().getLogger().log(Level.SEVERE, "Could not get field {} by reflections: are you using the latest version of BungeePluginManager?", field);
return false;
}
return true;
}
@SuppressWarnings("resource")
public static boolean loadPlugin(File pluginFile) {
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
Representer representer = new Representer();
representer.getPropertyUtils().setSkipMissingProperties(true);
PluginDescription desc = new Yaml(new Constructor(PluginDescription.class), representer).loadAs(in, PluginDescription.class);
desc.setFile(pluginFile);
//check depends
Map<String, Plugin> pluginsMap = ReflectionUtils.getFieldValue(ProxyServer.getInstance().getPluginManager(), "plugins");
Preconditions.checkNotNull(pluginsMap);
for (String dependency : desc.getDepends()) {
if (!pluginsMap.containsKey(dependency)) {
ProxyServer.getInstance().getLogger().log(Level.WARNING, "{0} (required by {1}) is unavailable", new Object[]{dependency, desc.getName()});
return false;
}
}
Object libraryLoader = ReflectionUtils.getFieldValue(ProxyServer.getInstance().getPluginManager(), "libraryLoader");
//load plugin
Class<?> pluginClassLoader = Class.forName("net.md_5.bungee.api.plugin.PluginClassloader");
java.lang.reflect.Constructor<?> constructor = pluginClassLoader.getConstructor(ProxyServer.class, PluginDescription.class, File.class, ClassLoader.class);
constructor.setAccessible(true);
URLClassLoader loader = (URLClassLoader) constructor.newInstance(ProxyServer.getInstance(), desc, pluginFile, libraryLoader != null ? ReflectionUtils.invokeMethod(libraryLoader, "createLoader", desc) : null);
Class<?> mainclazz = loader.loadClass(desc.getMain());
Plugin plugin = (Plugin) mainclazz.getDeclaredConstructor().newInstance();
ReflectionUtils.invokeMethod(plugin, "init", ProxyServer.getInstance(), desc);
pluginsMap.put(desc.getName(), plugin);
plugin.onLoad();
plugin.onEnable();
return true;
}
} catch (Exception t) {
severe("Failed to load plugin", t, pluginFile.getName());
return false;
}
}
private static void severe(String message, Exception t, String pluginName) {
ProxyServer.getInstance().getLogger().log(Level.SEVERE, message + " " + pluginName, t);
}
}

Datei anzeigen

@ -0,0 +1,90 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2020 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 net.md_5.bungee.api.bungeepluginmanager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public final class ReflectionUtils {
private ReflectionUtils() {
throw new IllegalStateException("Utility class");
}
@SuppressWarnings("unchecked")
static <T> T getFieldValue(Object obj, String fieldName) {
Class<?> clazz = obj.getClass();
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(obj);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
return null;
}
public static void setFieldValue(Object obj, String fieldName, Object value) {
Class<?> clazz = obj.getClass();
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
}
@SuppressWarnings("unchecked")
static <T> T getStaticFieldValue(Class<?> clazz, String fieldName) {
do {
try {
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return (T) field.get(null);
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException error) {
// Ignored
}
} while ((clazz = clazz.getSuperclass()) != null);
return null;
}
static Object invokeMethod(Object obj, String methodName, Object... args) {
Class<?> clazz = obj.getClass();
do {
try {
for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == args.length) {
method.setAccessible(true);
return method.invoke(obj, args);
}
}
} catch (SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException error) {
// Ignore
}
} while ((clazz = clazz.getSuperclass()) != null);
throw new SecurityException("Method could not be found!");
}
}

4
src/plugin.yml Normale Datei
Datei anzeigen

@ -0,0 +1,4 @@
name: PersistentBungeeCore
main: de.steamwar.bungeecore.Persistent
version: 1.0
author: Lixfel

Datei anzeigen

@ -6,5 +6,4 @@ artifacts:
"/binarys/persistentbungeecore.jar": "build/libs/persistentbungeecore.jar"
release:
- "./gradlew release"
- "./gradlew --stop"
- "mvn deploy:deploy-file -DgroupId=de.steamwar -DartifactId=persistentbungeecore -Dversion=RELEASE -Dpackaging=jar -Dfile=build/libs/persistentbungeecore.jar -Durl=file:///var/www/html/maven/"