Mirror von
https://github.com/PaperMC/Paper.git
synchronisiert 2024-11-15 04:20:04 +01:00
Apply a few more patches
Signed-off-by: Mariell Hoversholm <proximyst@proximyst.com>
Dieser Commit ist enthalten in:
Ursprung
648fec34e4
Commit
35487dbfcc
Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist
@ -5,7 +5,7 @@ Subject: [PATCH] Build system changes
|
||||
|
||||
|
||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||
index fddf2f440356425d948f40dcf9d9853a374ddc8e..332930391943da8b1601401f70e13f076b205e7c 100644
|
||||
index fddf2f440356425d948f40dcf9d9853a374ddc8e..32fee49011b630407d6fd1c66838a833a706741a 100644
|
||||
--- a/build.gradle.kts
|
||||
+++ b/build.gradle.kts
|
||||
@@ -15,21 +15,24 @@ repositories {
|
||||
@ -32,7 +32,7 @@ index fddf2f440356425d948f40dcf9d9853a374ddc8e..332930391943da8b1601401f70e13f07
|
||||
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.7.0")
|
||||
|
||||
+ implementation("co.aikar:cleaner:1.0-SNAPSHOT") // Paper
|
||||
+ implementation("io.netty:netty-all:4.1.50-Final") // Paper
|
||||
+ implementation("io.netty:netty-all:4.1.65.Final") // Paper
|
||||
+
|
||||
testImplementation("junit:junit:4.13.1")
|
||||
testImplementation("org.hamcrest:hamcrest-library:1.3")
|
||||
|
@ -7,7 +7,7 @@ Loads each yml file for early init too so it can be used for early options
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d05eeaa711a09bb121b530654821894e795ff4ea
|
||||
index 0000000000000000000000000000000000000000..94cc5b494cdbc163fb70d0f4a6708d6ca2f42288
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java
|
||||
@@ -0,0 +1,286 @@
|
||||
@ -227,7 +227,7 @@ index 0000000000000000000000000000000000000000..d05eeaa711a09bb121b530654821894e
|
||||
+ ChunkPos chunk = new ChunkPos(e.xChunk, e.zChunk);
|
||||
+ info.left++;
|
||||
+ info.right.put(chunk, info.right.getOrDefault(chunk, 0) + 1);
|
||||
+ if (!chunkProviderServer.isInEntityTickingChunk(e)) {
|
||||
+ if (!chunkProviderServer.isPositionTicking(e)) {
|
||||
+ nonEntityTicking.merge(key, Integer.valueOf(1), Integer::sum);
|
||||
+ }
|
||||
+ });
|
||||
@ -243,7 +243,7 @@ index 0000000000000000000000000000000000000000..d05eeaa711a09bb121b530654821894e
|
||||
+ sender.sendMessage("Entity: " + name + " Total Ticking: " + (info.getLeft() - nonTicking) + ", Total Non-Ticking: " + nonTicking);
|
||||
+ info.getRight().entrySet().stream()
|
||||
+ .sorted((a, b) -> !a.getValue().equals(b.getValue()) ? b.getValue() - a.getValue() : a.getKey().toString().compareTo(b.getKey().toString()))
|
||||
+ .limit(10).forEach(e -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isEntityTickingChunk(e.getKey()) ? " (Ticking)" : " (Non-Ticking)")));
|
||||
+ .limit(10).forEach(e -> sender.sendMessage(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")));
|
||||
+ } else {
|
||||
+ List<Pair<ResourceLocation, Integer>> info = list.entrySet().stream()
|
||||
+ .filter(e -> names.contains(e.getKey()))
|
||||
@ -563,11 +563,11 @@ index 0000000000000000000000000000000000000000..b31109d2dadd29e8852468c19265066b
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
|
||||
index 9366b5551047e87e455fafbf45be5fb145aa875b..5d83a8d4c69144219219877c521c364d912d2452 100644
|
||||
index 1707449cbbfa5eab585657cdde811b34a92e1d17..c8385460701395cb5c65fba41335469ffb2d9b9a 100644
|
||||
--- a/src/main/java/net/minecraft/server/Main.java
|
||||
+++ b/src/main/java/net/minecraft/server/Main.java
|
||||
@@ -95,6 +95,12 @@ public class Main {
|
||||
DedicatedServerSettings dedicatedserversettings = new DedicatedServerSettings(iregistrycustom_dimension, optionset); // CraftBukkit - CLI argument support
|
||||
@@ -101,6 +101,12 @@ public class Main {
|
||||
DedicatedServerSettings dedicatedserversettings = new DedicatedServerSettings(optionset); // CraftBukkit - CLI argument support
|
||||
|
||||
dedicatedserversettings.forceSave();
|
||||
+ // Paper start - load config files for access below if needed
|
||||
@ -576,10 +576,10 @@ index 9366b5551047e87e455fafbf45be5fb145aa875b..5d83a8d4c69144219219877c521c364d
|
||||
+ org.bukkit.configuration.file.YamlConfiguration paperConfiguration = loadConfigFile((File) optionset.valueOf("paper-settings"));
|
||||
+ // Paper end
|
||||
+
|
||||
java.nio.file.Path java_nio_file_path1 = Paths.get("eula.txt");
|
||||
Eula eula = new Eula(java_nio_file_path1);
|
||||
Path path1 = Paths.get("eula.txt");
|
||||
Eula eula = new Eula(path1);
|
||||
|
||||
@@ -236,6 +242,20 @@ public class Main {
|
||||
@@ -251,6 +257,20 @@ public class Main {
|
||||
|
||||
}
|
||||
|
||||
@ -601,10 +601,10 @@ index 9366b5551047e87e455fafbf45be5fb145aa875b..5d83a8d4c69144219219877c521c364d
|
||||
Main.LOGGER.info("Forcing world upgrade! {}", session.getLevelId()); // CraftBukkit
|
||||
WorldUpgrader worldupgrader = new WorldUpgrader(session, dataFixer, worlds, eraseCache);
|
||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 2228f83f251851aa683f739ac5ce2ec98f059f3f..23d6f803eafa78fd51ea4cdc4ca25c78661bc80b 100644
|
||||
index 7bad75bd86fcb484e253fca8077d017d3161158b..fe83f13d71f84591f5506e1c6b9dfbf9fba680bd 100644
|
||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -184,6 +184,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@@ -193,6 +193,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
org.spigotmc.SpigotConfig.init((java.io.File) options.valueOf("spigot-settings"));
|
||||
org.spigotmc.SpigotConfig.registerCommands();
|
||||
// Spigot end
|
||||
@ -621,44 +621,45 @@ index 2228f83f251851aa683f739ac5ce2ec98f059f3f..23d6f803eafa78fd51ea4cdc4ca25c78
|
||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
||||
this.setFlightAllowed(dedicatedserverproperties.allowFlight);
|
||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
index aa7bf54e4b93a9b6085aa943500f5dec5f60a117..7cc5070f70a4f740add9d971385ceaa4d44275a2 100644
|
||||
index 108432435aac34fadfd899941e6d2b951f509971..623b938177cc7287bccc55f34e644bda984a7b65 100644
|
||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -307,15 +307,15 @@ public class ServerChunkCache extends ChunkSource {
|
||||
@@ -23,6 +23,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
+import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.VisibleForDebug;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
@@ -334,6 +335,12 @@ public class ServerChunkCache extends ChunkSource {
|
||||
}
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public boolean isEntityTickingChunk(Entity entity) {
|
||||
+ public final boolean isInEntityTickingChunk(Entity entity) { return this.isEntityTickingChunk(entity); } // Paper - OBFHELPER
|
||||
+ @Override public boolean isEntityTickingChunk(Entity entity) {
|
||||
long i = ChunkPos.asLong(Mth.floor(entity.getX()) >> 4, Mth.floor(entity.getZ()) >> 4);
|
||||
|
||||
return this.checkChunkFuture(i, (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
|
||||
+ // Paper start - helper
|
||||
+ public boolean isPositionTicking(Entity entity) {
|
||||
+ return this.isPositionTicking(ChunkPos.asLong(Mth.floor(entity.getX()) >> 4, Mth.floor(entity.getZ()) >> 4));
|
||||
+ }
|
||||
+ // Paper end
|
||||
+
|
||||
public boolean isPositionTicking(long i) {
|
||||
return this.checkChunkFuture(i, (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getTickingChunkFuture); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
- @Override
|
||||
- public boolean isEntityTickingChunk(ChunkPos pos) {
|
||||
+ public final boolean isEntityTickingChunk(ChunkPos chunkcoordintpair) { return this.isEntityTickingChunk(chunkcoordintpair); } // Paper - OBFHELPER
|
||||
+ @Override public boolean isEntityTickingChunk(ChunkPos pos) {
|
||||
return this.checkChunkFuture(pos.toLong(), (Function<ChunkHolder, CompletableFuture<Either<LevelChunk, ChunkHolder.ChunkLoadingFailure>>>) ChunkHolder::getEntityTickingChunkFuture); // CraftBukkit - decompile error
|
||||
}
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
index f82fd4a50921c3c4791be18a43778e6fd216f557..ff482d0349c18d0d1ba902ea0d10611b1ca4e588 100644
|
||||
index 067216078c7b50390957d1fcfbfbaaeb81cfba21..7f3d83d3d071f6b441ad119b1c93be035e911e70 100644
|
||||
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
|
||||
@@ -2,6 +2,7 @@ package net.minecraft.world.entity;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Spliterator;
|
||||
+import java.util.Set; // Paper
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Stream;
|
||||
@@ -599,4 +600,10 @@ public class EntityType<T extends Entity> {
|
||||
return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions, this.clientTrackingRange, this.updateInterval);
|
||||
}
|
||||
@@ -666,4 +667,10 @@ public class EntityType<T extends Entity> implements EntityTypeTest<Entity, T> {
|
||||
|
||||
T create(EntityType<T> type, Level world);
|
||||
}
|
||||
+
|
||||
+ // Paper start
|
||||
@ -668,10 +669,10 @@ index f82fd4a50921c3c4791be18a43778e6fd216f557..ff482d0349c18d0d1ba902ea0d10611b
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
||||
index b7c64fcf49ea50fa38a121d906ec6df20a1be31b..f08de81dcc4acd5a3e44407b431ce827a19b2e9c 100644
|
||||
index b2083d26e3b239d0f26da77955db6a34b622a1bb..90854842fda0f91ac68c70efbcf8ad9e3297ceb4 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
||||
@@ -129,6 +129,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -146,6 +146,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
public boolean populating;
|
||||
public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot
|
||||
|
||||
@ -680,7 +681,7 @@ index b7c64fcf49ea50fa38a121d906ec6df20a1be31b..f08de81dcc4acd5a3e44407b431ce827
|
||||
public final SpigotTimings.WorldTimingsHandler timings; // Spigot
|
||||
public static BlockPos lastPhysicsProblem; // Spigot
|
||||
private org.spigotmc.TickLimiter entityLimiter;
|
||||
@@ -149,6 +151,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
@@ -166,6 +168,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
||||
|
||||
protected Level(WritableLevelData worlddatamutable, ResourceKey<Level> resourcekey, final DimensionType dimensionmanager, Supplier<ProfilerFiller> supplier, boolean flag, boolean flag1, long i, org.bukkit.generator.ChunkGenerator gen, org.bukkit.World.Environment env) {
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
||||
@ -689,35 +690,35 @@ index b7c64fcf49ea50fa38a121d906ec6df20a1be31b..f08de81dcc4acd5a3e44407b431ce827
|
||||
this.world = new CraftWorld((ServerLevel) this, gen, env);
|
||||
this.ticksPerAnimalSpawns = this.getCraftServer().getTicksPerAnimalSpawns(); // CraftBukkit
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 761ad2d7e538d1e299d3050446274addcde7d772..328d1e2b128b62f24917719c79823c9fb64a0dcf 100644
|
||||
index 69617d4da7d69fa45e189dc4b94fbd136e5d547c..743c9f11dbbb66db97bcb3b8fecd97290a7c9f61 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -806,6 +806,7 @@ public final class CraftServer implements Server {
|
||||
@@ -809,6 +809,7 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
|
||||
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
|
||||
+ com.destroystokyo.paper.PaperConfig.init((File) console.options.valueOf("paper-settings")); // Paper
|
||||
for (ServerLevel world : console.getAllLevels()) {
|
||||
world.worldDataServer.setDifficulty(config.difficulty);
|
||||
for (ServerLevel world : this.console.getAllLevels()) {
|
||||
world.serverLevelData.setDifficulty(config.difficulty);
|
||||
world.setSpawnSettings(config.spawnMonsters, config.spawnAnimals);
|
||||
@@ -839,6 +840,7 @@ public final class CraftServer implements Server {
|
||||
@@ -842,6 +843,7 @@ public final class CraftServer implements Server {
|
||||
world.ticksPerAmbientSpawns = this.getTicksPerAmbientSpawns();
|
||||
}
|
||||
world.spigotConfig.init(); // Spigot
|
||||
+ world.paperConfig.init(); // Paper
|
||||
}
|
||||
|
||||
pluginManager.clearPlugins();
|
||||
@@ -846,6 +848,7 @@ public final class CraftServer implements Server {
|
||||
resetRecipes();
|
||||
reloadData();
|
||||
this.pluginManager.clearPlugins();
|
||||
@@ -849,6 +851,7 @@ public final class CraftServer implements Server {
|
||||
this.resetRecipes();
|
||||
this.reloadData();
|
||||
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||
+ com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper
|
||||
overrideAllCommandBlockCommands = commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||
ignoreVanillaPermissions = commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||
|
||||
@@ -2101,4 +2104,35 @@ public final class CraftServer implements Server {
|
||||
return spigot;
|
||||
@@ -2104,4 +2107,35 @@ public final class CraftServer implements Server {
|
||||
return this.spigot;
|
||||
}
|
||||
// Spigot end
|
||||
+
|
||||
@ -753,7 +754,7 @@ index 761ad2d7e538d1e299d3050446274addcde7d772..328d1e2b128b62f24917719c79823c9f
|
||||
+ // Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 46a16e31775b28c44f95a8ac5545ebcb656c74b6..05aedca561919a12ced1925c5cc9af585bb04523 100644
|
||||
index 24e08ca0fca3e87f8a6b7670b266f3c2900b798c..3c4281ad770598ecf3b9fae0d6ed6e9130136dbb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -129,6 +129,14 @@ public class Main {
|
||||
@ -772,49 +773,49 @@ index 46a16e31775b28c44f95a8ac5545ebcb656c74b6..05aedca561919a12ced1925c5cc9af58
|
||||
};
|
||||
|
||||
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
index 83d83ff7ceffbb77723da721b869dfd0091e496d..0efcbab8f8806aeb8dd8bd6384e5a7cee375d100 100644
|
||||
index c7bfa5fe5f7945883bd41461247e0efb04f5e9e8..9a31d8b709b28bba658603106c623560c5362947 100644
|
||||
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
|
||||
@@ -39,36 +39,36 @@ public class SpigotWorldConfig
|
||||
config.set( "world-settings.default." + path, val );
|
||||
this.config.set( "world-settings.default." + path, val );
|
||||
}
|
||||
|
||||
- private boolean getBoolean(String path, boolean def)
|
||||
+ public boolean getBoolean(String path, boolean def) // Paper - private -> public
|
||||
{
|
||||
config.addDefault( "world-settings.default." + path, def );
|
||||
return config.getBoolean( "world-settings." + worldName + "." + path, config.getBoolean( "world-settings.default." + path ) );
|
||||
this.config.addDefault( "world-settings.default." + path, def );
|
||||
return this.config.getBoolean( "world-settings." + this.worldName + "." + path, this.config.getBoolean( "world-settings.default." + path ) );
|
||||
}
|
||||
|
||||
- private double getDouble(String path, double def)
|
||||
+ public double getDouble(String path, double def) // Paper - private -> public
|
||||
{
|
||||
config.addDefault( "world-settings.default." + path, def );
|
||||
return config.getDouble( "world-settings." + worldName + "." + path, config.getDouble( "world-settings.default." + path ) );
|
||||
this.config.addDefault( "world-settings.default." + path, def );
|
||||
return this.config.getDouble( "world-settings." + this.worldName + "." + path, this.config.getDouble( "world-settings.default." + path ) );
|
||||
}
|
||||
|
||||
- private int getInt(String path)
|
||||
+ public int getInt(String path) // Paper - private -> public
|
||||
{
|
||||
return config.getInt( "world-settings." + worldName + "." + path );
|
||||
return this.config.getInt( "world-settings." + this.worldName + "." + path );
|
||||
}
|
||||
|
||||
- private int getInt(String path, int def)
|
||||
+ public int getInt(String path, int def) // Paper - private -> public
|
||||
{
|
||||
config.addDefault( "world-settings.default." + path, def );
|
||||
return config.getInt( "world-settings." + worldName + "." + path, config.getInt( "world-settings.default." + path ) );
|
||||
this.config.addDefault( "world-settings.default." + path, def );
|
||||
return this.config.getInt( "world-settings." + this.worldName + "." + path, this.config.getInt( "world-settings.default." + path ) );
|
||||
}
|
||||
|
||||
- private <T> List getList(String path, T def)
|
||||
+ public <T> List getList(String path, T def) // Paper - private -> public
|
||||
{
|
||||
config.addDefault( "world-settings.default." + path, def );
|
||||
return (List<T>) config.getList( "world-settings." + worldName + "." + path, config.getList( "world-settings.default." + path ) );
|
||||
this.config.addDefault( "world-settings.default." + path, def );
|
||||
return (List<T>) this.config.getList( "world-settings." + this.worldName + "." + path, this.config.getList( "world-settings.default." + path ) );
|
||||
}
|
||||
|
||||
- private String getString(String path, String def)
|
||||
+ public String getString(String path, String def) // Paper - private -> public
|
||||
{
|
||||
config.addDefault( "world-settings.default." + path, def );
|
||||
return config.getString( "world-settings." + worldName + "." + path, config.getString( "world-settings.default." + path ) );
|
||||
this.config.addDefault( "world-settings.default." + path, def );
|
||||
return this.config.getString( "world-settings." + this.worldName + "." + path, this.config.getString( "world-settings.default." + path ) );
|
358
patches/server/0005-MC-Dev-fixes.patch
Normale Datei
358
patches/server/0005-MC-Dev-fixes.patch
Normale Datei
Dateidiff unterdrückt, weil mindestens eine Zeile zu lang ist
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren