2025-11-24 22:52:51 +03:00

155 lines
6.2 KiB
Java

/*
* 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<TeleportTarget> 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<ServerPlayer> 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> level, Vec3 pos, Vec2 rot) {
}
}