Merge branch 'main' into VelocityCore/SendCommand2.0

This commit is contained in:
2025-02-13 20:40:16 +01:00
195 changed files with 1897 additions and 1855 deletions
@@ -220,25 +220,22 @@ public class Subserver {
try {
if (checkpoint) {
start(process.getErrorStream(), line -> line.contains("Restore finished successfully."));
Thread.sleep(300); //Wait for port to be reopened
} else {
start(process.getInputStream(), line -> {
if (line.contains("Loading libraries, please wait"))
sendProgress(2);
else if (line.contains("Starting Minecraft server on"))
sendProgress(4);
sendProgress(5);
else if (line.contains("Preparing start region"))
sendProgress(6);
return line.contains("Finished mapping loading");
sendProgress(8);
return line.contains("Done (");
});
}
if (!started)
return;
sendProgress(8);
Thread.sleep(300);
sendProgress(10);
for (Player cachedPlayer : cachedPlayers) {
sendPlayer(cachedPlayer);
+4 -1
View File
@@ -47,6 +47,8 @@ java {
dependencies {
annotationProcessor(libs.velocityapi)
compileOnly(libs.velocity)
compileOnly(libs.viaapi)
compileOnly(libs.viavelocity)
compileOnly(project(":VelocityCore:Persistent", "default"))
@@ -61,6 +63,7 @@ dependencies {
}
implementation(libs.msgpack)
implementation(libs.apolloprotos)
implementation(libs.nbt)
}
+2 -2
View File
@@ -37,11 +37,11 @@ if __name__ == "__main__":
with open(configfile, 'r') as file:
gamemode = yaml.load(file)
builderworld = path.expanduser(f'~/builder{version}/{worldname}')
builderworld = path.expanduser(f'/worlds/builder{version}/{worldname}')
arenaworld = f'/servers/{gamemode["Server"]["Folder"]}/arenas/{worldname}'
if path.exists(arenaworld):
backupworld = path.expanduser(f'~/backup/arenas/{datetime.datetime.now()}-{worldname}-{version}.tar.xz')
backupworld = path.expanduser(f'/mnt/storage/backup/arenas/{datetime.datetime.now()}-{worldname}-{version}.tar.xz')
with tarfile.open(backupworld, 'w:xz') as tar:
tar.add(arenaworld, arcname=worldname)
@@ -369,23 +369,18 @@ R_USAGE=§8/§7r §8[§eanswer§8]
#RegelnCommand
REGELN_RULES=§7§lRules
REGELN_AS=§eAirShip §7Rules
REGELN_AS_HOVER=§7https://steamwar.de/spielmodi/airship-regelwerk/
REGELN_AS_URL=https://steamwar.de/spielmodi/airship-regelwerk/
REGELN_AS_URL=https://steamwar.de/en/rules/airship
REGELN_MWG=§eMiniWarGear §7Rules
REGELN_MWG_HOVER=§7https://steamwar.de/spielmodi/miniwargear-regelwerk/
REGELN_MWG_URL=https://steamwar.de/spielmodi/miniwargear-regelwerk/
REGELN_MWG_URL=https://steamwar.de/en/rules/miniwargear
REGELN_WG=§eWarGear §7Rules
REGELN_WG_HOVER=§7https://steamwar.de/spielmodi/wargear-regelwerk/
REGELN_WG_URL=https://steamwar.de/spielmodi/wargear-regelwerk/
REGELN_WG_URL=https://steamwar.de/en/rules/wargear
REGELN_WS=§eWarShip §7Rules
REGELN_WS_HOVER=§7https://steamwar.de/spielmodi/warship-regelwerk/
REGELN_WS_URL=https://steamwar.de/spielmodi/warship-regelwerk/
REGELN_WS_URL=https://steamwar.de/en/rules/warship
REGELN_QG=§eQuickGear §7Rules
REGELN_QG_HOVER=§7https://steamwar.de/spielmodi/quickgear-regelwerk/
REGELN_QG_URL=https://steamwar.de/spielmodi/quickgear-regelwerk/
REGELN_QG_URL=https://steamwar.de/en/rules/quickgear
REGELN_CONDUCT=§eCode of conduct
REGELN_CONDUCT_HOVER=§7https://steamwar.de/verhaltensrichtlinien/
REGELN_CONDUCT_URL=https://steamwar.de/verhaltensrichtlinien/
REGELN_CONDUCT_URL=https://steamwar.de/en/code-of-conduct
URL_FORMAT=§7{0}
#ReplayCommand
REPLAY_TITLE=Most recent fights
@@ -541,7 +536,7 @@ TP_USAGE_EVENT=§8/§7tp §8[§ePlayer §7or §eteam§8]
UNIGNORE_USAGE=§8/§7unignore §8[§eplayer§8]
UNIGNORE_NOT_PLAYER=§cThis player does not exist!
UNIGNORE_NOT_IGNORED=§cYou are not ignoring this player.
UNIGNORE_UNIGNORED=§7You ignored §e{0}§8.
UNIGNORE_UNIGNORED=§7You unignored §e{0}§8.
#WebregisterCommand
WEB_USAGE=§8/§7webpassword §8[§epassword§8]
@@ -626,6 +621,7 @@ WHOIS_ID=§7ID§8: §e{0}
WHOIS_PERMS=§7Perms§8: §7{0}
WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0}
WHOIS_JOINED_FIRST=§7Joined on§8: §e{0}
WHOIS_LAST_ONLINE=§7Last on§8: §e{0}
WHOIS_HOURS_PLAYED=§7Online Time§8: §e{0}h
WHOIS_CURRENT_PLAYED=§7Current Online Time§8: §e{0}m
WHOIS_CURRENT_SERVER=§7Current Server§8: §e{0}
@@ -728,6 +724,9 @@ MOD_ITEM_BACK=§7Back
INV_PAGE_BACK=§{0}Seite zurück
INV_PAGE_NEXT=§{0}Seite vor
#VersionAnnouncer
SERVER_VERSION=§7This server runs on Minecraft version §e{0}
#Discord
DC_UNLINKED=For this action your Discord account has to be linked to your Minecraft account. To link your accounts go onto the SteamWar Discord to the `regeln-infos` Channel and click on `Minecraft Verknüpfen`.
DC_TITLE_SCHEMINFO=Schematic Info
@@ -350,23 +350,17 @@ R_USAGE=§8/§7r §8[§eAntwort§8]
#RegelnCommand
REGELN_RULES=§7§lRegelwerke
REGELN_AS=§eAirShip§8-§7Regelwerk
REGELN_AS_HOVER=§7https://steamwar.de/spielmodi/airship-regelwerk/
REGELN_AS_URL=https://steamwar.de/spielmodi/airship-regelwerk/
REGELN_AS_URL=https://steamwar.de/regeln/airship
REGELN_MWG=§eMiniWarGear§8-§7Regelwerk
REGELN_MWG_HOVER=§7https://steamwar.de/spielmodi/miniwargear-regelwerk/
REGELN_MWG_URL=https://steamwar.de/spielmodi/miniwargear-regelwerk/
REGELN_MWG_URL=https://steamwar.de/regeln/miniwargear
REGELN_WG=§eWarGear§8-§7Regelwerk
REGELN_WG_HOVER=§7https://steamwar.de/spielmodi/wargear-regelwerk/
REGELN_WG_URL=https://steamwar.de/spielmodi/wargear-regelwerk/
REGELN_WG_URL=https://steamwar.de/regeln/wargear
REGELN_WS=§eWarShip§8-§7Regelwerk
REGELN_WS_HOVER=§7https://steamwar.de/spielmodi/warship-regelwerk/
REGELN_WS_URL=https://steamwar.de/spielmodi/warship-regelwerk/
REGELN_WS_URL=https://steamwar.de/regeln/warship
REGELN_QG=§eQuickGear§8-§7Regelwerk
REGELN_QG_HOVER=§7https://steamwar.de/spielmodi/quickgear-regelwerk/
REGELN_QG_URL=https://steamwar.de/spielmodi/quickgear-regelwerk/
REGELN_QG_URL=https://steamwar.de/regeln/quickgear
REGELN_CONDUCT=§eVerhaltensrichtlinien
REGELN_CONDUCT_HOVER=§7https://steamwar.de/verhaltensrichtlinien/
REGELN_CONDUCT_URL=https://steamwar.de/verhaltensrichtlinien/
REGELN_CONDUCT_URL=https://steamwar.de/verhaltensrichtlinien
#ReplayCommand
REPLAY_TITLE=Letzte Kämpfe
@@ -602,6 +596,7 @@ WHOIS_UUID_HOVER=§eUUID Kopieren
WHOIS_ID=§7ID§8: §e{0}
WHOIS_DISCORD_ID=§7Discord-ID§8: §e{0}
WHOIS_JOINED_FIRST=§7Beigetreten am§8: §e{0}
WHOIS_LAST_ONLINE=§7Zuletzt online§8: §e{0}
WHOIS_HOURS_PLAYED=§7Spielzeit§8: §e{0}h
WHOIS_CURRENT_PLAYED=§7Aktuell online§8: §e{0}m
WHOIS_CURRENT_SERVER=§7Aktueller Server§8: §e{0}
@@ -681,6 +676,9 @@ ADVENT_CALENDAR_OPEN=§7Du hast §e{0}§7 aus dem Adventskalender erhalten!
INV_PAGE_BACK=§{0}Page back
INV_PAGE_NEXT=§{0}Next page
#VersionAnnouncer
SERVER_VERSION=§7Dieser Server läuft auf Minecraft-Version §e{0}
#Discord
DC_UNLINKED=Für diese Aktion muss dein Minecraftaccount mit deinem Discordaccount verknüpft sein, gehe dazu auf dem SteamWar-Discord in den `regeln-infos` Channel und Klicke auf `Minecraft Verknüpfen`.
DC_TITLE_SCHEMINFO=Schematicinfo
@@ -27,10 +27,14 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@Getter
public class GameModeConfig {
private static final Pattern terminatingNumber = Pattern.compile("(\\d+)$");
public static <T extends GameModeConfig> void loadAll(Class<T> config, BiConsumer<File, T> consumer) {
File folder = new File(VelocityCore.get().getDataDirectory().getParent().toFile(), "FightSystem");
if(!folder.exists())
@@ -51,9 +55,9 @@ public class GameModeConfig {
@Getter
public static class Server {
private String Folder;
private String ServerJar;
private List<String> ChatNames = Collections.emptyList();
private List<String> Maps;
private boolean Spigot = false;
private boolean Ranked = false;
private boolean Historic = false;
}
@@ -66,8 +70,10 @@ public class GameModeConfig {
private boolean ManualCheck = true;
}
public String getServerJar() {
return getServer().getServerJar();
public ServerVersion getVersion() {
Matcher matcher = terminatingNumber.matcher(getServer().getFolder());
matcher.find();
return ServerVersion.valueOf((getServer().isSpigot() ? "SPIGOT_" : "PAPER_") + matcher.group(1));
}
public String getFolder() {
@@ -63,7 +63,7 @@ public abstract class Node {
nodes.forEach(consumer);
}
public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams);
public abstract ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams);
protected abstract ProcessBuilder prepareExecution(String... command);
protected abstract void calcLoadLimit();
@@ -95,17 +95,17 @@ public abstract class Node {
return hostname;
}
protected void constructServerstart(File directory, List<String> cmd, String serverJar, String worldDir, String levelName, int port, String xmx, String... dParams) {
protected void constructServerstart(File directory, List<String> cmd, String serverJar, String worldDir, String levelName, int port, String... dParams) {
if (JAVA_8.contains(serverJar))
cmd.add("/usr/lib/jvm/java-8-openj9-amd64/bin/java");
cmd.add("/usr/lib/jvm/openj9-8/bin/java");
else
cmd.add("/usr/lib/jvm/java-21-openj9-amd64/bin/java");
cmd.add("/usr/lib/jvm/openj9-21/bin/java");
for(String param : dParams){
cmd.add("-D" + param);
}
cmd.add("-Xshareclasses:nonfatal,name=" + directory.getName());
cmd.add("-Xmx" + xmx);
cmd.add("-Xmx768M");
cmd.addAll(OPENJ9_ARGS);
if (!JAVA_8.contains(serverJar)) {
cmd.add("--add-opens");
@@ -113,7 +113,7 @@ public abstract class Node {
cmd.add("-XX:-CRIUSecProvider");
}
cmd.add("-jar");
cmd.add("/binarys/" + serverJar);
cmd.add("/jars/" + serverJar);
cmd.add("--log-strip-color");
cmd.add("--world-dir");
cmd.add(worldDir);
@@ -142,9 +142,9 @@ public abstract class Node {
}
@Override
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams) {
List<String> cmd = new ArrayList<>();
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams);
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, dParams);
ProcessBuilder builder = new ProcessBuilder(cmd);
builder.directory(directory);
return builder;
@@ -174,7 +174,7 @@ public abstract class Node {
}
@Override
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String xmx, String... dParams) {
public ProcessBuilder startServer(String serverJar, File directory, String worldDir, String levelName, int port, String... dParams) {
List<String> cmd = new ArrayList<>();
cmd.add("ssh");
cmd.add("-L");
@@ -183,7 +183,7 @@ public abstract class Node {
cmd.add("cd");
cmd.add(directory.getPath());
cmd.add(";");
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, xmx, dParams);
constructServerstart(directory, cmd, serverJar, worldDir, levelName, port, dParams);
return new ProcessBuilder(cmd);
}
@@ -20,6 +20,8 @@
package de.steamwar.velocitycore;
import com.velocitypowered.api.proxy.Player;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.messages.Chatter;
import de.steamwar.persistent.Arenaserver;
import de.steamwar.persistent.Bauserver;
@@ -44,20 +46,23 @@ public class ServerStarter {
private static final Portrange ARENA_PORTS = VelocityCore.MAIN_SERVER ? new Portrange(3000, 3100) : (VelocityCore.get().getConfig().isEventmode() ? new Portrange(4000, 5000) : BAU_PORTS);
public static final String SERVER_PATH = "/servers/";
private static final String USER_HOME = System.getProperty("user.home") + "/";
private static final String EVENT_PATH = USER_HOME + "event/";
public static final String TEMP_WORLD_PATH = USER_HOME + "arenaserver/";
public static final String TUTORIAL_PATH = USER_HOME + "tutorials/";
public static final String WORLDS_BASE_PATH = USER_HOME + "userworlds";
public static final String BUILDER_BASE_PATH = USER_HOME + "builder";
private static final String TMP_DATA = System.getProperty("user.home") + "/";
private static final String EVENT_PATH = TMP_DATA + "event/";
public static final String TEMP_WORLD_PATH = TMP_DATA + "arenaserver/";
private static final String WORLDS_FOLDER = "/worlds";
public static final String TUTORIAL_PATH = WORLDS_FOLDER + "/tutorials/";
public static final String WORLDS_BASE_PATH = WORLDS_FOLDER + "/userworlds";
public static final String BUILDER_BASE_PATH = WORLDS_FOLDER + "/builder";
private static final String WORLDS_STORAGE_BASE_PATH = "/mnt/storage/worlds/userworlds";
private File directory = null;
private String worldDir = null;
private Node node = null;
private String serverJar = "spigot-1.15.2.jar";
private String xmx = "768M";
private ServerVersion version = ServerVersion.PAPER_20;
private Portrange portrange = BAU_PORTS;
private Function<Integer, String> serverNameProvider = port -> node.getName() + port;
private BooleanSupplier startCondition = () -> true;
@@ -78,7 +83,7 @@ public class ServerStarter {
public ServerStarter arena(ArenaMode mode, String map) {
portrange = ARENA_PORTS;
serverNameProvider = port -> mode.getGameName() + (port - portrange.start);
serverJar = mode.getServerJar();
version = mode.getVersion();
allowMerge = true;
fightMap = map;
gameMode = mode.getInternalName();
@@ -145,18 +150,24 @@ public class ServerStarter {
}
public ServerStarter build(ServerVersion version, UUID owner) {
this.version = version;
directory = version.getServerDirectory("Bau");
serverJar = version.getServerJar();
worldDir = version.getWorldFolder(WORLDS_BASE_PATH);
worldName = version != ServerVersion.SPIGOT_12 ? String.valueOf(SteamwarUser.get(owner).getId()) : owner.toString();
worldName = String.valueOf(SteamwarUser.get(owner).getId());
checkpoint = true;
build(owner);
worldSetup = () -> {
File world = new File(worldDir, worldName);
if (!world.exists())
copyWorld(node, new File(directory, "Bauwelt").getPath(), world.getPath());
if (!world.exists()) {
File storage = new File(version.getWorldFolder(WORLDS_STORAGE_BASE_PATH), worldName);
if(storage.exists())
node.execute("mv", storage.getPath(), world.getPath());
else
copyWorld(node, new File(directory, "Bauwelt").getPath(), world.getPath());
}
};
// Send players to existing server
@@ -184,6 +195,7 @@ public class ServerStarter {
}
public ServerStarter tutorial(Player owner, Tutorial tutorial) {
version = ServerVersion.SPIGOT_15;
directory = new File(SERVER_PATH, "Tutorial");
buildWithTemp(owner);
tempWorld(TUTORIAL_PATH + tutorial.getTutorialId());
@@ -219,7 +231,7 @@ public class ServerStarter {
}
public ServerStarter builder(ServerVersion version, String map, File generator) {
serverJar = version.getServerJar();
this.version = version;
directory = version.getServerDirectory("Builder");
worldDir = version.getWorldFolder(BUILDER_BASE_PATH);
worldName = map;
@@ -294,6 +306,7 @@ public class ServerStarter {
if(checkpoint)
arguments.put("checkpoint", checkpointDir.getPath());
((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(serverName, version.getProtocolVersion().getProtocol());
if(checkpoint && checkpointDir.exists()) {
try(DataOutputStream out = new DataOutputStream(Files.newOutputStream(new File(checkpointDir, "port").toPath()))) {
out.writeInt(port);
@@ -313,7 +326,7 @@ public class ServerStarter {
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)
version.getServerJar(), directory, worldDir, worldName, port, arguments.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).toArray(String[]::new)
), worldCleanup, null));
}
@@ -19,6 +19,8 @@
package de.steamwar.velocitycore;
import com.velocitypowered.api.network.ProtocolVersion;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.io.File;
@@ -27,12 +29,22 @@ import java.util.Map;
import java.util.Set;
@Getter
@AllArgsConstructor
public enum ServerVersion {
SPIGOT_12("spigot-1.12.2.jar", 12),
SPIGOT_15("spigot-1.15.2.jar", 15),
PAPER_19("paper-1.19.3.jar", 19),
PAPER_20("paper-1.20.1.jar", 20),
PAPER_21("paper-1.21.jar", 21);
SPIGOT_8("spigot-1.8.8.jar", 8, ProtocolVersion.MINECRAFT_1_8),
SPIGOT_9("spigot-1.9.4.jar", 9, ProtocolVersion.MINECRAFT_1_9),
SPIGOT_10("spigot-1.10.2.jar", 10, ProtocolVersion.MINECRAFT_1_10),
SPIGOT_12("spigot-1.12.2.jar", 12, ProtocolVersion.MINECRAFT_1_12_2),
SPIGOT_14("spigot-1.14.4.jar", 14, ProtocolVersion.MINECRAFT_1_14_4),
SPIGOT_15("spigot-1.15.2.jar", 15, ProtocolVersion.MINECRAFT_1_15_2),
PAPER_8("paper-1.8.8.jar", 8, ProtocolVersion.MINECRAFT_1_8),
PAPER_10("paper-1.10.2.jar", 10, ProtocolVersion.MINECRAFT_1_10),
PAPER_12("paper-1.12.2.jar", 12, ProtocolVersion.MINECRAFT_1_12_2),
PAPER_18("paper-1.18.2.jar", 15, ProtocolVersion.MINECRAFT_1_18_2),
PAPER_19("paper-1.19.3.jar", 19, ProtocolVersion.MINECRAFT_1_19_3),
PAPER_20("paper-1.20.1.jar", 20, ProtocolVersion.MINECRAFT_1_20),
PAPER_21("paper-1.21.3.jar", 21, ProtocolVersion.MINECRAFT_1_21_2);
private static final Map<String, ServerVersion> chatMap = new HashMap<>();
@@ -74,13 +86,20 @@ public enum ServerVersion {
return chatMap.keySet();
}
private static final Map<Integer, ServerVersion> versionMap = new HashMap<>();
static {
for(ServerVersion version : values())
versionMap.put(version.getVersionSuffix(), version);
}
public static ServerVersion get(int version) {
return versionMap.get(version);
}
private final String serverJar;
private final int versionSuffix;
ServerVersion(String serverJar, int versionSuffix) {
this.serverJar = serverJar;
this.versionSuffix = versionSuffix;
}
private final ProtocolVersion protocolVersion;
public String getWorldFolder(String base) {
return base + versionSuffix + "/";
@@ -152,6 +152,7 @@ public class VelocityCore implements ReloadablePlugin {
new BanListener();
new CheckListener();
new IPSanitizer();
new VersionAnnouncer();
local = new Node.LocalNode();
if(MAIN_SERVER) {
@@ -251,7 +252,17 @@ public class VelocityCore implements ReloadablePlugin {
@Override
public void onProxyShutdown(ProxyShutdownEvent event) {
try {
DiscordBot.withBot(bot -> bot.getJda().shutdownNow());
DiscordBot.withBot(bot -> {
bot.getJda().shutdownNow();
bot.getJda().getHttpClient().connectionPool().evictAll();
bot.getJda().getHttpClient().dispatcher().executorService().shutdown();
try {
if(!bot.getJda().awaitShutdown(1, TimeUnit.SECONDS))
logger.log(Level.SEVERE, "Could not await discord bot shutdown");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
} catch (Throwable e) {
logger.log(Level.SEVERE, "Could not shutdown discord bot", e);
}
@@ -214,7 +214,7 @@ public class BauCommand extends SWCommand {
public void delete(PlayerChatter sender, @OptionalValue(value = "", onlyUINIG = true) ServerVersion version) {
SWInventory inventory = new SWInventory(sender, 9, new Message("BAU_DELETE_GUI_NAME"));
inventory.addItem(0, new SWItem(new Message("BAU_DELETE_GUI_DELETE"), 10), click -> {
String world = version.getWorldFolder(ServerStarter.WORLDS_BASE_PATH) + (version != ServerVersion.SPIGOT_12 ? sender.user().getId() : sender.user().getUUID().toString());
String world = version.getWorldFolder(ServerStarter.WORLDS_BASE_PATH) + sender.user().getId();
VelocityCore.schedule(() -> {
Bauserver subserver = Bauserver.get(sender.user().getUUID());
@@ -90,7 +90,7 @@ public class BuilderCloudCommand extends SWCommand {
}
VelocityCore.schedule(() -> {
VelocityCore.local.execute("/binarys/deployarena.py", arenaMode.getConfig(), Integer.toString(version.getVersionSuffix()), map);
VelocityCore.local.execute("deployarena.py", arenaMode.getConfig(), Integer.toString(version.getVersionSuffix()), map);
ArenaMode.init();
sender.system("BUILDERCLOUD_DEPLOY_FINISHED");
}).schedule();
@@ -21,15 +21,21 @@ package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerInfo;
import de.steamwar.messages.Message;
import de.steamwar.velocitycore.VelocityCore;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.command.SWCommand;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.TypeMapper;
import de.steamwar.command.TypeValidator;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import de.steamwar.velocitycore.ArenaMode;
import de.steamwar.velocitycore.ServerVersion;
import de.steamwar.velocitycore.VelocityCore;
import lombok.Getter;
import java.io.File;
@@ -79,6 +85,14 @@ public class DevCommand extends SWCommand {
sender.getPlayer().createConnectionRequest(server).fireAndForget();
}
@Register(value = "reloadmodes")
public void reloadModes(Chatter sender) {
if(!sender.user().hasPerm(UserPerm.ADMINISTRATION))
return;
ArenaMode.init();
}
@ClassValidator(value = PlayerChatter.class, local = true)
public TypeValidator<PlayerChatter> punishmentGuardChecker() {
return (sender, value, messageSender) -> {
@@ -102,28 +116,32 @@ public class DevCommand extends SWCommand {
private void updateDevServers() {
String[] serverFiles = devServerDir.list();
Map<String, Integer> devServerFiles = new HashMap<>();
Map<String, Integer> devServerPorts = new HashMap<>();
Map<String, Integer> devServerVersions = new HashMap<>();
if (serverFiles != null) {
for (String serverFile : serverFiles) {
String[] server = serverFile.split("\\.");
devServerFiles.put(server[0], Integer.parseInt(server[1]));
devServerPorts.put(server[0], Integer.parseInt(server[1]));
devServerVersions.put(server[0], Integer.parseInt(server[2]));
}
}
devServers.entrySet().removeIf(entry -> {
if (!devServerFiles.containsKey(entry.getKey())) {
if (!devServerPorts.containsKey(entry.getKey())) {
VelocityCore.getProxy().unregisterServer(entry.getValue().getServerInfo());
return true;
}
return false;
});
devServerFiles.forEach((key, value) -> {
if (devServers.containsKey(key))
devServerPorts.forEach((username, value) -> {
if (devServers.containsKey(username))
return;
SteamwarUser user = SteamwarUser.get(key);
devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo("Dev " + user.getUserName(), new InetSocketAddress("127.0.0.1", value))));
SteamwarUser user = SteamwarUser.get(username);
String name = "Dev " + user.getUserName();
((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().put(name, ServerVersion.get(devServerVersions.get(username)).getProtocolVersion().getProtocol());
devServers.put(user.getUserName().toLowerCase(), VelocityCore.getProxy().registerServer(new ServerInfo(name, new InetSocketAddress("127.0.0.1", value))));
});
}
}
@@ -61,7 +61,7 @@ public class PunishmentCommand {
return null;
}
return SteamwarUser.getOrCreate(uuid, name, u -> {}, (o, n) -> {});
return SteamwarUser.getOrCreate(uuid, name, u -> {});
}
private static UUID getUUIDofOfflinePlayer(String playerName) {
@@ -36,6 +36,6 @@ public class RulesCommand extends SWCommand {
sender.system("REGELN_RULES");
for(String ruleset : Arrays.asList("REGELN_AS", "REGELN_MWG", "REGELN_WG", "REGELN_WS", "REGELN_QG", "REGELN_CONDUCT"))
sender.prefixless(ruleset, new Message(ruleset + "_HOVER"), ClickEvent.openUrl(sender.parseToPlain(ruleset + "_URL")));
sender.prefixless(ruleset, new Message("URL_FORMAT", sender.parseToPlain(ruleset + "_URL")), ClickEvent.openUrl(sender.parseToPlain(ruleset + "_URL")));
}
}
@@ -19,12 +19,10 @@
package de.steamwar.velocitycore.commands;
import de.steamwar.velocitycore.network.NetworkSender;
import de.steamwar.command.SWCommand;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.PlayerChatter;
import de.steamwar.network.packets.server.LocaleInvalidationPacket;
import java.util.Objects;
import de.steamwar.velocitycore.network.NetworkSender;
public class SetLocaleCommand extends SWCommand {
@@ -33,8 +31,8 @@ public class SetLocaleCommand extends SWCommand {
}
@Register
public void genericCommand(Chatter sender) {
sender.user().setLocale(Objects.requireNonNull(sender.getLocale()), true);
public void genericCommand(PlayerChatter sender) {
sender.user().setLocale(sender.getPlayer().getPlayerSettings().getLocale(), true);
sender.withPlayer(player -> NetworkSender.send(player, new LocaleInvalidationPacket(sender.user().getId())));
sender.system("LOCK_LOCALE_CHANGED");
}
@@ -21,10 +21,7 @@ package de.steamwar.velocitycore.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.messages.Chatter;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import de.steamwar.sql.SteamwarUser;
public class WebpasswordCommand extends SWCommand {
@@ -40,33 +37,11 @@ public class WebpasswordCommand extends SWCommand {
return;
}
ProcessBuilder pb = new ProcessBuilder("php", "/var/www/register.php", sender.user().getUserName(), password);
pb.redirectErrorStream(true);
try {
Process regProcess = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(regProcess.getInputStream()));
String errorLine;
if((errorLine = reader.readLine()) != null) {
if ("updated".equals(errorLine)) {
sender.system("WEB_UPDATED");
return;
} else {
throw new SecurityException("Could not create webaccount " + errorLine);
}
}
SteamwarUser user = sender.user();
boolean resetPW = user.hasPassword();
sender.system("WEB_CREATED");
} catch (IOException e) {
throw new SecurityException("Could not create webaccount", e);
}
}
user.setPassword(password);
public static void changeUsername(String oldUsername, String newUsername){
ProcessBuilder pb = new ProcessBuilder("php", "/var/www/changename.php", oldUsername, newUsername);
try {
pb.start();
} catch (IOException e) {
throw new SecurityException("Could not change username", e);
}
sender.system(resetPW ? "WEB_UPDATED" : "WEB_CREATED");
}
}
@@ -20,15 +20,15 @@
package de.steamwar.velocitycore.commands;
import com.velocitypowered.api.proxy.Player;
import de.steamwar.persistent.Storage;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.mods.ModUtils;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.persistent.Storage;
import de.steamwar.sql.*;
import de.steamwar.velocitycore.VelocityCore;
import de.steamwar.velocitycore.mods.ModUtils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.kyori.adventure.text.event.ClickEvent;
@@ -86,9 +86,12 @@ public class WhoisCommand extends SWCommand {
if(firstJoin == null && target != null) {
firstJoin = Storage.sessions.get(target);
}
Timestamp lastOnline = user.getLastOnline();
if(firstJoin != null)
sender.system("WHOIS_JOINED_FIRST", firstJoin.toString());
if (lastOnline != null)
sender.system("WHOIS_LAST_ONLINE", lastOnline.toString());
sender.system("WHOIS_HOURS_PLAYED", new DecimalFormat("###.##").format(onlineTime / 3600d));
if(target != null) {
@@ -100,7 +100,7 @@ public class DiscordBot {
.createDefault(config.getToken())
.setStatus(OnlineStatus.ONLINE)
.setMemberCachePolicy(MemberCachePolicy.ONLINE)
.enableIntents(GatewayIntent.MESSAGE_CONTENT)
.enableIntents(GatewayIntent.GUILD_MEMBERS, GatewayIntent.MESSAGE_CONTENT)
.build();
instance = this;
@@ -165,6 +165,7 @@ public class DiscordBot {
.setComponents(actionRows), DiscordTicketHandler::openTicket);
eventChannel = new StaticMessageChannel(config.channel("events"), EventChannel::get);
checklistChannel = new ChecklistChannel(config.channel("checklist"));
config.getCouncilThread().forEach((roleId, threadId) -> new CouncilChannel(DiscordBot.getGuild().getRoleById(roleId), DiscordBot.getGuild().getThreadChannelById(threadId)));
announcementChannel = new DiscordChannel(config.channel("announcement")) {
@Override
@@ -185,6 +186,8 @@ public class DiscordBot {
}
}).repeat(30, TimeUnit.SECONDS).schedule();
VelocityCore.schedule(CouncilChannel::updateAll).repeat(1, TimeUnit.HOURS).schedule();
jda.addEventListener(
new DiscordTicketHandler(),
new DiscordTeamEvent(),
@@ -56,6 +56,8 @@ public class DiscordConfig {
private String ticketcategory;
private Map<String, String> councilThread;
@NoArgsConstructor
public static class DiscordRole {
@@ -0,0 +1,69 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 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.velocitycore.discord.channels;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.discord.DiscordBot;
import it.unimi.dsi.fastutil.Pair;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Role;
import net.dv8tion.jda.api.entities.channel.concrete.ThreadChannel;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class CouncilChannel extends StaticMessageChannel {
private static final Set<CouncilChannel> channels = new HashSet<>();
public static void updateAll() {
channels.forEach(StaticMessageChannel::update);
}
public CouncilChannel(Role role, ThreadChannel threadChannel) {
super(threadChannel, () -> {
MessageCreateBuilder messageCreateBuilder = new MessageCreateBuilder();
messageCreateBuilder.setContent("# Ratsmitglieder");
DiscordBot.getGuild().findMembersWithRoles(role).get()
.stream()
.map(member -> {
SteamwarUser steamwarUser = SteamwarUser.get(member.getIdLong());
String name = steamwarUser == null ? member.getEffectiveName() : steamwarUser.getUserName();
UUID uuid = steamwarUser == null ? null : steamwarUser.getUUID();
return Pair.of(name, uuid);
})
.sorted(Comparator.comparing(Pair::key))
.forEach(pair -> {
messageCreateBuilder.addEmbeds(new EmbedBuilder()
.setTitle(pair.key())
.setImage(pair.value() == null ? null : "https://api.steamwar.de/data/skin/" + pair.value().toString())
.build());
});
return messageCreateBuilder;
}, event -> {});
channels.add(this);
}
}
@@ -19,11 +19,11 @@
package de.steamwar.velocitycore.discord.channels;
import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.listeners.ChannelListener;
import de.steamwar.messages.Chatter;
import de.steamwar.messages.Message;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.velocitycore.discord.DiscordBot;
import de.steamwar.velocitycore.discord.listeners.ChannelListener;
import lombok.AllArgsConstructor;
import lombok.Getter;
import net.dv8tion.jda.api.entities.User;
@@ -31,7 +31,6 @@ import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
@@ -53,7 +52,11 @@ public class DiscordChannel extends Chatter.PlayerlessChatter {
}
public DiscordChannel(String channel) {
this(SteamwarUser.get(-1), DiscordBot.getGuild().getTextChannelById(channel));
this(DiscordBot.getGuild().getTextChannelById(channel));
}
public DiscordChannel(MessageChannel channel) {
this(SteamwarUser.get(-1), channel);
ChannelListener.getChannels().put(this.channel, this);
}
@@ -21,6 +21,7 @@ package de.steamwar.velocitycore.discord.channels;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.events.interaction.component.GenericComponentInteractionCreateEvent;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageEditData;
@@ -48,7 +49,17 @@ public class StaticMessageChannel extends DiscordChannel {
super(channel);
this.supplier = supplier;
this.interaction = interaction;
init();
}
public StaticMessageChannel(MessageChannel channel, Supplier<MessageCreateBuilder> supplier, Consumer<GenericComponentInteractionCreateEvent> interaction) {
super(channel);
this.supplier = supplier;
this.interaction = interaction;
init();
}
private void init() {
if(getChannel().getLatestMessageIdLong() != 0)
message = getChannel().getIterableHistory().complete().stream().filter(m -> m.getAuthor().isBot()).findFirst().orElse(null);
@@ -25,19 +25,23 @@ import de.steamwar.sql.NodeData;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import dev.dewy.nbt.Nbt;
import dev.dewy.nbt.tags.collection.CompoundTag;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.zip.GZIPInputStream;
public class DiscordSchemUpload extends ListenerAdapter {
private static final Nbt NBT = new Nbt();
private static final List<String> SCHEM_FILE_ENDINGS = Arrays.asList(".schem", ".schematic");
@Override
@@ -79,7 +83,18 @@ public class DiscordSchemUpload extends ListenerAdapter {
node = SchematicNode.createSchematic(user.getId(), name, null);
try (InputStream in = attachment.getProxy().download().get()) {
NodeData.get(node).saveFromStream(in, fileName.substring(dot).equalsIgnoreCase(".schem"));
byte[] bytes = in.readAllBytes();
CompoundTag tags = NBT.fromStream(new DataInputStream(new GZIPInputStream(new ByteArrayInputStream(bytes))));
NodeData.SchematicFormat version = NodeData.SchematicFormat.SPONGE_V2;
if (tags.size() == 1) {
version = NodeData.SchematicFormat.SPONGE_V3;
} else if (tags.contains("Materials")) {
version = NodeData.SchematicFormat.MCEDIT;
}
NodeData.get(node).saveFromStream(new ByteArrayInputStream(bytes), version);
sender.system("DC_SCHEMUPLOAD_SUCCESS", name);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
@@ -41,12 +41,12 @@ import net.dv8tion.jda.api.interactions.components.ActionRow;
import net.dv8tion.jda.api.interactions.components.buttons.Button;
import net.dv8tion.jda.api.utils.SplitUtil;
import net.dv8tion.jda.api.utils.messages.MessageCreateBuilder;
import net.dv8tion.jda.api.utils.messages.MessageCreateData;
import net.kyori.adventure.text.event.ClickEvent;
import org.jetbrains.annotations.NotNull;
import java.awt.*;
import java.time.Instant;
import java.util.Collections;
import java.util.LinkedList;
import java.util.stream.Collectors;
@@ -112,9 +112,12 @@ public class DiscordTicketHandler extends ListenerAdapter {
.setTimestamp(Instant.now())
.setTitle(event.getChannel().getName());
User user;
if(channel.getTopic() != null && !channel.getTopic().isEmpty()) {
User user = event.getJDA().retrieveUserById(channel.getTopic()).complete();
user = event.getJDA().retrieveUserById(channel.getTopic()).complete();
embedBuilder.setAuthor(user.getName(), null, user.getAvatarUrl());
} else {
user = null;
}
TextChannel logChannel = event.getGuild().getTextChannelById(TICKET_LOG);
@@ -124,7 +127,14 @@ public class DiscordTicketHandler extends ListenerAdapter {
2000,
SplitUtil.Strategy.NEWLINE,
SplitUtil.Strategy.ANYWHERE
).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build())).forEach(builder -> logChannel.sendMessage(builder.build()).queue());
).stream().map(message -> new MessageCreateBuilder().setEmbeds(embedBuilder.setDescription(message).build()))
.forEach(builder -> {
MessageCreateData createData = builder.build();
logChannel.sendMessage(createData).queue();
if (user != null) {
user.openPrivateChannel().queue(privateChannel -> privateChannel.sendMessage(createData).queue());
}
});
Chatter.serverteam().prefixless("DISCORD_TICKET_CLOSED", channel.getName());
channel.delete().reason("Closed").queue();
@@ -39,6 +39,7 @@ import net.kyori.adventure.text.event.ClickEvent;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.function.BiConsumer;
public class ConnectionListener extends BasicListener {
@@ -56,7 +57,7 @@ public class ConnectionListener extends BasicListener {
if(!(subject instanceof Player player))
return perm -> Tristate.TRUE;
Set<UserPerm> perms = SteamwarUser.getOrCreate(player.getUniqueId(), player.getUsername(), ConnectionListener::newPlayer, WebpasswordCommand::changeUsername).perms();
Set<UserPerm> perms = SteamwarUser.getOrCreate(player.getUniqueId(), player.getUsername(), ConnectionListener::newPlayer).perms();
if(perms.contains(UserPerm.ADMINISTRATION))
return perm -> Tristate.TRUE;
else if(perms.contains(UserPerm.TEAM))
@@ -20,6 +20,7 @@
package de.steamwar.velocitycore.listeners;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PreLoginEvent;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.proxy.connection.MinecraftConnection;
@@ -32,21 +33,32 @@ import de.steamwar.velocitycore.mods.Hostname;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
public class IPSanitizer extends BasicListener {
private static final Reflection.Field<MinecraftConnection, SocketAddress> remoteAddress = new Reflection.Field<>(MinecraftConnection.class, "remoteAddress");
private static final Map<UUID, InetAddress> trueAddress = new HashMap<>(); // Will likely slightly leak over time
public static InetAddress getTrueAddress(Player player) {
return ((InetSocketAddress) ((ConnectedPlayer)player).getConnection().getChannel().remoteAddress()).getAddress();
return trueAddress.getOrDefault(player.getUniqueId(), ((InetSocketAddress) ((ConnectedPlayer)player).getConnection().getChannel().remoteAddress()).getAddress());
}
private final InetSocketAddress sanitized = new InetSocketAddress("127.127.127.127", 25565);
private static final Reflection.Field<MinecraftConnection, SocketAddress> remoteAddress = new Reflection.Field<>(MinecraftConnection.class, "remoteAddress");
private static final InetSocketAddress sanitized = new InetSocketAddress("127.127.127.127", 25565);
@Subscribe
public void loginEvent(PreLoginEvent e) {
VelocityCore.getLogger().log(Level.INFO, "%s has logged in with user name %s".formatted(e.getConnection().getRemoteAddress(), e.getUsername()));
InetSocketAddress address = e.getConnection().getRemoteAddress();
VelocityCore.getLogger().log(Level.INFO, "%s has logged in with user name %s".formatted(address, e.getUsername()));
trueAddress.put(e.getUniqueId(), address.getAddress());
remoteAddress.set(Hostname.getInitialInboundConnection((LoginInboundConnection) e.getConnection()).getConnection(), sanitized);
}
@Subscribe
public void disconnectEvent(DisconnectEvent e) {
trueAddress.remove(e.getPlayer().getUniqueId());
}
}
@@ -137,7 +137,6 @@ public class PluginMessage extends BasicListener {
"itemswapper:enableshulker", "itemswapper:enablerefill", //https://github.com/tr7zw/ItemSwapper/tree/main (Easier inventory item swapping)
"jade:show_overlay", "jade:receive_data", "jade:server_ping", "jade:server_ping_v1", //https://github.com/Snownee/Jade (Information over block/entity under crosshair)
"bclib:hello_client", "bclib:request_files", "bclib:send_files", "bclib:chunker", //https://github.com/quiqueck/BCLib (Library for additional dimensions)
"roughlyenoughitems:ci_msg", "roughlyenoughitems:request_tags_s2c", "roughlyenoughitems:og_not_enough", //https://github.com/shedaniel/RoughlyEnoughItems (Crafting recipe helper)
"essentialclient:chunkdebug", "essentialclient:clientscript", "essentialclient:gamerule", //https://github.com/senseiwells/EssentialClient (Carpet mod extension)
"couplings:server_config", //https://github.com/ChloeDawn/Couplings (Opens/closes double doors/gates simultaneously)
"yigd:grave_overview_s2c", "yigd:grave_selection_s2c", "yigd:player_selection_s2c", //https://github.com/B1n-ry/Youre-in-grave-danger (Adds new block - graves)
@@ -190,6 +189,10 @@ public class PluginMessage extends BasicListener {
"better-suggestions:entity_scores_response", "better-suggestions:entity_tags_response", //https://github.com/shurik204/better-suggestions (Better command tab completion)
"farmingforblockheads:chicken_nest_effect", "farmingforblockheads:market_categories", //https://github.com/TwelveIterationMods/FarmingForBlockheads (Improved farming with new blocks)
//https://github.com/shedaniel/RoughlyEnoughItems (Crafting recipe helper)
"roughlyenoughitems:ci_msg", "roughlyenoughitems:request_tags_s2c", "roughlyenoughitems:og_not_enough",
"roughlyenoughitems:sync_displays",
//https://modrinth.com/mod/servux
"servux:structures", "servux:entity_data", "servux:hud_metadata", "servux:debug_service",
"servux:tweaks",
@@ -0,0 +1,47 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 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.velocitycore.listeners;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.server.ServerInfo;
import com.viaversion.viaversion.api.Via;
import com.viaversion.viaversion.velocity.platform.VelocityViaConfig;
import de.steamwar.messages.Chatter;
import de.steamwar.persistent.Subserver;
public class VersionAnnouncer extends BasicListener {
@Subscribe
public void postConnect(ServerConnectedEvent e) {
ServerInfo server = e.getServer().getServerInfo();
if(!Subserver.isBuild(Subserver.getSubserver(server)))
return;
Player player = e.getPlayer();
int serverVersion = ((VelocityViaConfig) Via.getConfig()).getVelocityServerProtocols().get(server.getName());
if(Via.getAPI().getPlayerVersion(player) == serverVersion)
return;
player.sendActionBar(Chatter.of(player).parse("SERVER_VERSION", ProtocolVersion.getProtocolVersion(serverVersion).getMostRecentSupportedVersion()));
}
}
@@ -143,8 +143,10 @@ public class Tablist extends ChannelInboundHandlerAdapter {
public void onServerPostSwitch() {
if(player.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_20)) {
if(player.getProtocolVersion().greaterThan(ProtocolVersion.MINECRAFT_1_20))
if(player.getProtocolVersion().greaterThan(ProtocolVersion.MINECRAFT_1_20)) {
sendTabPacket(current, null);
current.clear();
}
sendPacket(player, createTeamPacket);
}