203 lines
5.7 KiB
Java
203 lines
5.7 KiB
Java
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 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.jetbrains.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;
|
|
@Nullable
|
|
private Socket socket;
|
|
@Nullable
|
|
private 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(this.socket);
|
|
this.socket = null;
|
|
this.thread = null;
|
|
}
|
|
|
|
public void run() {
|
|
String string = this.serverHost + ":" + this.serverPort;
|
|
|
|
while (this.wantsToRun) {
|
|
try {
|
|
LOGGER.info("Connecting to remote control server {}", string);
|
|
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));
|
|
|
|
try {
|
|
while (this.wantsToRun) {
|
|
String string2 = bufferedReader.readLine();
|
|
if (string2 == null) {
|
|
LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", string, 5);
|
|
break;
|
|
}
|
|
|
|
this.handleMessage(string2);
|
|
}
|
|
} catch (Throwable var7) {
|
|
try {
|
|
bufferedReader.close();
|
|
} catch (Throwable var6) {
|
|
var7.addSuppressed(var6);
|
|
}
|
|
|
|
throw var7;
|
|
}
|
|
|
|
bufferedReader.close();
|
|
} catch (IOException var8) {
|
|
LOGGER.warn("Lost connection to remote control server {}. Will retry in {}s.", string, 5);
|
|
}
|
|
} catch (IOException var9) {
|
|
LOGGER.warn("Failed to connect to remote control server {}. Will retry in {}s.", string, 5);
|
|
}
|
|
|
|
if (this.wantsToRun) {
|
|
try {
|
|
Thread.sleep(5000L);
|
|
} catch (InterruptedException var5) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void handleMessage(String message) {
|
|
try {
|
|
Scanner scanner = new Scanner(new StringReader(message));
|
|
|
|
try {
|
|
scanner.useLocale(Locale.ROOT);
|
|
String string = scanner.next();
|
|
if ("t".equals(string)) {
|
|
this.handleTeleport(scanner);
|
|
} else {
|
|
LOGGER.warn("Unknown message type '{}'", string);
|
|
}
|
|
} catch (Throwable var6) {
|
|
try {
|
|
scanner.close();
|
|
} catch (Throwable var5) {
|
|
var6.addSuppressed(var5);
|
|
}
|
|
|
|
throw var6;
|
|
}
|
|
|
|
scanner.close();
|
|
} catch (NoSuchElementException var7) {
|
|
LOGGER.warn("Could not parse message '{}', ignoring", message);
|
|
}
|
|
}
|
|
|
|
private void handleTeleport(Scanner scanner) {
|
|
this.parseTarget(scanner)
|
|
.ifPresent(
|
|
teleportTarget -> this.executeCommand(
|
|
String.format(
|
|
Locale.ROOT,
|
|
"execute in %s run tp @s %.3f %.3f %.3f %.3f %.3f",
|
|
teleportTarget.level.location(),
|
|
teleportTarget.pos.x,
|
|
teleportTarget.pos.y,
|
|
teleportTarget.pos.z,
|
|
teleportTarget.rot.y,
|
|
teleportTarget.rot.x
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
private Optional<ChaseClient.TeleportTarget> parseTarget(Scanner scanner) {
|
|
ResourceKey<Level> resourceKey = (ResourceKey<Level>)ChaseCommand.DIMENSION_NAMES.get(scanner.next());
|
|
if (resourceKey == null) {
|
|
return Optional.empty();
|
|
} else {
|
|
float f = scanner.nextFloat();
|
|
float g = scanner.nextFloat();
|
|
float h = scanner.nextFloat();
|
|
float i = scanner.nextFloat();
|
|
float j = scanner.nextFloat();
|
|
return Optional.of(new ChaseClient.TeleportTarget(resourceKey, new Vec3(f, g, h), new Vec2(j, i)));
|
|
}
|
|
}
|
|
|
|
private void executeCommand(String command) {
|
|
this.server
|
|
.execute(
|
|
() -> {
|
|
List<ServerPlayer> list = this.server.getPlayerList().getPlayers();
|
|
if (!list.isEmpty()) {
|
|
ServerPlayer 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, command);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
record TeleportTarget(ResourceKey<Level> level, Vec3 pos, Vec2 rot) {
|
|
}
|
|
}
|