geforkt von SteamWar/BungeeCore
Commits vergleichen
14 Commits
master
...
schemsearc
Autor | SHA1 | Datum | |
---|---|---|---|
|
3b0e4aa5aa | ||
|
d9ad5bd14a | ||
|
1c54b1c60f | ||
|
ec0c06227f | ||
|
3bd18531f5 | ||
|
afece3008c | ||
|
a6dbf41feb | ||
|
e728483e5f | ||
|
b7d42a767a | ||
|
badb5e5e1e | ||
|
f624d2893d | ||
|
edb108b7b3 | ||
|
81dbcc691a | ||
|
06d3aeb9d1 |
@ -28,6 +28,7 @@ import de.steamwar.bungeecore.listeners.ping.PingListener;
|
||||
import de.steamwar.bungeecore.network.BungeeNetworkHandler;
|
||||
import de.steamwar.bungeecore.network.NetworkReceiver;
|
||||
import de.steamwar.bungeecore.network.SWScriptSyntaxForwarder;
|
||||
import de.steamwar.bungeecore.util.SchematicSearch;
|
||||
import de.steamwar.sql.Punishment;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import de.steamwar.sql.UserElo;
|
||||
@ -122,6 +123,7 @@ public class BungeeCore extends Plugin {
|
||||
new Fabric();
|
||||
new SubserverProtocolFixer();
|
||||
new PingListener();
|
||||
new SchematicSearchListener();
|
||||
|
||||
local = new Node.LocalNode();
|
||||
if(MAIN_SERVER) {
|
||||
@ -233,6 +235,7 @@ public class BungeeCore extends Plugin {
|
||||
tablistManager.disable();
|
||||
errorLogger.unregister();
|
||||
Statement.closeAll();
|
||||
SchematicSearch.abortAll();
|
||||
}
|
||||
|
||||
public static BungeeCore get() {
|
||||
|
@ -21,6 +21,7 @@ package de.steamwar.bungeecore.commands;
|
||||
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.Node;
|
||||
import de.steamwar.bungeecore.util.SchematicSearch;
|
||||
import de.steamwar.command.SWCommand;
|
||||
import net.md_5.bungee.api.CommandSender;
|
||||
|
||||
@ -37,6 +38,7 @@ public class StatCommand extends SWCommand {
|
||||
|
||||
@Register
|
||||
public void genericCommand(CommandSender sender) {
|
||||
Message.send("STAT_SEARCH_QUEUE", sender, SchematicSearch.getQueueSize());
|
||||
Map<String, Integer> serverCount = new HashMap<>();
|
||||
try {
|
||||
Process process = new ProcessBuilder("ps", "x").start();
|
||||
|
41
src/de/steamwar/bungeecore/listeners/SchematicSearchListener.java
Normale Datei
41
src/de/steamwar/bungeecore/listeners/SchematicSearchListener.java
Normale Datei
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.listeners;
|
||||
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.bungeecore.util.SchematicSearch;
|
||||
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class SchematicSearchListener extends BasicListener {
|
||||
|
||||
@EventHandler
|
||||
public void onServerSwitch(ServerSwitchEvent event) {
|
||||
if(SchematicSearch.removeFromQueue(event.getPlayer())) {
|
||||
Message.send("SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE", event.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onQuit(PlayerDisconnectEvent event) {
|
||||
SchematicSearch.removeFromQueue(event.getPlayer());
|
||||
}
|
||||
}
|
@ -31,5 +31,6 @@ public class BungeeNetworkHandler {
|
||||
new ImALobbyHandler().register();
|
||||
new InventoryCallbackHandler().register();
|
||||
new PrepareSchemHandler().register();
|
||||
new SchematicSearchRequestHandler().register();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.network.handlers;
|
||||
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.util.SchematicSearch;
|
||||
import de.steamwar.network.packets.PacketHandler;
|
||||
import de.steamwar.network.packets.client.RequestSchematicSearchPacket;
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
|
||||
public class SchematicSearchRequestHandler extends PacketHandler {
|
||||
|
||||
@Handler
|
||||
public void handle(RequestSchematicSearchPacket packet) {
|
||||
SteamwarUser user = SteamwarUser.get(packet.getPlayerId());
|
||||
SchematicNode node = SchematicNode.getSchematicNode(packet.getSchematicId());
|
||||
ProxiedPlayer proxiedPlayer = BungeeCore.get().getProxy().getPlayer(user.getUUID());
|
||||
if(proxiedPlayer == null) {
|
||||
return;
|
||||
}
|
||||
SchematicSearch.SchematicSearchBehavior behavior = SchematicSearch.SchematicSearchBehavior.builder()
|
||||
.airAsAny(packet.isAirAsAny())
|
||||
.ignoreAir(packet.isIgnoreAir())
|
||||
.ignoreBlockData(packet.isIgnoreBlockData())
|
||||
.build();
|
||||
SchematicSearch.queueSearch(proxiedPlayer, node, behavior);
|
||||
}
|
||||
}
|
307
src/de/steamwar/bungeecore/util/SchematicSearch.java
Normale Datei
307
src/de/steamwar/bungeecore/util/SchematicSearch.java
Normale Datei
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* This file is a part of the SteamWar software.
|
||||
*
|
||||
* Copyright (C) 2023 SteamWar.de-Serverteam
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package de.steamwar.bungeecore.util;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import de.steamwar.bungeecore.BungeeCore;
|
||||
import de.steamwar.bungeecore.Message;
|
||||
import de.steamwar.sql.NodeData;
|
||||
import de.steamwar.sql.SchematicNode;
|
||||
import de.steamwar.sql.SteamwarUser;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import net.md_5.bungee.api.ChatMessageType;
|
||||
import net.md_5.bungee.api.chat.ClickEvent;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.scheduler.ScheduledTask;
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class SchematicSearch {
|
||||
private static final String SEARCH_BINARY = "/home/chaoscaot/schemsearch/target/release/schemsearch-cli";
|
||||
private static final LinkedBlockingQueue<SchematicSearch> searchQueue = new LinkedBlockingQueue<>();
|
||||
private static SchematicSearch currentSearch;
|
||||
|
||||
private static void startNext() {
|
||||
if(currentSearch != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (searchQueue) {
|
||||
if(searchQueue.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
currentSearch = searchQueue.poll();
|
||||
currentSearch.start();
|
||||
}
|
||||
}
|
||||
|
||||
public static void queueSearch(ProxiedPlayer player, SchematicNode node, SchematicSearchBehavior behavior) {
|
||||
synchronized (searchQueue) {
|
||||
searchQueue.add(new SchematicSearch(player, node, behavior));
|
||||
startNext();
|
||||
if (!searchQueue.isEmpty()) {
|
||||
Message.send("SCHEMATIC_SEARCH_QUEUED", player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void abortAll() {
|
||||
synchronized (searchQueue) {
|
||||
searchQueue.stream().map(schematicSearch -> schematicSearch.player).collect(Collectors.toSet()).forEach(player -> {
|
||||
Message.send("SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE_SOFTRELOAD", player);
|
||||
});
|
||||
searchQueue.clear();
|
||||
}
|
||||
if(currentSearch != null) {
|
||||
Message.send("SCHEMATIC_SEARCH_CANCELED_SOFTRELOAD", currentSearch.player);
|
||||
currentSearch.end();
|
||||
}
|
||||
}
|
||||
|
||||
public static int getQueueSize() {
|
||||
synchronized (searchQueue) {
|
||||
return searchQueue.size();
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> constructArguments(SteamwarUser user, File pattern, SchematicSearchBehavior behavior) {
|
||||
List<String> args = new ArrayList<>(Arrays.asList(SEARCH_BINARY, "-T", "2", "-s", "-u", String.valueOf(user.getId()), "-o", "json:std", "-m", "50"));
|
||||
if(behavior.isAirAsAny()) {
|
||||
args.add("-A");
|
||||
}
|
||||
if(behavior.isIgnoreAir()) {
|
||||
args.add("-a");
|
||||
}
|
||||
if(behavior.isIgnoreBlockData()) {
|
||||
args.add("-d");
|
||||
}
|
||||
args.add(pattern.getAbsolutePath());
|
||||
return args;
|
||||
}
|
||||
|
||||
public static boolean removeFromQueue(ProxiedPlayer player) {
|
||||
boolean removed;
|
||||
synchronized (searchQueue) {
|
||||
removed = searchQueue.removeIf(search -> search.player.equals(player));
|
||||
}
|
||||
|
||||
if (currentSearch != null && currentSearch.player.equals(player)) {
|
||||
currentSearch.end();
|
||||
removed = true;
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
private static File schematicNodeToTempFile(NodeData node) {
|
||||
try {
|
||||
File f = File.createTempFile("schemsearch", ".schem");
|
||||
f.deleteOnExit();
|
||||
OutputStream os = new GZIPOutputStream(Files.newOutputStream(f.toPath()));
|
||||
InputStream is = node.schemData();
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
while((read = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, read);
|
||||
}
|
||||
|
||||
os.close();
|
||||
is.close();
|
||||
return f;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private final ProxiedPlayer player;
|
||||
private final SchematicNode node;
|
||||
private final SchematicSearchBehavior behavior;
|
||||
private File pattern;
|
||||
private ScheduledTask task;
|
||||
private Process process;
|
||||
|
||||
private SchematicSearch(ProxiedPlayer player, SchematicNode node, SchematicSearchBehavior behavior) {
|
||||
this.player = player;
|
||||
this.node = node;
|
||||
this.behavior = behavior;
|
||||
}
|
||||
|
||||
private static String readInputStream(InputStream is) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
byte[] buffer = new byte[1024];
|
||||
long total = 0;
|
||||
while (is.available() > 0) {
|
||||
int read = is.read(buffer);
|
||||
total += read;
|
||||
if (read > 0) {
|
||||
sb.append(new String(buffer, 0, read));
|
||||
}
|
||||
if (total > 1024 * 128) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void start() {
|
||||
task = BungeeCore.get().getProxy().getScheduler().runAsync(BungeeCore.get(), () -> {
|
||||
try {
|
||||
NodeData data = NodeData.get(node);
|
||||
if (!data.getNodeFormat()) {
|
||||
Message.send("SCHEMATIC_SEARCH_NOT_SUPPORTED", player);
|
||||
end();
|
||||
return;
|
||||
}
|
||||
Message.send("SCHEMATIC_SEARCH_STARTED", player, node.getName());
|
||||
pattern = schematicNodeToTempFile(data);
|
||||
ProcessBuilder builder = new ProcessBuilder(constructArguments(SteamwarUser.get(player.getUniqueId()), pattern, behavior));
|
||||
process = builder.start();
|
||||
InputStream stdout = process.getInputStream();
|
||||
InputStream stderr = process.getErrorStream();
|
||||
|
||||
String bar = "";
|
||||
while (!process.waitFor(200, TimeUnit.MILLISECONDS)) {
|
||||
String s = readInputStream(stderr);
|
||||
if (s.length() > 0) {
|
||||
if (s.contains("s[")) {
|
||||
s = s.substring(s.lastIndexOf("s[") + 1);
|
||||
}
|
||||
s = s.replace("█", "§e█§7");
|
||||
bar = s;
|
||||
}
|
||||
BungeeCore.send(player, ChatMessageType.ACTION_BAR, "§7" + bar);
|
||||
}
|
||||
String s = readInputStream(stderr);
|
||||
if (s.contains("s[")) {
|
||||
s = s.substring(s.lastIndexOf("s[") + 1);
|
||||
}
|
||||
BungeeCore.send(player, ChatMessageType.ACTION_BAR, "§7" + s.replace("█", "§e█§7"));
|
||||
s = readInputStream(stdout);
|
||||
String[] outputs = s.split("\n");
|
||||
|
||||
List<JsonObject> elements = Arrays.stream(outputs).map(JsonParser::parseString).map(JsonElement::getAsJsonObject).collect(Collectors.toList());
|
||||
|
||||
int searchCount = 0;
|
||||
long searchTime = 0;
|
||||
List<Match> matches = new ArrayList<>();
|
||||
|
||||
for (JsonObject element : elements) {
|
||||
switch (element.get("event").getAsString()) {
|
||||
case "Init":
|
||||
searchCount = element.get("total").getAsInt();
|
||||
break;
|
||||
case "Found":
|
||||
matches.add(new Match(element.get("x").getAsInt(), element.get("y").getAsInt(), element.get("z").getAsInt(), element.get("percent").getAsFloat() * 100, element.get("name").getAsString()));
|
||||
break;
|
||||
case "End":
|
||||
searchTime = element.get("end_time").getAsLong();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Message.send("SCHEMATIC_SEARCH_RESULT_HEADER", player, searchCount, DurationFormatUtils.formatDuration(searchTime, "' 'm'm 's's 'S'ms'")
|
||||
.replace(" 0ms", "")
|
||||
.replace(" 0s", "")
|
||||
.replace(" 0m", ""));
|
||||
|
||||
if (matches.size() <= 1) {
|
||||
Message.send("SCHEMATIC_SEARCH_NO_RESULTS", player);
|
||||
end();
|
||||
return;
|
||||
}
|
||||
|
||||
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
|
||||
for (Match match : matches) {
|
||||
String[] nameSplit = match.name.split(" ");
|
||||
String name = nameSplit[0];
|
||||
int id = Integer.parseInt(nameSplit[1].substring(1, nameSplit[1].length() - 1));
|
||||
if (id == node.getId()) continue;
|
||||
Message.sendPrefixless("SCHEMATIC_SEARCH_RESULT", player, Message.parse("SCHEMATIC_SEARCH_RESULT_HOVER", player, name),
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/schem info " + SchematicNode.byIdAndUser(user, id).generateBreadcrumbs()),
|
||||
name, match.percent, match.x + 1, match.y + 1, match.z + 1);
|
||||
}
|
||||
|
||||
if (matches.size() >= 49) {
|
||||
Message.send("SCHEMATIC_SEARCH_TOO_MANY_RESULTS", player);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new SecurityException(e);
|
||||
} finally {
|
||||
end();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if(process != null && process.isAlive()) {
|
||||
process.destroy();
|
||||
}
|
||||
|
||||
if(pattern != null) {
|
||||
pattern.delete();
|
||||
}
|
||||
|
||||
if(task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
synchronized (searchQueue) {
|
||||
if(currentSearch == this) {
|
||||
currentSearch = null;
|
||||
}
|
||||
}
|
||||
startNext();
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
private static class Match {
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
float percent;
|
||||
String name;
|
||||
}
|
||||
|
||||
@Builder
|
||||
@Getter
|
||||
public static class SchematicSearchBehavior {
|
||||
@Builder.Default
|
||||
boolean airAsAny = false;
|
||||
@Builder.Default
|
||||
boolean ignoreAir = false;
|
||||
@Builder.Default
|
||||
boolean ignoreBlockData = false;
|
||||
}
|
||||
}
|
@ -121,6 +121,7 @@ MOD_USE_MODSENDER=§cPlease use the §c§lFabricModSender§c (https://steamwar.d
|
||||
#Various commands
|
||||
ALERT=§f{0}
|
||||
STAT_SERVER=§7Server §e{0}§8: §7Below limit §e{1} §7Server count §e{2}
|
||||
STAT_SEARCH_QUEUE=§7Schematic search queue: §e{0}
|
||||
|
||||
#Ban&Mute-Command
|
||||
PUNISHMENT_USAGE=§8/§7{0} §8[§eplayer§8] [§edd§8.§emm§8.§eyyyy §7or §edd§8.§emm§8.§eyyyy§8_§ehh§8:§emm §7or §enumber§8[§eh§7our|§ed§7ay|§ew§7eek|§em§7onth|§ey§7ear§8] §7or §eperma§8] [§ereason§8]
|
||||
@ -690,3 +691,16 @@ MOD_FORBIDDEN=§eForbidden
|
||||
MOD_AUTOBAN=§cAutoban
|
||||
MOD_YT=§5YT Only
|
||||
MOD_ITEM_BACK=§7Back
|
||||
|
||||
#Schematic Search
|
||||
SCHEMATIC_SEARCH_QUEUED=§7Your search has been queued and will be executed shortly.
|
||||
SCHEMATIC_SEARCH_STARTED=§7Your search for "§e{0}§7" has started.
|
||||
SCHEMATIC_SEARCH_NO_RESULTS=§cNo results found.
|
||||
SCHEMATIC_SEARCH_RESULT_HEADER=§7Searched §e{0} §7schematics in§e{1}.
|
||||
SCHEMATIC_SEARCH_RESULT=§7{0}: §e{1}§7% §8(§e{2}§7,§e{3},§e{4}§8)
|
||||
SCHEMATIC_SEARCH_RESULT_HOVER=§7Click for more info about {0}.
|
||||
SCHEMATIC_SEARCH_NOT_SUPPORTED=§cThis schematic is not supported because it is on an old format.
|
||||
SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE=§cYour search has been removed from the queue because you switched servers.
|
||||
SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE_SOFTRELOAD=§cYour search has been removed from the queue because of a software update.
|
||||
SCHEMATIC_SEARCH_CANCELED_SOFTRELOAD=§cYour search has been cancelled because of a software update.
|
||||
SCHEMATIC_SEARCH_TOO_MANY_RESULTS=§cToo many results found. Please be more specific.
|
@ -647,4 +647,16 @@ ADVENT_CALENDAR_TITLE=§eAdventskalender
|
||||
ADVENT_CALENDAR_DAY=§7Tag§8: §e{0}
|
||||
ADVENT_CALENDAR_MESSAGE=§eHast du heute schon dein Geschenk geholt?
|
||||
ADVENT_CALENDAR_MESSAGE_HOVER=§eKlicken zum öffnen!
|
||||
ADVENT_CALENDAR_OPEN=§7Du hast §e{0}§7 aus dem Adventskalender erhalten!
|
||||
ADVENT_CALENDAR_OPEN=§7Du hast §e{0}§7 aus dem Adventskalender erhalten!
|
||||
|
||||
#Schematic Search
|
||||
SCHEMATIC_SEARCH_QUEUED=§7Deine Suche wurde in die Warteschlange eingereiht.
|
||||
SCHEMATIC_SEARCH_STARTED=§7Deine Suche nach §e{0} §7wurde gestartet.
|
||||
SCHEMATIC_SEARCH_NO_RESULTS=§cEs wurden keine Ergebnisse gefunden.
|
||||
SCHEMATIC_SEARCH_RESULT_HEADER=§e{0} §7Schematics in §e{1} §7durchsucht
|
||||
SCHEMATIC_SEARCH_RESULT_HOVER=§7Klicke für mehr Informationen
|
||||
SCHEMATIC_SEARCH_NOT_SUPPORTED=§cDiese Schematic ist in einem alten Format und kann nicht genutzt werden.
|
||||
SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE=§cDeine Suche wurde aus der Warteschlange entfernt, weil du den Server gewechselt hast.
|
||||
SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE_SOFTRELOAD=§cWegen eines Software Updates wurde deine Suche aus der Warteschlange entfernt.
|
||||
SCHEMATIC_SEARCH_CANCELED_SOFTRELOAD=§cDeine Suche wurde wegen eines Software Updates abgebrochen.
|
||||
SCHEMATIC_SEARCH_TOO_MANY_RESULTS=§cEs wurden zu viele Ergebnisse gefunden. Bitte spezifiziere deine Suche.
|
In neuem Issue referenzieren
Einen Benutzer sperren