/* * Decompiled with CFR 0.152. * * Could not load the following classes: * com.mojang.logging.LogUtils * org.apache.commons.io.IOUtils * org.jspecify.annotations.Nullable * org.slf4j.Logger */ package net.minecraft.server.chase; import com.mojang.logging.LogUtils; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Scanner; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.network.chat.CommonComponents; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; import net.minecraft.server.commands.ChaseCommand; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.permissions.LevelBasedPermissionSet; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.apache.commons.io.IOUtils; import org.jspecify.annotations.Nullable; import org.slf4j.Logger; public class ChaseClient { private static final Logger LOGGER = LogUtils.getLogger(); private static final int RECONNECT_INTERVAL_SECONDS = 5; private final String serverHost; private final int serverPort; private final MinecraftServer server; private volatile boolean wantsToRun; private @Nullable Socket socket; private @Nullable Thread thread; public ChaseClient(String serverHost, int serverPort, MinecraftServer server) { this.serverHost = serverHost; this.serverPort = serverPort; this.server = server; } public void start() { if (this.thread != null && this.thread.isAlive()) { LOGGER.warn("Remote control client was asked to start, but it is already running. Will ignore."); } this.wantsToRun = true; this.thread = new Thread(this::run, "chase-client"); this.thread.setDaemon(true); this.thread.start(); } public void stop() { this.wantsToRun = false; IOUtils.closeQuietly((Socket)this.socket); this.socket = null; this.thread = null; } public void run() { String serverAddress = this.serverHost + ":" + this.serverPort; while (this.wantsToRun) { try { LOGGER.info("Connecting to remote control server {}", (Object)serverAddress); this.socket = new Socket(this.serverHost, this.serverPort); LOGGER.info("Connected to remote control server! Will continuously execute the command broadcasted by that server."); try (BufferedReader input = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), StandardCharsets.US_ASCII));){ while (this.wantsToRun) { String message = input.readLine(); if (message == null) { LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", (Object)serverAddress, (Object)5); break; } this.handleMessage(message); } } catch (IOException err) { LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", (Object)serverAddress, (Object)5); } } catch (IOException e) { LOGGER.warn("Failed to connect to remote control server {}. Will retry in {}s.", (Object)serverAddress, (Object)5); } if (!this.wantsToRun) continue; try { Thread.sleep(5000L); } catch (InterruptedException interruptedException) {} } } private void handleMessage(String message) { try (Scanner scanner = new Scanner(new StringReader(message));){ scanner.useLocale(Locale.ROOT); String head = scanner.next(); if ("t".equals(head)) { this.handleTeleport(scanner); } else { LOGGER.warn("Unknown message type '{}'", (Object)head); } } catch (NoSuchElementException e) { LOGGER.warn("Could not parse message '{}', ignoring", (Object)message); } } private void handleTeleport(Scanner scanner) { this.parseTarget(scanner).ifPresent(target -> this.executeCommand(String.format(Locale.ROOT, "execute in %s run tp @s %.3f %.3f %.3f %.3f %.3f", target.level.identifier(), target.pos.x, target.pos.y, target.pos.z, Float.valueOf(target.rot.y), Float.valueOf(target.rot.x)))); } private Optional parseTarget(Scanner scanner) { ResourceKey levelType = (ResourceKey)ChaseCommand.DIMENSION_NAMES.get((Object)scanner.next()); if (levelType == null) { return Optional.empty(); } float x = scanner.nextFloat(); float y = scanner.nextFloat(); float z = scanner.nextFloat(); float yRot = scanner.nextFloat(); float xRot = scanner.nextFloat(); return Optional.of(new TeleportTarget(levelType, new Vec3(x, y, z), new Vec2(xRot, yRot))); } private void executeCommand(String command) { this.server.execute(() -> { List players = this.server.getPlayerList().getPlayers(); if (players.isEmpty()) { return; } ServerPlayer player = players.get(0); ServerLevel level = this.server.overworld(); CommandSourceStack commandSourceStack = new CommandSourceStack(player.commandSource(), Vec3.atLowerCornerOf(level.getRespawnData().pos()), Vec2.ZERO, level, LevelBasedPermissionSet.OWNER, "", CommonComponents.EMPTY, this.server, player); Commands commands = this.server.getCommands(); commands.performPrefixedCommand(commandSourceStack, command); }); } record TeleportTarget(ResourceKey level, Vec3 pos, Vec2 rot) { } }