package net.minecraft.server.chase; import com.google.common.base.Charsets; 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.util.List; import java.util.Locale; import java.util.NoSuchElementException; import java.util.Optional; import java.util.Scanner; import javax.annotation.Nullable; 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.world.level.Level; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; import org.apache.commons.io.IOUtils; 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; @Nullable private Socket socket; @Nullable private Thread thread; public ChaseClient(String p_195990_, int p_195991_, MinecraftServer p_195992_) { this.serverHost = p_195990_; this.serverPort = p_195991_; this.server = p_195992_; } 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(this.socket); this.socket = null; this.thread = null; } public void run() { String s = this.serverHost + ":" + this.serverPort; while (this.wantsToRun) { try { LOGGER.info("Connecting to remote control server {}", s); 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 bufferedreader = new BufferedReader(new InputStreamReader(this.socket.getInputStream(), Charsets.US_ASCII))) { while (this.wantsToRun) { String s1 = bufferedreader.readLine(); if (s1 == null) { LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", s, 5); break; } this.handleMessage(s1); } } catch (IOException ioexception) { LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", s, 5); } } catch (IOException ioexception1) { LOGGER.warn("Failed to connect to remote control server {}. Will retry in {}s.", s, 5); } if (this.wantsToRun) { try { Thread.sleep(5000L); } catch (InterruptedException interruptedexception) { } } } } private void handleMessage(String p_195995_) { try (Scanner scanner = new Scanner(new StringReader(p_195995_))) { scanner.useLocale(Locale.ROOT); String s = scanner.next(); if ("t".equals(s)) { this.handleTeleport(scanner); } else { LOGGER.warn("Unknown message type '{}'", s); } } catch (NoSuchElementException nosuchelementexception) { LOGGER.warn("Could not parse message '{}', ignoring", p_195995_); } } private void handleTeleport(Scanner p_195997_) { this.parseTarget(p_195997_) .ifPresent( p_195999_ -> this.executeCommand( String.format( Locale.ROOT, "execute in %s run tp @s %.3f %.3f %.3f %.3f %.3f", p_195999_.level.location(), p_195999_.pos.x, p_195999_.pos.y, p_195999_.pos.z, p_195999_.rot.y, p_195999_.rot.x ) ) ); } private Optional parseTarget(Scanner p_196004_) { ResourceKey resourcekey = ChaseCommand.DIMENSION_NAMES.get(p_196004_.next()); if (resourcekey == null) { return Optional.empty(); } else { float f = p_196004_.nextFloat(); float f1 = p_196004_.nextFloat(); float f2 = p_196004_.nextFloat(); float f3 = p_196004_.nextFloat(); float f4 = p_196004_.nextFloat(); return Optional.of(new ChaseClient.TeleportTarget(resourcekey, new Vec3((double)f, (double)f1, (double)f2), new Vec2(f4, f3))); } } private void executeCommand(String p_196002_) { this.server .execute( () -> { List list = this.server.getPlayerList().getPlayers(); if (!list.isEmpty()) { ServerPlayer serverplayer = list.get(0); ServerLevel serverlevel = this.server.overworld(); CommandSourceStack commandsourcestack = new CommandSourceStack( serverplayer.commandSource(), Vec3.atLowerCornerOf(serverlevel.getSharedSpawnPos()), Vec2.ZERO, serverlevel, 4, "", CommonComponents.EMPTY, this.server, serverplayer ); Commands commands = this.server.getCommands(); commands.performPrefixedCommand(commandsourcestack, p_196002_); } } ); } static record TeleportTarget(ResourceKey level, Vec3 pos, Vec2 rot) { } }