SteamWar/BungeeCore
Archiviert
13
2

Mod detection refactoring
Alle Prüfungen waren erfolgreich
SteamWarCI Build successful

Adding Lunar support
Fixing LabyMod support
Restricting ReplayMod
Restricting WorldDownloader
Enabling Fabric without FabricModSender
Adding logging for unknown channels

Untested.

Signed-off-by: Lixfel <agga-games@gmx.de>
Dieser Commit ist enthalten in:
Lixfel 2024-03-02 00:43:42 +01:00
Ursprung b852423442
Commit 1436069cb5
33 geänderte Dateien mit 1178 neuen und 1292 gelöschten Zeilen

Datei anzeigen

@ -59,6 +59,15 @@ repositories {
mavenCentral() mavenCentral()
maven { maven {
url 'https://m2.dv8tion.net/releases' url 'https://m2.dv8tion.net/releases'
content {
includeGroup 'net.dv8tion'
}
}
maven {
url 'https://repo.lunarclient.dev'
content {
includeGroup 'com.lunarclient'
}
} }
} }
@ -75,4 +84,7 @@ dependencies {
} }
implementation project(":CommonCore") implementation project(":CommonCore")
implementation 'com.lunarclient:apollo-api:1.1.0'
implementation 'com.lunarclient:apollo-common:1.1.0'
} }

Datei anzeigen

@ -23,11 +23,9 @@ import de.steamwar.bungeecore.bot.SteamwarDiscordBot;
import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig; import de.steamwar.bungeecore.bot.config.SteamwarDiscordBotConfig;
import de.steamwar.bungeecore.commands.*; import de.steamwar.bungeecore.commands.*;
import de.steamwar.bungeecore.listeners.*; import de.steamwar.bungeecore.listeners.*;
import de.steamwar.bungeecore.listeners.mods.*; import de.steamwar.bungeecore.mods.ServerListPing;
import de.steamwar.bungeecore.listeners.ping.PingListener; import de.steamwar.bungeecore.mods.*;
import de.steamwar.bungeecore.network.BungeeNetworkHandler; import de.steamwar.bungeecore.network.BungeeNetworkHandler;
import de.steamwar.bungeecore.network.NetworkReceiver;
import de.steamwar.bungeecore.network.SWScriptSyntaxForwarder;
import de.steamwar.bungeecore.tablist.TablistManager; import de.steamwar.bungeecore.tablist.TablistManager;
import de.steamwar.command.SWCommandUtils; import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.SWTypeMapperCreator; import de.steamwar.command.SWTypeMapperCreator;
@ -38,7 +36,6 @@ import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.Team; import de.steamwar.sql.Team;
import de.steamwar.sql.UserElo; import de.steamwar.sql.UserElo;
import de.steamwar.sql.internal.Statement; import de.steamwar.sql.internal.Statement;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@ -76,11 +73,6 @@ public class BungeeCore extends Plugin {
@Override @Override
public void onEnable(){ public void onEnable(){
getProxy().registerChannel("sw:bridge");
getProxy().registerChannel("fabricmodsender:mods");
getProxy().registerChannel("nochatreports:sync");
getProxy().registerChannel("sw:script_syntax");
setInstance(this); setInstance(this);
MAIN_SERVER = ProxyServer.getInstance().getConfig().getListeners().stream().anyMatch(info -> ((InetSocketAddress) info.getSocketAddress()).getPort() == 25565); MAIN_SERVER = ProxyServer.getInstance().getConfig().getListeners().stream().anyMatch(info -> ((InetSocketAddress) info.getSocketAddress()).getPort() == 25565);
loadConfig(); loadConfig();
@ -98,25 +90,21 @@ public class BungeeCore extends Plugin {
return tabCompleter.apply(sender, s); return tabCompleter.apply(sender, s);
} }
}); });
BungeeCord.getInstance().getScheduler().schedule(this, TabCompletionCache::invalidateOldEntries, 1, 1, TimeUnit.SECONDS); ProxyServer.getInstance().getScheduler().schedule(this, TabCompletionCache::invalidateOldEntries, 1, 1, TimeUnit.SECONDS);
new NonFabricFabricCheck(); new ServerListPing();
new PluginMessage();
new SWScriptSyntaxForwarder(); new Schematica();
new ConnectionListener();
new Forge();
new Forge12();
new LabyMod();
new Badlion(); new Badlion();
new FabricModSender();
new ReplayMod();
new FML2();
new ConnectionListener();
new ChatListener(); new ChatListener();
new BanListener(); new BanListener();
new CheckListener(); new CheckListener();
new ModLoaderBlocker();
new WorldDownloader();
new BrandListener();
new Fabric();
new SubserverProtocolFixer(); new SubserverProtocolFixer();
new PingListener();
local = new Node.LocalNode(); local = new Node.LocalNode();
if(MAIN_SERVER) { if(MAIN_SERVER) {
@ -186,7 +174,6 @@ public class BungeeCore extends Plugin {
new EventStarter(); new EventStarter();
new SessionManager(); new SessionManager();
new NetworkReceiver();
BungeeNetworkHandler.register(); BungeeNetworkHandler.register();
tablistManager = new TablistManager(); tablistManager = new TablistManager();
new SettingsChangedListener(); new SettingsChangedListener();
@ -317,9 +304,6 @@ public class BungeeCore extends Plugin {
serverName, serverName,
cmds.toArray(new String[0]) cmds.toArray(new String[0])
); );
if(server.getBoolean("modchecked", false)) {
ModLoaderBlocker.addServer(serverName);
}
} }
File discordFile = new File(System.getProperty("user.home"), "discord.yml"); File discordFile = new File(System.getProperty("user.home"), "discord.yml");

Datei anzeigen

@ -20,7 +20,6 @@
package de.steamwar.bungeecore.commands; package de.steamwar.bungeecore.commands;
import de.steamwar.bungeecore.ArenaMode; import de.steamwar.bungeecore.ArenaMode;
import de.steamwar.bungeecore.listeners.mods.ModLoaderBlocker;
import de.steamwar.command.SWCommandUtils; import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.TypeMapper; import de.steamwar.command.TypeMapper;
import de.steamwar.command.TypeValidator; import de.steamwar.command.TypeValidator;
@ -49,10 +48,6 @@ public class TypeMappers {
return false; return false;
} }
if (ModLoaderBlocker.isFabric(value)) {
messageSender.send("MODLOADER_DENIED");
return false;
}
return true; return true;
}; };
} }

Datei anzeigen

@ -21,7 +21,7 @@ package de.steamwar.bungeecore.commands;
import de.steamwar.bungeecore.Message; import de.steamwar.bungeecore.Message;
import de.steamwar.bungeecore.Storage; import de.steamwar.bungeecore.Storage;
import de.steamwar.bungeecore.listeners.mods.Utils; import de.steamwar.bungeecore.mods.ModUtils;
import de.steamwar.command.SWCommand; import de.steamwar.command.SWCommand;
import de.steamwar.command.SWCommandUtils; import de.steamwar.command.SWCommandUtils;
import de.steamwar.command.TypeMapper; import de.steamwar.command.TypeMapper;
@ -118,7 +118,7 @@ public class WhoisCommand extends SWCommand {
sender.system("WHOIS_CURRENT_SERVER", target.getServer().getInfo().getName()); sender.system("WHOIS_CURRENT_SERVER", target.getServer().getInfo().getName());
sender.system("WHOIS_CURRENT_PROTOCOL", target.getPendingConnection().getVersion()); sender.system("WHOIS_CURRENT_PROTOCOL", target.getPendingConnection().getVersion());
List<Mod> mods = Utils.playerModMap.get(user.getUUID()); List<Mod> mods = ModUtils.getPlayerModMap().get(user.getUUID());
if(mods == null) if(mods == null)
mods = Collections.emptyList(); mods = Collections.emptyList();

Datei anzeigen

@ -23,7 +23,6 @@ import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Message; import de.steamwar.bungeecore.Message;
import de.steamwar.bungeecore.commands.PunishmentCommand; import de.steamwar.bungeecore.commands.PunishmentCommand;
import de.steamwar.bungeecore.commands.WebpasswordCommand; import de.steamwar.bungeecore.commands.WebpasswordCommand;
import de.steamwar.bungeecore.listeners.mods.Forge;
import de.steamwar.messages.ChatSender; import de.steamwar.messages.ChatSender;
import de.steamwar.sql.BannedUserIPs; import de.steamwar.sql.BannedUserIPs;
import de.steamwar.sql.Punishment; import de.steamwar.sql.Punishment;
@ -57,7 +56,6 @@ public class BanListener extends BasicListener {
List<BannedUserIPs> ips = BannedUserIPs.get(connection.getAddress().getAddress().getHostAddress()); List<BannedUserIPs> ips = BannedUserIPs.get(connection.getAddress().getAddress().getHostAddress());
if(!ips.isEmpty()){ if(!ips.isEmpty()){
Timestamp highestBan = ips.get(0).getTimestamp(); Timestamp highestBan = ips.get(0).getTimestamp();
boolean perma = false; boolean perma = false;
for(BannedUserIPs banned : ips) { for(BannedUserIPs banned : ips) {
@ -74,7 +72,7 @@ public class BanListener extends BasicListener {
} }
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/ban " + user.getUserName() + " " ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/ban " + user.getUserName() + " "
+ (perma?"perma":highestBan.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy_HH:mm"))) + (perma?"perma":highestBan.toLocalDateTime().format(DateTimeFormatter.ofPattern("dd.MM.yyyy_HH:mm")))
+ " Bannumgehung"); + " Ban Evasion - Bannumgehung");
ChatSender.serverteamReceivers().forEach(sender -> sender.system( ChatSender.serverteamReceivers().forEach(sender -> sender.system(
"BAN_AVOIDING_ALERT", "BAN_AVOIDING_ALERT",
@ -89,7 +87,7 @@ public class BanListener extends BasicListener {
)); ));
} }
Forge.onServerConnected(event); event.completeIntent(BungeeCore.get());
}); });
} }
} }

Datei anzeigen

@ -1,71 +0,0 @@
/*
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 de.steamwar.bungeecore.listeners;
import de.steamwar.messages.ChatSender;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
public class BrandListener extends BasicListener {
private static boolean isLocalHost(InetAddress addr) {
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress()) {
return true;
}
try {
return NetworkInterface.getByInetAddress(addr) != null;
} catch (SocketException e) {
return false;
}
}
@EventHandler
public void onServerSwitch(PluginMessageEvent event) {
if(!event.getTag().equals("minecraft:brand") && !event.getTag().equals("MC|Brand")) {
return;
}
if (event.getReceiver() == null || isLocalHost(event.getReceiver().getAddress().getAddress())) {
return;
}
if (!(event.getReceiver() instanceof ProxiedPlayer)) {
return;
}
event.setCancelled(true);
ProxiedPlayer player = (ProxiedPlayer) event.getReceiver();
String brandString = ChatSender.of(player).parseToLegacy("STEAMWAR_BRAND", ProxyServer.getInstance().getName(), player.getServer().getInfo().getName(), new String(event.getData(), 1, event.getData().length - 1));
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString(brandString, brand);
player.sendData(event.getTag(), DefinedPacket.toArray(brand));
brand.release();
}
}

Datei anzeigen

@ -29,7 +29,7 @@ import de.steamwar.bungeecore.commands.ChallengeCommand;
import de.steamwar.bungeecore.commands.CheckCommand; import de.steamwar.bungeecore.commands.CheckCommand;
import de.steamwar.bungeecore.commands.ModCommand; import de.steamwar.bungeecore.commands.ModCommand;
import de.steamwar.bungeecore.commands.MsgCommand; import de.steamwar.bungeecore.commands.MsgCommand;
import de.steamwar.bungeecore.listeners.mods.Utils; import de.steamwar.bungeecore.mods.ModUtils;
import de.steamwar.sql.SteamwarUser; import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm; import de.steamwar.sql.UserPerm;
import net.md_5.bungee.api.AbstractReconnectHandler; import net.md_5.bungee.api.AbstractReconnectHandler;
@ -156,7 +156,7 @@ public class ConnectionListener extends BasicListener {
public void onDisconnect(PlayerDisconnectEvent e){ public void onDisconnect(PlayerDisconnectEvent e){
ChallengeCommand.remove(e.getPlayer()); ChallengeCommand.remove(e.getPlayer());
MsgCommand.remove(e.getPlayer()); MsgCommand.remove(e.getPlayer());
Utils.playerModMap.remove(e.getPlayer().getUniqueId()); ModUtils.getPlayerModMap().remove(e.getPlayer().getUniqueId());
ModCommand.playerFilterType.remove(e.getPlayer()); ModCommand.playerFilterType.remove(e.getPlayer());
} }
} }

Datei anzeigen

@ -1,97 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.listeners;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Message;
import de.steamwar.bungeecore.Storage;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class NonFabricFabricCheck extends BasicListener {
private final Set<UUID> usingFabric = new HashSet<>();
private final Set<ProxiedPlayer> checking = new HashSet<>();
private final Set<ProxiedPlayer> vanilla = new HashSet<>();
{
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), usingFabric::clear, 0, 15, TimeUnit.MINUTES);
}
@EventHandler
public void pluginMessageEvent(PluginMessageEvent e) {
Connection sender = e.getSender();
if(!(sender instanceof ProxiedPlayer))
return;
ProxiedPlayer p = (ProxiedPlayer) sender;
if (e.getTag().equals("minecraft:register") && new String(e.getData()).contains("fabric-screen-handler-api-v1:open_screen")) {
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
if (!sender.isConnected()) return;
if (!vanilla.remove(p)) return;
if (Storage.fabricCheckedPlayers.containsKey(p)) return;
p.disconnect(Message.parse("MOD_USE_MODSENDER", p));
}, 25, TimeUnit.SECONDS);
return;
}
if(!e.getTag().equals("minecraft:brand"))
return;
if(!new String(e.getData()).equals("vanilla"))
return;
vanilla.add(p);
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
if (!p.isConnected()) return;
if (Storage.fabricCheckedPlayers.containsKey(p)) return;
checking.add(p);
p.sendData("fabric-screen-handler-api-v1:open_screen", new byte[] {0});
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> checking.remove(p), 1, TimeUnit.SECONDS);
}, 30, TimeUnit.SECONDS);
}
@EventHandler
public void onPlayerPreLogin(LoginEvent e) {
if (usingFabric.remove(e.getConnection().getUniqueId())) {
e.getConnection().disconnect(Message.parse("MOD_USE_MODSENDER", Locale.getDefault()));
}
}
@EventHandler
public void onPlayerDisconnect(PlayerDisconnectEvent e) {
if (checking.remove(e.getPlayer())) {
usingFabric.add(e.getPlayer().getUniqueId());
}
vanilla.remove(e.getPlayer());
}
}

Datei anzeigen

@ -0,0 +1,177 @@
/*
* 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.bungeecore.listeners;
import com.lunarclient.apollo.ApolloManager;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.commands.TeamCommand;
import de.steamwar.bungeecore.mods.*;
import de.steamwar.bungeecore.network.ServerMetaInfo;
import de.steamwar.messages.ChatSender;
import de.steamwar.network.packets.NetworkPacket;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
public class PluginMessage extends BasicListener {
public static void send(ProxiedPlayer player, String legacyChannel, String channel, byte[] data) {
// 1.12 format change
player.sendData(player.getPendingConnection().getVersion() > 340 ? channel : legacyChannel, data);
}
//TODO change to warning level
private static final Parser UNKNOWN = event -> BungeeCore.get().getLogger().log(Level.INFO, () -> "Undefined PluginMessage on channel " + event.getTag() + " from " + event.getSender() + " received.\n" + Arrays.toString(event.getData()));
private static final Parser PASS_THROUGH = event -> event.setCancelled(false);
private static final Parser DROP = event -> {};
private final Lunar lunar = new Lunar();
private final Map<String, Parser> handlers = new HashMap<>();
public PluginMessage() {
LabyMod labyMod = new LabyMod();
FML fml = new FML();
FabricModSender fabricModSender = new FabricModSender();
WorldDownloader wdl = new WorldDownloader();
register("REGISTER", false, directional(PASS_THROUGH, this::clientRegistersChannel));
register("minecraft:register", false, directional(PASS_THROUGH, this::clientRegistersChannel));
register("BungeeCord", false, onlySWSource(PASS_THROUGH));
register("bungeecord:main", false, onlySWSource(PASS_THROUGH));
register("MC|Brand", true, directional(this::steamWarBrand, this::userBrand));
register("minecraft:brand", true, directional(this::steamWarBrand, this::userBrand));
register("sw:script_syntax", false, directional(onlySWSource(PASS_THROUGH), UNKNOWN));
register("sw:bridge", false, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo(((Server) event.getSender()).getInfo()), event.getData()))), UNKNOWN));
register("fabricmodsender:mods", true, directional(UNKNOWN, fabricModSender::handlePluginMessage));
register("WDL|REQUEST", false, DROP);
register("wdl:request", false, DROP);
register("WDL|INIT", true, directional(UNKNOWN, wdl::handlePluginMessage));
register("wdl:init", true, directional(UNKNOWN, wdl::handlePluginMessage));
register(ApolloManager.PLUGIN_MESSAGE_CHANNEL, true, async(lunar::handlePluginMessage));
register("LMC", true, directional(UNKNOWN, async(labyMod::handlePluginMessage)));
register("labymod3:main", true, directional(UNKNOWN, async(labyMod::handlePluginMessage)));
register(FML.CHANNEL, true, directional(UNKNOWN, fml::handlePluginMessage));
//litematica/malilib https://github.com/maruohon/litematica/issues/75 https://github.com/maruohon/malilib/blob/liteloader_1.12.2/src/main/java/malilib/network/message/ConfigLockPacketHandler.java#L65
}
@EventHandler
public void onPluginMessage(PluginMessageEvent event) {
event.setCancelled(true);
BungeeCore.get().getLogger().log(Level.INFO, event + "\n" + new String(event.getData()) + "\n" + Arrays.toString(event.getData())); //TODO remove logging
try {
handlers.getOrDefault(event.getTag(), UNKNOWN).handle(event);
} catch (Exception e) {
throw new SecurityException("PluginMessage handling exception: " + event + "\n" + Arrays.toString(event.getData()), e);
}
}
private void register(String channel, boolean clientSideRegister, Parser handler) {
handlers.put(channel, handler);
if(clientSideRegister)
ProxyServer.getInstance().registerChannel(channel);
}
private void clientRegistersChannel(PluginMessageEvent event) {
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
for(String channel : new String(event.getData()).split("\0")) {
if(channel.equals(ApolloManager.PLUGIN_MESSAGE_CHANNEL))
lunar.sendRestrictions(player);
if(!handlers.containsKey(channel))
//TODO change to warning level
BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " registered unknown channel " + channel);
}
PASS_THROUGH.handle(event);
}
private void userBrand(PluginMessageEvent event) {
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
String brand = new String(event.getData());
if(brand.equals("vanilla")) {
// nothing to do
} else if(brand.startsWith("lunarclient:")) {
lunar.sendRestrictions(player);
} else {
//TODO change to warning level
BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " joined with unknown brand " + brand);
}
PASS_THROUGH.handle(event);
}
private void steamWarBrand(PluginMessageEvent event) {
ProxiedPlayer player = (ProxiedPlayer) event.getReceiver();
String brandString = ChatSender.of(player).parseToLegacy("STEAMWAR_BRAND", ProxyServer.getInstance().getName(), player.getServer().getInfo().getName(), new String(event.getData(), 1, event.getData().length - 1));
ByteBuf brand = ByteBufAllocator.DEFAULT.heapBuffer();
DefinedPacket.writeString(brandString, brand);
player.sendData(event.getTag(), DefinedPacket.toArray(brand));
brand.release();
}
private Parser directional(Parser fromServer, Parser fromPlayer) {
return event -> {
if(event.getSender() instanceof ProxiedPlayer)
fromPlayer.handle(event);
else
fromServer.handle(event);
};
}
private Parser onlySWSource(Parser parser) {
return event -> {
if(TeamCommand.isLocalhost(((InetSocketAddress) event.getSender().getSocketAddress()).getAddress()))
parser.handle(event);
else
UNKNOWN.handle(event);
};
}
private Parser async(Parser parser) {
return event -> ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> parser.handle(event));
}
private interface Parser {
void handle(PluginMessageEvent event);
}
}

Datei anzeigen

@ -1,31 +0,0 @@
package de.steamwar.bungeecore.listeners.mods;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.event.EventHandler;
public class Badlion extends BasicListener {
@EventHandler
public void onPostLogin(PostLoginEvent event) {
/*
{
"modsDisallowed": {
"Clear Glass":{"disabled":true},
"ClearWater":{"disabled":true},
"FOV Changer":{"disabled":true},
"Hitboxes":{"disabled":true},
"MiniMap":{"disabled":true},
"MLG Cobweb":{"disabled":true},
"Replay":{"disabled":true},
"Schematica":{"disabled":true},
"ToggleSneak":{"disabled":true},
"ToggleSprint":{"disabled":true},
"TNT Time":{"disabled":true}
}
}
*/
event.getPlayer().sendData("badlion:mods", ("{\"Clear Glass\":{\"disabled\":true},\"ClearWater\":{\"disabled\":true},\"FOV Changer\":{\"disabled\":true},\"Hitboxes\":{\"disabled\":true},\"LevelHead\":{\"disabled\":true},\"MiniMap\":{\"disabled\":true},\"MLG Cobweb\":{\"disabled\":true},\"Replay\":{\"disabled\":true},\"Schematica\":{\"disabled\":true},\"ToggleSneak\":{\"disabled\":true},\"ToggleSprint\":{\"disabled\":true},\"TNT Time\":{\"disabled\":true}}").getBytes());
}
}

Datei anzeigen

@ -1,193 +0,0 @@
/*
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 de.steamwar.bungeecore.listeners.mods;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Storage;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import de.steamwar.sql.SWException;
import de.steamwar.sql.SteamwarUser;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.event.EventHandler;
import java.nio.charset.StandardCharsets;
import java.nio.charset.UnsupportedCharsetException;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Fabric extends BasicListener {
public static void remove(ProxiedPlayer player) {
Storage.fabricCheckedPlayers.remove(player);
synchronized (Storage.fabricExpectPluginMessage) {
Storage.fabricExpectPluginMessage.remove(player);
}
}
private static final HashSet<String> ppCircumventerList = new HashSet<>();
static {
ppCircumventerList.add("java");
ppCircumventerList.add("minecraft");
ppCircumventerList.add("org_joml_joml");
ppCircumventerList.add("steamwarmodsender");
}
private static final Set<String> neededMods = new HashSet<>();
static {
neededMods.add("java");
neededMods.add("minecraft");
neededMods.add("fabricloader");
neededMods.add("steamwarmodsender");
}
{
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
synchronized (Storage.fabricExpectPluginMessage) {
for (Map.Entry<ProxiedPlayer, Long> entry : Storage.fabricExpectPluginMessage.entrySet()) {
if (!Storage.fabricCheckedPlayers.containsKey(entry.getKey())) {
continue;
}
if (System.currentTimeMillis() - entry.getValue() > TimeUnit.SECONDS.toMillis(20)) {
logMessage(SteamwarUser.get(entry.getKey().getUniqueId()), "Expected message not received", String.valueOf(entry.getValue()));
Storage.fabricExpectPluginMessage.remove(entry.getKey());
return;
}
}
}
}, 0, 1, TimeUnit.SECONDS);
}
@EventHandler
public void onPluginMessageEvent(PluginMessageEvent e){
if(!e.getTag().equals("fabricmodsender:mods"))
return;
if (!(e.getSender() instanceof ProxiedPlayer)) {
return;
}
ProxiedPlayer player = (ProxiedPlayer) e.getSender();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
byte[] data = e.getData();
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
synchronized (Storage.fabricExpectPluginMessage) {
if (Storage.fabricExpectPluginMessage.containsKey(player)) {
logMessage(user, "Was not fabric checked but send message nonetheless", Arrays.toString(data));
return;
}
}
}
Storage.fabricExpectPluginMessage.remove(player);
List<Mod> mods = new ArrayList<>();
Utils.VarInt varInt = Utils.readVarInt(data,0);
if(data.length != varInt.length + varInt.value) {
logMessage(user, "Invalid message length", Arrays.toString(data));
return;
}
data = Arrays.copyOfRange(data,varInt.length, data.length);
String dataString;
try{
dataString = new String(data, StandardCharsets.UTF_8);
}catch (UnsupportedCharsetException exception) {
logMessage(user, "Unsupported charset", Arrays.toString(data));
return;
}
JsonArray array;
try {
array = JsonParser.parseString(dataString).getAsJsonArray();
}catch (JsonSyntaxException exception) {
logMessage(user, "Invalid json", dataString);
return;
}
for(JsonElement mod : array) {
mods.add(Mod.getOrCreate(mod.getAsString(), Mod.Platform.FABRIC));
}
boolean neededMods = neededModsContained(mods);
if(!neededMods) {
logMessage(user, "Needed mods are not contained", dataString);
return;
}
if(ppCircumventerCheck(mods))
logMessage(user, "PP circumventer suspicion", dataString);
if(!Utils.handleMods(player,mods))
return;
if (Storage.fabricCheckedPlayers.containsKey(player)) {
long current = Storage.fabricCheckedPlayers.get(player);
if (current != dataString.hashCode()) {
logMessage(user, "Mods changed during runtime", dataString);
return;
}
} else {
Storage.fabricCheckedPlayers.put(player, dataString.hashCode());
}
Storage.fabricPlayers.remove(player);
}
@EventHandler
public void onServerSwitchEvent(ServerSwitchEvent e) {
if (e.getFrom() == null) return;
synchronized (Storage.fabricExpectPluginMessage) {
Storage.fabricExpectPluginMessage.put(e.getPlayer(), System.currentTimeMillis());
}
}
private boolean neededModsContained(List<Mod> mods) {
return mods.stream()
.map(Mod::getModName)
.filter(neededMods::contains)
.count() == neededMods.size();
}
private void logMessage(SteamwarUser user, String reason, String data) {
SWException.log("FabricModSender " + user.getUserName() + ": " + reason, data);
}
private boolean ppCircumventerCheck(List<Mod> mods) {
for(Mod mod : mods) {
String name = mod.getModName();
if(!name.startsWith("fabric") && !ppCircumventerList.contains(name))
return false;
}
return true;
}
}

Datei anzeigen

@ -1,147 +0,0 @@
/*
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 de.steamwar.bungeecore.listeners.mods;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import io.netty.channel.ChannelPipeline;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
public class Forge extends BasicListener {
private static final String WRAPPER = "fml:loginwrapper";
private static final Field initialHandlerCh;
static{
try {
initialHandlerCh = InitialHandler.class.getDeclaredField("ch");
} catch (NoSuchFieldException e) {
throw new SecurityException("Could not initialize Reflection", e);
}
initialHandlerCh.setAccessible(true);
}
public static void onServerConnected(LoginEvent event) {
if(event.getConnection().getVersion() < 341 || event.getConnection().getVersion() > 763) { //1.13 - 1.20.1
event.completeIntent(BungeeCore.get());
return;
}
//fml:handshake without mods, channels and registries
//for more information see https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
event.getConnection().unsafe().sendPacket(new LoginPayloadRequest(1, WRAPPER, new byte[]{13,102,109,108,58,104,97,110,100,115,104,97,107,101,4,1,0,0,0}));
InitialHandler handler = (InitialHandler) event.getConnection();
ChannelWrapper wrapper;
try{
wrapper = (ChannelWrapper) initialHandlerCh.get(handler);
} catch (IllegalAccessException e) {
BungeeCore.get().getLogger().log(Level.SEVERE, "Could not get Channel", e);
event.completeIntent(BungeeCore.get());
return;
}
ChannelPipeline pipeline = wrapper.getHandle().pipeline();
if(pipeline != null) {
HandlerBoss handlerBoss = pipeline.get(HandlerBoss.class);
if(handlerBoss != null)
handlerBoss.setHandler(new CustomPacketHandler(event));
}
}
private static class CustomPacketHandler extends PacketHandler {
private final LoginEvent event;
public CustomPacketHandler(LoginEvent event) {
this.event = event;
}
@Override
public String toString() {
return "SteamWar Forge Handler";
}
@Override
public void handle(LoginPayloadResponse response){
byte[] data = response.getData();
if(data == null) {
event.completeIntent(BungeeCore.get());
return;
}
//for more information see https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
Utils.VarInt channelLength = Utils.readVarInt(data, 0);
int pos = channelLength.length;
if(!new String(data, pos, channelLength.value).equals("fml:handshake")) {
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x00)"));
return;
}
pos += channelLength.value;
Utils.VarInt length = Utils.readVarInt(data, pos);
pos += length.length;
if(channelLength.length + channelLength.value + length.length + length.value != data.length) {
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x01)"));
return;
}
Utils.VarInt packetId = Utils.readVarInt(data, pos);
pos += packetId.length;
if(packetId.value != 2) {
event.getConnection().disconnect(TextComponent.fromLegacyText("Invalid forge registry response (0x02)"));
return;
}
Utils.VarInt modCount = Utils.readVarInt(data, pos);
pos += modCount.length;
List<Mod> mods = new ArrayList<>();
for(int i = 0; i < modCount.value; i++) {
Utils.VarInt nameLength = Utils.readVarInt(data, pos);
pos += nameLength.length;
mods.add(Mod.getOrCreate(new String(data, pos, nameLength.value), Mod.Platform.FORGE));
pos += nameLength.value;
}
PendingConnection connection = event.getConnection();
if(!Utils.handleMods(connection.getUniqueId(), Locale.getDefault(), event::setCancelReason, mods)) {
event.setCancelled(true);
}
event.completeIntent(BungeeCore.get());
}
}
}

Datei anzeigen

@ -1,113 +0,0 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2022 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.listeners.mods;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.UnpooledByteBufAllocator;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.event.EventHandler;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Forge12 extends BasicListener {
private static final String FMLHS = "FML|HS";
private static final byte[] REGISTER;
private static final byte[] HELLO = new byte[]{0, 2, 0, 0, 0, 0};
private static final Set<UUID> unlocked = new HashSet<>();
static {
ByteBuf buf = UnpooledByteBufAllocator.DEFAULT.directBuffer(7);
buf.writeByte(6);
buf.writeCharSequence(FMLHS, StandardCharsets.UTF_8);
REGISTER = new byte[buf.readableBytes()];
buf.readBytes(REGISTER);
}
@EventHandler
public void onPostLogin(PostLoginEvent event) {
ProxiedPlayer player = event.getPlayer();
synchronized (unlocked) {
if(unlocked.contains(player.getUniqueId())){
unlocked.remove(player.getUniqueId());
return;
}
}
if(player.getPendingConnection().getVersion() <= 340) {
player.sendData("REGISTER", REGISTER); //1.12-
player.sendData(FMLHS, HELLO);
}
}
@EventHandler
public void onPluginMessageEvent(PluginMessageEvent e){
if(!e.getTag().equals(FMLHS))
return;
e.setCancelled(true);
byte[] data = e.getData();
Connection sender = e.getSender();
if(!(sender instanceof ProxiedPlayer))
return;
ProxiedPlayer p = (ProxiedPlayer) sender;
if (data[0] == 2) {
Utils.VarInt numMods = Utils.readVarInt(data, 1);
List<Mod> mods = new LinkedList<>();
int bytePos = 1 + numMods.length;
for (int i = 0; i < numMods.value; i++) {
byte[] name = Arrays.copyOfRange(data, bytePos + 1, bytePos + data[bytePos] + 1);
bytePos += 1 + data[bytePos];
//Version information is unused
bytePos += 1 + data[bytePos];
mods.add(Mod.getOrCreate(new String(name), Mod.Platform.FORGE));
}
if (Utils.handleMods(p, mods)) {
synchronized (unlocked) {
unlocked.add(p.getUniqueId());
}
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(),
() -> p.disconnect(BungeeCore.stringToText("§7Deine installierten Mods wurden überprüft\n§aDu kannst nun §eSteam§8War §abetreten")),
2, TimeUnit.SECONDS);
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
synchronized (unlocked) {
unlocked.remove(p.getUniqueId());
}
}, 30, TimeUnit.SECONDS);
}
}
}
}

Datei anzeigen

@ -1,184 +0,0 @@
/*
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 de.steamwar.bungeecore.listeners.mods;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonReader;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class LabyMod extends BasicListener {
@EventHandler
public void onPluginMessageEvent(PluginMessageEvent event){
if(!event.getTag().equals("LMC"))
return;
Connection sender = event.getSender();
if(!(sender instanceof ProxiedPlayer))
return;
event.setCancelled(true);
updateGameInfo((ProxiedPlayer) sender);
byte[] data = event.getData();
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> runAsync(data, (ProxiedPlayer) sender));
}
private void runAsync(byte[] data, ProxiedPlayer player) {
VarString purpose = readString(data, 0);
if(!"INFO".equals(purpose.value))
return;
VarString value = readString(data, purpose.length);
List<Mod> mods = new LinkedList<>();
try{
InfoPacket info = new InfoPacket(value.value);
for(InfoPacket.Addon addon : info.addons) {
mods.add(Mod.getOrCreate(addon.name, Mod.Platform.LABYMOD));
}
}catch(IOException e){
BungeeCore.log("Could not read JSON", e);
}
Utils.handleMods(player, mods);
}
private VarString readString(byte[] array, int startPos){
Utils.VarInt varInt = Utils.readVarInt(array, startPos);
startPos += varInt.length;
return new VarString(varInt.value+varInt.length, new String(Arrays.copyOfRange(array, startPos, startPos + varInt.value), StandardCharsets.UTF_8));
}
private void updateGameInfo(ProxiedPlayer proxiedPlayer) {
JsonObject obj = new JsonObject();
obj.addProperty("hasGame", true);
obj.addProperty("game_mode", "steamwar.de");
obj.addProperty("game_startTime", 0);
obj.addProperty("game_endTime", 0);
String output = "{ \"hasGame\" : \"true\", \"game_mode\" : \"steamwar.de\", \"game_startTime\" : \"0\", \"game_endTime\" : \"0\" }";
proxiedPlayer.sendData("LMC", output.getBytes());
}
private static class VarString{
private final int length;
private final String value;
private VarString(int length, String value) {
this.length = length;
this.value = value;
}
}
private static class InfoPacket{
String version = null;
Feature ccp = null;
Feature shadow = null;
List<Addon> addons = new LinkedList<>();
InfoPacket(String input) throws IOException {
JsonReader reader = new JsonReader(new StringReader(input));
reader.beginObject();
while(reader.hasNext()){
String name = reader.nextName();
switch(name){
case "version":
version = reader.nextString();
break;
case "ccp":
ccp = new Feature(reader);
break;
case "shadow":
shadow = new Feature(reader);
break;
case "addons":
reader.beginArray();
while(reader.hasNext()){
addons.add(new Addon(reader));
}
reader.endArray();
break;
default:
reader.skipValue();
}
}
reader.endObject();
reader.close();
}
static class Addon{
UUID uuid = null;
String name = null;
Addon(JsonReader reader) throws IOException {
reader.beginObject();
while(reader.hasNext()){
String n = reader.nextName();
if(n.equals("uuid"))
try{
uuid = UUID.fromString(reader.nextString());
}catch(IllegalArgumentException ignored){
//ignored
}
else if(n.equals("name"))
name = reader.nextString();
else
reader.skipValue();
}
reader.endObject();
}
}
static class Feature{
boolean enabled;
int version;
Feature(JsonReader reader) throws IOException {
reader.beginObject();
while(reader.hasNext()){
String name = reader.nextName();
if(name.equals("version"))
version = reader.nextInt();
else if(name.equals("enabled"))
enabled = reader.nextBoolean();
else
reader.skipValue();
}
reader.endObject();
}
}
}
}

Datei anzeigen

@ -1,87 +0,0 @@
/*
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 de.steamwar.bungeecore.listeners.mods;
import de.steamwar.bungeecore.*;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.event.EventHandler;
import java.util.HashSet;
import java.util.Set;
public class ModLoaderBlocker extends BasicListener {
private static final Set<String> BLOCKED_SERVER = new HashSet<>();
@EventHandler
public void onPluginMessageEvent(PluginMessageEvent e){
Connection sender = e.getSender();
if(!(sender instanceof ProxiedPlayer))
return;
ProxiedPlayer p = (ProxiedPlayer) sender;
if (e.getTag().equals("lunarclient:pm")) {
p.disconnect(Message.parseToComponent("MOD_LOADER_LUNAR_CLIENT", false, p));
return;
}
if(!e.getTag().equals("minecraft:brand"))
return;
String brand = new String(e.getData());
if(brand.contains("fabric") || brand.contains("quilt") || brand.contains("LiteLoader")){
if (!Storage.fabricCheckedPlayers.containsKey(p)) {
Storage.fabricPlayers.add(p);
}
} else if (brand.contains("lunar")) {
p.disconnect(Message.parseToComponent("MOD_LOADER_LUNAR_CLIENT", false, p));
}
}
@EventHandler
public void onDisconnect(PlayerDisconnectEvent e){
Fabric.remove(e.getPlayer());
Storage.fabricPlayers.remove(e.getPlayer());
}
@EventHandler
public void onServerSwitch(ServerSwitchEvent event) {
if(((Subserver.getSubserver(event.getPlayer()) != null
&& Subserver.getSubserver(event.getPlayer()).getType() == Servertype.ARENA)
|| BLOCKED_SERVER.contains(event.getPlayer().getServer().getInfo().getName()))
&& isFabric(event.getPlayer())) {
event.getPlayer().connect(BungeeCore.get().getProxy().getServerInfo(BungeeCore.LOBBY_SERVER));
Message.send("MODLOADER_DENIED", event.getPlayer());
}
}
public static boolean isFabric(ProxiedPlayer player) {
return Storage.fabricPlayers.contains(player);
}
public static void addServer(String server) {
BLOCKED_SERVER.add(server);
}
}

Datei anzeigen

@ -1,33 +0,0 @@
package de.steamwar.bungeecore.listeners.mods;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import net.md_5.bungee.api.connection.Connection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import java.util.Collections;
import java.util.Set;
public class WorldDownloader extends BasicListener {
private static final Set<String> wdlTags = Collections.unmodifiableSet(
Sets.newHashSet("WDL|INIT", "wdl:init", "WDL|REQUEST", "wdl:request")
);
@EventHandler
public void onPluginMessageEvent(PluginMessageEvent event){
if(!wdlTags.contains(event.getTag()))
return;
Connection sender = event.getSender();
if(!(sender instanceof ProxiedPlayer))
return;
event.setCancelled(true);
Utils.handleMods((ProxiedPlayer) sender, Lists.newArrayList(Mod.getOrCreate("wdl", Mod.Platform.FORGE)));
}
}

Datei anzeigen

@ -1,32 +0,0 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2022 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.listeners.ping;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.event.EventHandler;
public class PingListener extends BasicListener {
@EventHandler
public void onPing(ProxyPingEvent event) {
event.setResponse(new SteamWarServerPing(event.getResponse(), event.getConnection().getVersion()));
}
}

Datei anzeigen

@ -1,90 +0,0 @@
/*
This file is a part of the SteamWar software.
Copyright (C) 2022 SteamWar.de-Serverteam
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.listeners.ping;
import net.md_5.bungee.api.ServerPing;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class SteamWarServerPing extends ServerPing {
private final boolean preventsChatReports = true;
private final ForgeData forgeData;
public SteamWarServerPing(ServerPing existing, int version) {
super(existing.getVersion(), existing.getPlayers(), existing.getDescriptionComponent(), existing.getFaviconObject());
forgeData = new ForgeData(version);
}
private static class ForgeData {
private final List<ForgeChannel> channels = new ArrayList<>();
private final List<ForgeMod> mods = new ArrayList<>();
private final int fmlNetworkVersion = 2;
public ForgeData(int versionNumber) {
channels.add(new ForgeChannel("minecraft:unregister"));
channels.add(new ForgeChannel("minecraft:register"));
channels.add(new ForgeChannel("fml:handshake"));
mods.add(new ForgeMod("minecraft", ProtocolVersion.getVersion(versionNumber)));
mods.add(new ForgeMod("forge", "ANY"));
}
public final static class ProtocolVersion {
private static final HashMap<Integer, String> versions;
static {
versions = new HashMap();
versions.put(757, "1.18");
versions.put(756, "1.17.1");
versions.put(754, "1.16.5");
versions.put(578, "1.15.2");
versions.put(498, "1.14.1");
versions.put(393, "1.13");
}
public static String getVersion(int version) {
return versions.get(version);
}
}
private static class ForgeChannel {
private final String res;
private final String version = "FML2";
private final boolean required = true;
private ForgeChannel(String res) {
this.res = res;
}
}
private static class ForgeMod {
private final String modId;
private final String modmarker;
private ForgeMod(String modId, String modmarker) {
this.modId = modId;
this.modmarker = modmarker;
}
}
}
}

Datei anzeigen

@ -0,0 +1,57 @@
/*
* 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.bungeecore.mods;
import com.google.gson.JsonObject;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.event.EventHandler;
public class Badlion extends BasicListener {
// https://github.com/BadlionClient/BadlionClientModAPI
private final byte[] packet;
public Badlion() { //TODO check if working or (json) modsDisallowed wrapper necessary
JsonObject disabled = new JsonObject();
disabled.addProperty("disabled", true);
JsonObject json = new JsonObject();
json.add("Clear Glass", disabled);
json.add("ClearWater", disabled);
json.add("FOV Changer", disabled);
json.add("Hitboxes", disabled);
json.add("LevelHead", disabled);
json.add("MiniMap", disabled);
json.add("MLG Cobweb", disabled);
//json.add("Replay", disabled); //TODO check if ReplayMod restrictions work
json.add("Schematica", disabled);
json.add("ToggleSneak", disabled);
json.add("ToggleSprint", disabled);
json.add("TNT Time", disabled);
packet = json.toString().getBytes();
}
@EventHandler
public void onPostLogin(PostLoginEvent event) {
event.getPlayer().sendData("badlion:mods", packet);
}
}

Datei anzeigen

@ -0,0 +1,94 @@
/*
* 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.bungeecore.mods;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class FML extends BasicListener {
// https://wiki.vg/Minecraft_Forge_Handshake#FML_protocol_.281.7_-_1.12.29
public static final String CHANNEL = "FML|HS";
private final byte[] helloPacket = new byte[]{
/* Packet type: ServerHello */ 0,
/* FML protocol version */ 2,
/* Override dimension (int) */ 0, 0, 0, 0
};
private static final Set<UUID> unlocked = new HashSet<>();
@EventHandler
public void onPostLogin(PostLoginEvent event) {
ProxiedPlayer player = event.getPlayer();
synchronized (unlocked) {
if(unlocked.contains(player.getUniqueId())){
unlocked.remove(player.getUniqueId());
return;
}
}
if(((InitialHandler)player.getPendingConnection()).getHandshake().getHost().endsWith("\0FML\0")) {
player.sendData(CHANNEL, helloPacket);
}
}
public void handlePluginMessage(PluginMessageEvent event) {
ProxiedPlayer p = (ProxiedPlayer) event.getSender();
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
if (buf.readByte() == /* ModList */ 2) {
int numMods = DefinedPacket.readVarInt(buf);
List<Mod> mods = new ArrayList<>();
for(int i = 0; i < numMods; i++) {
String name = DefinedPacket.readString(buf);
DefinedPacket.readString(buf); // version
mods.add(Mod.getOrCreate(name, Mod.Platform.FORGE));
}
if (ModUtils.handleMods(p, mods)) {
synchronized (unlocked) {
unlocked.add(p.getUniqueId());
}
p.disconnect(BungeeCore.stringToText("§7Deine installierten Mods wurden überprüft\n§aDu kannst nun §eSteam§8War §abetreten"));
ProxyServer.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
synchronized (unlocked) {
unlocked.remove(p.getUniqueId());
}
}, 30, TimeUnit.SECONDS);
}
}
}
}

Datei anzeigen

@ -0,0 +1,151 @@
/*
* 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.bungeecore.mods;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.connection.InitialHandler;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.netty.ChannelWrapper;
import net.md_5.bungee.netty.HandlerBoss;
import net.md_5.bungee.netty.PacketHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import net.md_5.bungee.protocol.packet.LoginPayloadRequest;
import net.md_5.bungee.protocol.packet.LoginPayloadResponse;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
public class FML2 extends BasicListener {
// https://wiki.vg/Minecraft_Forge_Handshake#FML2_protocol_.281.13_-_Current.29
public static boolean isFML2(PendingConnection connection) {
return ((InitialHandler)connection).getHandshake().getHost().endsWith("\0FML2\0");
}
private final Field initialHandlerCh;
public FML2() {
try {
initialHandlerCh = InitialHandler.class.getDeclaredField("ch");
} catch (NoSuchFieldException e) {
throw new SecurityException("Could not initialize Reflection", e);
}
initialHandlerCh.setAccessible(true);
}
//TODO current identifier is \0FORGE and fmlNetworkVersion 0 ?
//TODO links for current implementation (if current checker not working)
//https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/ServerStatusPing.java
//https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkContext.java#L26
//https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/tasks/ForgeNetworkConfigurationHandler.java#L20
//https://github.com/MinecraftForge/MinecraftForge/blob/1.20.x/src/main/java/net/minecraftforge/network/NetworkRegistry.java#L177
@EventHandler
public void onLogin(LoginEvent event) {
PendingConnection connection = event.getConnection();
if(!isFML2(connection))
return;
try {
((ChannelWrapper) initialHandlerCh.get(connection)).getHandle().pipeline().get(HandlerBoss.class).setHandler(new FML2LoginHandler(event));
} catch (IllegalAccessException e) {
BungeeCore.get().getLogger().log(Level.SEVERE, "Could not get Channel", e);
return;
}
event.registerIntent(BungeeCore.get());
connection.unsafe().sendPacket(new LoginPayloadRequest(1, "fml:loginwrapper", new byte[] {
/* fml:handshake */ 13,102,109,108,58,104,97,110,100,115,104,97,107,101,
/* Packet length */ 4,
/* Type mod list */ 1,
/* Mod count */ 0,
/* Channel count */ 0,
/* Registry count */ 0
}));
}
private static class FML2LoginHandler extends PacketHandler {
private final LoginEvent event;
public FML2LoginHandler(LoginEvent event) {
this.event = event;
}
@Override
public String toString() {
return "SteamWar FML2 Handler";
}
@Override
public void handle(LoginPayloadResponse response) {
byte[] data = response.getData();
if(data == null) {
abort(response, "Not FML2 client");
return;
}
ByteBuf buf = Unpooled.wrappedBuffer(data);
if(!DefinedPacket.readString(buf).equals("fml:handshake")) {
abort(response, "Not FML2 handshake response");
return;
}
int packetLength = DefinedPacket.readVarInt(buf);
if(packetLength != buf.readableBytes()) {
abort(response, "FML2 packet size mismatch");
return;
}
if(DefinedPacket.readVarInt(buf) != /* Mod List Reply */ 2) {
abort(response, "FML2 no mod list reply");
return;
}
List<Mod> mods = new ArrayList<>();
int modCount = DefinedPacket.readVarInt(buf);
for(int i = 0; i < modCount; i++)
mods.add(Mod.getOrCreate(DefinedPacket.readString(buf), Mod.Platform.FORGE));
if(!ModUtils.handleMods(event.getConnection().getUniqueId(), Locale.getDefault(), event::setReason, mods))
event.setCancelled(true);
event.completeIntent(BungeeCore.get());
}
private void abort(LoginPayloadResponse response, String error) {
event.setReason(TextComponent.fromLegacy(error));
event.setCancelled(true);
event.completeIntent(BungeeCore.get());
BungeeCore.get().getLogger().log(Level.SEVERE, () -> error + "\n" + response);
}
}
}

Datei anzeigen

@ -0,0 +1,141 @@
/*
* 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.bungeecore.mods;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Storage;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.Mod;
import de.steamwar.sql.SWException;
import de.steamwar.sql.SteamwarUser;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.protocol.DefinedPacket;
import java.util.*;
import java.util.concurrent.TimeUnit;
public class FabricModSender extends BasicListener {
private final Set<String> neededMods = new HashSet<>();
public FabricModSender() {
neededMods.add("java");
neededMods.add("minecraft");
neededMods.add("fabricloader");
neededMods.add("steamwarmodsender");
BungeeCord.getInstance().getScheduler().schedule(BungeeCore.get(), () -> {
synchronized (Storage.fabricExpectPluginMessage) {
for (Map.Entry<ProxiedPlayer, Long> entry : Storage.fabricExpectPluginMessage.entrySet()) {
if (!Storage.fabricCheckedPlayers.containsKey(entry.getKey())) {
continue;
}
if (System.currentTimeMillis() - entry.getValue() > TimeUnit.SECONDS.toMillis(20)) {
Storage.fabricExpectPluginMessage.remove(entry.getKey());
return;
}
}
}
}, 0, 1, TimeUnit.SECONDS);
}
public void handlePluginMessage(PluginMessageEvent e){
ProxiedPlayer player = (ProxiedPlayer) e.getSender();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
synchronized (Storage.fabricExpectPluginMessage) {
if (Storage.fabricExpectPluginMessage.containsKey(player)) {
logMessage(user, "Was not fabric checked but send message nonetheless", Arrays.toString(e.getData()));
return;
}
}
}
Storage.fabricExpectPluginMessage.remove(player);
List<Mod> mods = new ArrayList<>();
ByteBuf buf = Unpooled.wrappedBuffer(e.getData());
String data = DefinedPacket.readString(buf, 1024*1024);
if(buf.readableBytes() > 0) {
logMessage(user, "Invalid message length", Arrays.toString(e.getData()));
return;
}
JsonArray array = JsonParser.parseString(data).getAsJsonArray();
for(JsonElement mod : array) {
mods.add(Mod.getOrCreate(mod.getAsString(), Mod.Platform.FABRIC));
}
if(!neededModsContained(mods)) {
logMessage(user, "Needed mods are not contained", data);
return;
}
if(!ModUtils.handleMods(player,mods))
return;
if (!Storage.fabricCheckedPlayers.containsKey(player)) {
Storage.fabricCheckedPlayers.put(player, data.hashCode());
} else if (Storage.fabricCheckedPlayers.get(player) != data.hashCode()) {
logMessage(user, "Mods changed during runtime", data);
}
}
@EventHandler
public void onServerSwitchEvent(ServerSwitchEvent e) {
if (e.getFrom() == null) return;
synchronized (Storage.fabricExpectPluginMessage) {
Storage.fabricExpectPluginMessage.put(e.getPlayer(), System.currentTimeMillis());
}
}
@EventHandler
public void onDisconnect(PlayerDisconnectEvent e) {
ProxiedPlayer player = e.getPlayer();
Storage.fabricCheckedPlayers.remove(player);
synchronized (Storage.fabricExpectPluginMessage) {
Storage.fabricExpectPluginMessage.remove(player);
}
}
private boolean neededModsContained(List<Mod> mods) {
return mods.stream()
.map(Mod::getModName)
.filter(neededMods::contains)
.count() == neededMods.size();
}
private void logMessage(SteamwarUser user, String reason, String data) {
SWException.log("FabricModSender " + user.getUserName() + ": " + reason, data);
}
}

Datei anzeigen

@ -0,0 +1,83 @@
/*
* 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.bungeecore.mods;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.steamwar.sql.Mod;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.protocol.DefinedPacket;
import java.util.LinkedList;
import java.util.List;
public class LabyMod {
// https://docs.labymod.net/pages/server/introduction/
// https://github.com/LabyMod/labymod-server-api
// https://dl.labymod.net/addons.json
private final byte[] gameInfoPacket;
public LabyMod() {
ByteBuf buf = Unpooled.buffer();
DefinedPacket.writeString("discord_rpc", buf);
JsonObject json = new JsonObject();
json.addProperty("hasGame", true);
json.addProperty("game_mode", "steamwar.de");
json.addProperty("game_startTime", 0);
json.addProperty("game_endTime", 0);
DefinedPacket.writeString(json.toString(), buf);
gameInfoPacket = new byte[buf.readableBytes()];
buf.readBytes(gameInfoPacket);
}
public void handlePluginMessage(PluginMessageEvent event) {
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
player.sendData(event.getTag(), gameInfoPacket);
ByteBuf buf = Unpooled.wrappedBuffer(event.getData());
String purpose = DefinedPacket.readString(buf);
if(!"INFO".equals(purpose))
return;
JsonObject message = JsonParser.parseString(DefinedPacket.readString(buf)).getAsJsonObject();
List<Mod> mods = new LinkedList<>();
for(JsonElement element : message.getAsJsonArray("addons")) {
JsonObject addon = element.getAsJsonObject();
mods.add(Mod.getOrCreate(addon.get("name").getAsString(), Mod.Platform.LABYMOD));
}
if(message.has("mods")) {
for(JsonElement element : message.getAsJsonArray("mods")) {
JsonObject addon = element.getAsJsonObject();
//TODO observer, FORGE and FABRIC mods available, do they always and with .jar? (would equal new mod platform)
//mods.add(Mod.getOrCreate(addon.get("name").getAsString().replace(".jar", ""), Mod.Platform.FORGE));
}
}
ModUtils.handleMods(player, mods);
}
}

Datei anzeigen

@ -0,0 +1,132 @@
/*
* 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.bungeecore.mods;
import com.lunarclient.apollo.ApolloManager;
import com.lunarclient.apollo.libs.protobuf.Any;
import com.lunarclient.apollo.libs.protobuf.InvalidProtocolBufferException;
import com.lunarclient.apollo.libs.protobuf.Message;
import com.lunarclient.apollo.mods.impl.*;
import com.lunarclient.apollo.module.ApolloModuleManager;
import com.lunarclient.apollo.module.ApolloModuleManagerImpl;
import com.lunarclient.apollo.module.modsetting.ModSettingModule;
import com.lunarclient.apollo.network.NetworkOptions;
import com.lunarclient.apollo.option.Options;
import com.lunarclient.apollo.player.AbstractApolloPlayer;
import com.lunarclient.apollo.player.v1.ModMessage;
import com.lunarclient.apollo.player.v1.PlayerHandshakeMessage;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.sql.Mod;
import lombok.AllArgsConstructor;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import java.util.logging.Level;
public class Lunar {
// https://lunarclient.dev/apollo/introduction
// https://github.com/LunarClient/Apollo
private final ApolloModuleManager manager = new ApolloModuleManagerImpl().addModule(ModSettingModule.class);
public Lunar() {
Options modSettings = manager.getModule(ModSettingModule.class).getOptions();
//modSettings.set(ModReplaymod.ENABLED, false); // TODO check if restrictions working
modSettings.set(ModFreelook.ENABLED, false);
modSettings.set(ModHypixelMod.ENABLED, false);
modSettings.set(ModMinimap.ENABLED, false);
modSettings.set(ModNametag.ENABLED, false);
modSettings.set(ModTeamView.ENABLED, false);
modSettings.set(ModTntCountdown.ENABLED, false);
modSettings.set(ModToggleSneak.TOGGLE_SNEAK_CONTAINER, false);
}
public void sendRestrictions(ProxiedPlayer player) {
NetworkOptions.sendOptions(manager.getModules(), true, new SWApolloPlayer(player));
}
public void handlePluginMessage(PluginMessageEvent event) {
ProxiedPlayer player = (ProxiedPlayer) event.getSender();
Any packet;
try {
packet = Any.parseFrom(event.getData());
} catch (InvalidProtocolBufferException e) {
throw new SecurityException(e);
}
handle(PlayerHandshakeMessage.class, packet, handshake -> {
List<Mod> mods = new ArrayList<>();
for(ModMessage mod : handshake.getInstalledModsList()) {
switch(mod.getType()) {
case TYPE_FABRIC_INTERNAL:
case TYPE_FORGE_INTERNAL:
// Controlled with ModSettings
break;
case TYPE_FABRIC_EXTERNAL:
mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FABRIC));
break;
case TYPE_FORGE_EXTERNAL:
mods.add(Mod.getOrCreate(mod.getName(), Mod.Platform.FORGE));
break;
case TYPE_UNSPECIFIED:
case UNRECOGNIZED:
default:
BungeeCore.get().getLogger().log(Level.INFO, () -> player.getName() + " uses Lunar mod with unknown type " + mod);
break;
}
}
ModUtils.handleMods(player, mods);
});
}
private <T extends Message> void handle(Class<T> type, Any packet, Consumer<T> handler) {
try {
handler.accept(packet.unpack(type));
} catch (InvalidProtocolBufferException ignored) { /*ignored*/ }
}
@AllArgsConstructor
private static class SWApolloPlayer extends AbstractApolloPlayer {
private final ProxiedPlayer player;
@Override
public void sendPacket(Message message) {
sendPacket(Any.pack(message).toByteArray());
}
@Override
public void sendPacket(byte[] bytes) {
player.sendData(ApolloManager.PLUGIN_MESSAGE_CHANNEL, bytes);
}
@Override public UUID getUniqueId() { return player.getUniqueId(); }
@Override public String getName() { return player.getName(); }
@Override public boolean hasPermission(String s) { return player.hasPermission(s); }
@Override public Object getPlayer() { return player; }
}
}

Datei anzeigen

@ -1,23 +1,23 @@
/* /*
This file is a part of the SteamWar software. * 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/>.
*/
Copyright (C) 2020 SteamWar.de-Serverteam package de.steamwar.bungeecore.mods;
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.listeners.mods;
import de.steamwar.bungeecore.BungeeCore; import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.Message; import de.steamwar.bungeecore.Message;
@ -27,6 +27,8 @@ import de.steamwar.messages.ChatSender;
import de.steamwar.sql.Mod; import de.steamwar.sql.Mod;
import de.steamwar.sql.Mod.ModType; import de.steamwar.sql.Mod.ModType;
import de.steamwar.sql.UserPerm; import de.steamwar.sql.UserPerm;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -39,35 +41,17 @@ import java.util.function.Consumer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class Utils { @UtilityClass
public class ModUtils {
public static final Map<UUID,List<Mod>> playerModMap = new HashMap<>(); @Getter
private static final Map<UUID,List<Mod>> playerModMap = new HashMap<>();
private Utils(){} public static boolean handleMods(ProxiedPlayer player, List<Mod> mods) {
static VarInt readVarInt(byte[] array, int startPos) {
int numRead = 0;
int result = 0;
byte read;
do {
read = array[startPos + numRead];
int value = (read & 0b01111111);
result |= (value << (7 * numRead));
numRead++;
if (numRead > 5) {
break;
}
} while ((read & 0b10000000) != 0);
return new VarInt(numRead, result);
}
static boolean handleMods(ProxiedPlayer player, List<Mod> mods) {
return handleMods(player.getUniqueId(), ChatSender.of(player).getLocale(), player::disconnect, mods); return handleMods(player.getUniqueId(), ChatSender.of(player).getLocale(), player::disconnect, mods);
} }
static boolean handleMods(UUID uuid, Locale locale, Consumer<BaseComponent[]> disconnect, List<Mod> mods){ public static boolean handleMods(UUID uuid, Locale locale, Consumer<BaseComponent> disconnect, List<Mod> mods){
SteamwarUser user = SteamwarUser.get(uuid); SteamwarUser user = SteamwarUser.get(uuid);
playerModMap.put(uuid,new ArrayList<>(mods)); playerModMap.put(uuid,new ArrayList<>(mods));
@ -101,17 +85,7 @@ public class Utils {
BungeeCore.log(Level.SEVERE, user.getUserName() + " " + user.getId() + " wurde automatisch wegen der Mods " + modList + " gebannt."); BungeeCore.log(Level.SEVERE, user.getUserName() + " " + user.getId() + " wurde automatisch wegen der Mods " + modList + " gebannt.");
} }
disconnect.accept(TextComponent.fromLegacyText(message)); disconnect.accept(TextComponent.fromLegacy(message));
return false; return false;
} }
static class VarInt{
final int length;
final int value;
VarInt(int length, int value){
this.length = length;
this.value = value;
}
}
} }

Datei anzeigen

@ -0,0 +1,71 @@
/*
* 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.bungeecore.mods;
import de.steamwar.bungeecore.Bauserver;
import de.steamwar.bungeecore.Subserver;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.bungeecore.listeners.PluginMessage;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.event.EventHandler;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Arrays;
public class ReplayMod extends BasicListener {
// https://gist.github.com/Johni0702/2547c463e51f65f312cb
// https://github.com/ReplayMod/replay-restrictions/blob/master/bungeecord/src/main/java/de/johni0702/replay/restrictions/BungeeCordPlugin.java
private final byte[] restrict;
private final byte[] unlock;
public ReplayMod() {
restrict = generatePacket(true);
unlock = generatePacket(false);
}
@EventHandler
public void onPlayerJoin(ServerSwitchEvent event) {
ProxiedPlayer player = event.getPlayer();
Subserver server = Subserver.getSubserver(player.getServer().getInfo());
PluginMessage.send(
player, "Replay|Restrict", "replaymod:restrict",
(server instanceof Bauserver && ((Bauserver) server).getOwner().equals(player.getUniqueId())) ? unlock : restrict
);
}
private byte[] generatePacket(boolean restrict) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
for(String restriction : Arrays.asList("no_xray", "no_noclip", "only_first_person", "only_recording_player")) {
byte[] bytes = restriction.getBytes();
stream.write(bytes.length);
stream.write(bytes);
stream.write(restrict ? 1 : 0);
}
} catch (IOException e) {
throw new SecurityException(e);
}
return stream.toByteArray();
}
}

Datei anzeigen

@ -0,0 +1,40 @@
/*
* 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.bungeecore.mods;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.event.EventHandler;
public class Schematica extends BasicListener {
// https://github.com/Lunatrius/SchematicaPlugin/blob/master/src/main/java/com/github/lunatrius/schematica/plugin/SchematicaPlugin.java
private final byte[] packet = new byte[] {
/* ProtocolVersion? */ 0,
/* PERM_PRINTER */ 1,
/* PERM_SAVE */ 0,
/* PERM_LOAD */ 1
};
@EventHandler
public void onPostLogin(PostLoginEvent event) {
event.getPlayer().sendData("schematica", packet);
}
}

Datei anzeigen

@ -0,0 +1,119 @@
/*
* 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.bungeecore.mods;
import com.google.gson.*;
import de.steamwar.bungeecore.listeners.BasicListener;
import lombok.AllArgsConstructor;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.ServerPing;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import net.md_5.bungee.protocol.ProtocolConstants;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class ServerListPing extends BasicListener implements JsonSerializer<ServerPing>, JsonDeserializer<ServerPing> {
// https://github.com/Aizistral-Studios/No-Chat-Reports/discussions/206
// https://github.com/Aizistral-Studios/No-Chat-Reports/wiki/How-to-Get-Safe-Server-Status
// https://wiki.vg/Minecraft_Forge_Handshake#Changes_to_Server_List_Ping_2
private final Gson gson;
private final Map<Integer, String> versionMap = new HashMap<>();
private final FML2Channel[] fml2Channels = new FML2Channel[]{new FML2Channel("minecraft:register"), new FML2Channel("minecraft:unregister"), new FML2Channel("fml:handshake")};
private final Map<ServerPing, PendingConnection> connections = new ConcurrentHashMap<>();
public ServerListPing() {
BungeeCord bungeeCord = BungeeCord.getInstance();
gson = bungeeCord.gson;
try {
Field gsonField = BungeeCord.class.getDeclaredField("gson");
gsonField.setAccessible(true);
gsonField.set(bungeeCord, gson.newBuilder().registerTypeAdapter(ServerPing.class, this).create());
for(Field version : ProtocolConstants.class.getFields()) {
String name = version.getName();
if(version.getType() != int.class || !name.startsWith("MINECRAFT_"))
continue;
versionMap.put(version.getInt(null), name.substring(10).replace('_', '.'));
}
} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
throw new SecurityException("Failed to inject ServerListPing", e);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPing(ProxyPingEvent event) {
connections.put(event.getResponse(), event.getConnection());
connections.values().removeIf(connection -> !connection.isConnected()); // Prevent long term leaks
}
@Override
public JsonElement serialize(ServerPing ping, Type type, JsonSerializationContext context) {
JsonElement element = gson.toJsonTree(ping, type);
JsonObject object = element.getAsJsonObject();
object.addProperty("preventsChatReports", true);
PendingConnection connection = connections.remove(ping);
if(FML2.isFML2(connection)) {
object.add("forgeData", gson.toJsonTree(new FML2Data(fml2Channels, new FML2Mod[]{
new FML2Mod("forge", "ANY"),
new FML2Mod("minecraft", versionMap.get(connection.getVersion()))
}), FML2Data.class));
}
return element;
}
@Override
public ServerPing deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
return gson.fromJson(element, ServerPing.class);
}
@AllArgsConstructor
private static class FML2Data {
private final int fmlNetworkVersion = 2;
private final FML2Channel[] channels;
private final FML2Mod[] mods;
}
@AllArgsConstructor
private static class FML2Channel {
private final String res;
private final String version = "FML2";
private final boolean required = true;
}
@AllArgsConstructor
private static class FML2Mod {
private final String modId;
private final String modmarker;
}
}

Datei anzeigen

@ -0,0 +1,56 @@
/*
* 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.bungeecore.mods;
import de.steamwar.bungeecore.listeners.PluginMessage;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PluginMessageEvent;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class WorldDownloader {
private final byte[] controlPacket;
public WorldDownloader() {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(stream);
try {
out.writeInt(1); // basic data packet
out.writeBoolean(false); // General download enabled
out.writeInt(-1); // Save radius
out.writeBoolean(false); // Chunk caching enabled
out.writeBoolean(false); // Entity saving enabled
out.writeBoolean(false); // Tile entity saving disabled
out.writeBoolean(false); // Container saving disabled
} catch (IOException e) {
throw new SecurityException("Could not create AntiWDL packet", e);
}
controlPacket = stream.toByteArray();
}
public void handlePluginMessage(PluginMessageEvent event) {
PluginMessage.send((ProxiedPlayer) event.getSender(), "WDL|CONTROL", "wdl:control", controlPacket);
}
}

Datei anzeigen

@ -1,58 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.network;
import de.steamwar.bungeecore.BungeeCore;
import de.steamwar.bungeecore.commands.TeamCommand;
import de.steamwar.bungeecore.listeners.BasicListener;
import de.steamwar.sql.SWException;
import de.steamwar.network.packets.NetworkPacket;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
public class NetworkReceiver extends BasicListener {
private static final List<String> blockedTags = Arrays.asList("bungeecord:main", "BungeeCord", "sw:bridge");
@EventHandler(priority = EventPriority.HIGHEST)
public void onPluginMessage(PluginMessageEvent event) {
if (blockedTags.contains(event.getTag()) && !TeamCommand.isLocalhost(((InetSocketAddress) event.getSender().getSocketAddress()).getAddress())) {
SWException.log(((InetSocketAddress) event.getSender().getSocketAddress()).getHostString() + " tried to send a plugin message with tag " + event.getTag(), Base64.getEncoder().encodeToString(event.getData()));
event.setCancelled(true);
return;
}
if(!event.getTag().equals("sw:bridge"))
return;
event.setCancelled(true);
if(!(event.getSender() instanceof Server))
return;
ProxyServer.getInstance().getScheduler().runAsync(BungeeCore.get(), () -> NetworkPacket.handle(new ServerMetaInfo(((Server) event.getSender()).getInfo()), event.getData()));
}
}

Datei anzeigen

@ -1,48 +0,0 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bungeecore.network;
import de.steamwar.bungeecore.commands.TeamCommand;
import de.steamwar.bungeecore.listeners.BasicListener;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.net.InetSocketAddress;
public class SWScriptSyntaxForwarder extends BasicListener {
@EventHandler(priority = EventPriority.HIGHEST)
public void onPluginMessage(PluginMessageEvent event) {
if (!event.getTag().equals("sw:script_syntax")) {
return;
}
event.setCancelled(true);
if (!(event.getSender() instanceof Server)) {
return;
}
if (!TeamCommand.isLocalhost(((InetSocketAddress) event.getSender().getSocketAddress()).getAddress())) {
return;
}
((ProxiedPlayer) event.getReceiver()).sendData("sw:script_syntax", event.getData());
}
}

Datei anzeigen

@ -20,9 +20,6 @@ DISABLED=§cCurrently disabled.
SERVER_START_OVERLOAD=§cServer start cancelled due to overload. Please try again later. SERVER_START_OVERLOAD=§cServer start cancelled due to overload. Please try again later.
#ModLoader blocker
MODLOADER_DENIED=§cYou cannot join arenas with LiteLoader or Fabric without the FabricModSender https://steamwar.de/downloads installed.
#Help command #Help command
HELP_LOBBY=§7Return from anywhere to the lobby using §8/§el§7! HELP_LOBBY=§7Return from anywhere to the lobby using §8/§el§7!
HELP_LOBBY_HOVER=§eBack to the lobby HELP_LOBBY_HOVER=§eBack to the lobby
@ -118,10 +115,6 @@ MOD_RED_PLUR=Attempted use of mods:\n{0}
MOD_YELLOW_SING=§7Deactivate the mod §e{0}§7 to continue playing on §eSteam§8War§7. MOD_YELLOW_SING=§7Deactivate the mod §e{0}§7 to continue playing on §eSteam§8War§7.
MOD_YELLOW_PLUR=§7Deactivate the mods\n§e{0}\n§7to continue playing on §eSteam§8War§7. MOD_YELLOW_PLUR=§7Deactivate the mods\n§e{0}\n§7to continue playing on §eSteam§8War§7.
MOD_LOADER_LUNAR_CLIENT=§eLunar Client§7 is not supported on §eSteam§8War§7.
MOD_USE_MODSENDER=§cPlease use the §c§lFabricModSender§c (https://steamwar.de/downloads/) or remove the mod that is rebranding your installation.
#Various commands #Various commands
ALERT=§f{0} ALERT=§f{0}
STAT_SERVER=§7Server §e{0}§8: §7Below limit §e{1} §7Server count §e{2} STAT_SERVER=§7Server §e{0}§8: §7Below limit §e{1} §7Server count §e{2}

Datei anzeigen

@ -16,9 +16,6 @@ DISABLED=§cDerzeit deaktiviert.
SERVER_START_OVERLOAD=§cDer Serverstart wurde aufgrund von Überlastung abgebrochen. Versuche es später erneut. SERVER_START_OVERLOAD=§cDer Serverstart wurde aufgrund von Überlastung abgebrochen. Versuche es später erneut.
#ModLoader blocker
MODLOADER_DENIED=§cMit LiteLoader oder Fabric kannst du keinen Arenen ohne den FabricModSender https://steamwar.de/downloads beitreten.
#Help command #Help command
HELP_LOBBY=§7Kehre von überall mit §8/§el §7zur Lobby zurück! HELP_LOBBY=§7Kehre von überall mit §8/§el §7zur Lobby zurück!
HELP_LOBBY_HOVER=§eZurück zur Lobby HELP_LOBBY_HOVER=§eZurück zur Lobby
@ -103,10 +100,6 @@ MOD_RED_PLUR=Versuchte Benutzung der Mods:\n{0}
MOD_YELLOW_SING=§7Deaktiviere den Mod §e{0}§7, um weiter auf §eSteam§8War §7spielen zu können. MOD_YELLOW_SING=§7Deaktiviere den Mod §e{0}§7, um weiter auf §eSteam§8War §7spielen zu können.
MOD_YELLOW_PLUR=§7Deaktiviere die Mods\n§e{0}\n§7um weiter auf §eSteam§8War §7spielen zu können. MOD_YELLOW_PLUR=§7Deaktiviere die Mods\n§e{0}\n§7um weiter auf §eSteam§8War §7spielen zu können.
MOD_LOADER_LUNAR_CLIENT=§eLunar Client§7 ist auf §eSteam§8War§7 nicht unterstützt.
MOD_USE_MODSENDER=§cBitte nutze den §c§lFabricModSender§c (https://steamwar.de/downloads/) oder entferne den Mod, der deine Fabric-Installation tarnt.
#Various commands #Various commands
STAT_SERVER=§7Server §e{0}§8: §7Startfähig §e{1} §7Serveranzahl §e{2} STAT_SERVER=§7Server §e{0}§8: §7Startfähig §e{1} §7Serveranzahl §e{2}