1
0

Basic SchemSearch

Dieser Commit ist enthalten in:
Chaoscaot 2023-04-06 14:23:26 +02:00
Ursprung 2a91876cb9
Commit 06d3aeb9d1
5 geänderte Dateien mit 327 neuen und 0 gelöschten Zeilen

Datei anzeigen

@ -122,6 +122,7 @@ public class BungeeCore extends Plugin {
new Fabric();
new SubserverProtocolFixer();
new PingListener();
new SchematicSearchListener();
local = new Node.LocalNode();
if(MAIN_SERVER) {
@ -170,6 +171,7 @@ public class BungeeCore extends Plugin {
new CalendarListener();
new ModCommand();
new SchemSearchTestCommand();
// Punishment Commands:
new PunishmentCommand("ban", Punishment.PunishmentType.Ban);

Datei anzeigen

@ -0,0 +1,40 @@
package de.steamwar.bungeecore.commands;
import de.steamwar.bungeecore.util.SchematicSearch;
import de.steamwar.command.PreviousArguments;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.Collection;
public class SchemSearchTestCommand extends SWCommand {
public SchemSearchTestCommand() {
super("schemsearch");
}
@Register
public void genericCommand(ProxiedPlayer player, SchematicNode node) {
SchematicSearch.queueSearch(player, node);
}
@ClassMapper(SchematicNode.class)
public TypeMapper<SchematicNode> getSchematicNodeMapper() {
return new TypeMapper<SchematicNode>() {
@Override
public SchematicNode map(CommandSender commandSender, String[] previousArguments, String s) {
return SchematicNode.getNodeFromPath(SteamwarUser.get(commandSender.getName()), s);
}
@Override
public Collection<String> tabCompletes(CommandSender sender, PreviousArguments previousArguments, String s) {
return SchematicNode.getNodeTabcomplete(SteamwarUser.get(sender.getName()), s);
}
};
}
}

Datei anzeigen

@ -0,0 +1,22 @@
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());
}
}

Datei anzeigen

@ -0,0 +1,252 @@
package de.steamwar.bungeecore.util;
import com.google.gson.Gson;
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 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.TimeUnit;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;
public class SchematicSearch {
private static final Gson gson = new Gson();
private static final String searchBinary = "/home/chaoscaot/schemsearch/target/release/schemsearch-cli";
private static final List<SchematicSearch> searchQueue = new ArrayList<>();
private static SchematicSearch currentSearch;
private static ScheduledTask watchdog;
private static void startQueueWatchdog() {
watchdog = BungeeCore.get().getProxy().getScheduler().schedule(BungeeCore.get(), () -> {
synchronized (searchQueue) {
if(currentSearch == null) {
if(!searchQueue.isEmpty()) {
currentSearch = searchQueue.remove(0);
currentSearch.start();
} else {
watchdog.cancel();
watchdog = null;
}
}
}
}, 0, 1, TimeUnit.SECONDS);
}
public static void queueSearch(ProxiedPlayer player, SchematicNode node ) {
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
synchronized (searchQueue) {
if(user.getUserGroup().isAdminGroup()) {
searchQueue.add(0, new SchematicSearch(player, node));
} else {
searchQueue.add(new SchematicSearch(player, node));
}
}
if(watchdog == null) {
startQueueWatchdog();
} else {
Message.send("SCHEMATIC_SEARCH_QUEUED", player);
}
}
private static List<String> constructArguments(SteamwarUser user, File pattern) {
return Arrays.asList(searchBinary, "-T", "1", "-s", "-u", String.valueOf(user.getId()), "-o", "json:std", "-m", "50", pattern.getAbsolutePath());
}
public static boolean removeFromQueue(ProxiedPlayer player) {
boolean removed = false;
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 File pattern;
private ScheduledTask task;
private Process process;
private SchematicSearch(ProxiedPlayer player, SchematicNode node) {
this.player = player;
this.node = node;
}
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));
process = builder.start();
InputStream stdout = process.getInputStream();
InputStream stderr = process.getErrorStream();
while (!process.waitFor(100, TimeUnit.MILLISECONDS)) {
String s = readInputStream(stderr);
if(s.length() > 0) {
if(s.contains("s[")) {
s = s.substring(s.lastIndexOf("s[") + 1);
}
BungeeCore.send(player, ChatMessageType.ACTION_BAR, "§7" + s.replace("", "§e█§7"));
}
}
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);
}
end();
} catch (Exception e) {
end();
throw new SecurityException(e);
}
});
}
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;
}
}
}
@AllArgsConstructor
private static class Match {
int x;
int y;
int z;
float percent;
String name;
}
}

Datei anzeigen

@ -680,3 +680,14 @@ 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 in §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 to get more info about {0}.
SCHEMATIC_SEARCH_NOT_SUPPORTED=§cThis schematic is not supported by the schematic search.
SCHEMATIC_SEARCH_REMOVED_FROM_QUEUE=§cYour search has been removed from the queue because you switched servers.
SCHEMATIC_SEARCH_TOO_MANY_RESULTS=§cToo many results found. Please be more specific.