Spaces:
Build error
Build error
package net.minecraft.server.chase; | |
import com.mojang.logging.LogUtils; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.net.InetAddress; | |
import java.net.ServerSocket; | |
import java.net.Socket; | |
import java.nio.channels.ClosedByInterruptException; | |
import java.nio.charset.StandardCharsets; | |
import java.util.List; | |
import java.util.Locale; | |
import java.util.concurrent.CopyOnWriteArrayList; | |
import java.util.stream.Collectors; | |
import javax.annotation.Nullable; | |
import net.minecraft.Util; | |
import net.minecraft.server.commands.ChaseCommand; | |
import net.minecraft.server.level.ServerPlayer; | |
import net.minecraft.server.players.PlayerList; | |
import org.apache.commons.io.IOUtils; | |
import org.slf4j.Logger; | |
public class ChaseServer { | |
private static final Logger LOGGER = LogUtils.getLogger(); | |
private final String serverBindAddress; | |
private final int serverPort; | |
private final PlayerList playerList; | |
private final int broadcastIntervalMs; | |
private volatile boolean wantsToRun; | |
private ServerSocket serverSocket; | |
private final CopyOnWriteArrayList<Socket> clientSockets = new CopyOnWriteArrayList<>(); | |
public ChaseServer(String p_196032_, int p_196033_, PlayerList p_196034_, int p_196035_) { | |
this.serverBindAddress = p_196032_; | |
this.serverPort = p_196033_; | |
this.playerList = p_196034_; | |
this.broadcastIntervalMs = p_196035_; | |
} | |
public void start() throws IOException { | |
if (this.serverSocket != null && !this.serverSocket.isClosed()) { | |
LOGGER.warn("Remote control server was asked to start, but it is already running. Will ignore."); | |
} else { | |
this.wantsToRun = true; | |
this.serverSocket = new ServerSocket(this.serverPort, 50, InetAddress.getByName(this.serverBindAddress)); | |
Thread thread = new Thread(this::runAcceptor, "chase-server-acceptor"); | |
thread.setDaemon(true); | |
thread.start(); | |
Thread thread1 = new Thread(this::runSender, "chase-server-sender"); | |
thread1.setDaemon(true); | |
thread1.start(); | |
} | |
} | |
private void runSender() { | |
ChaseServer.PlayerPosition chaseserver$playerposition = null; | |
while (this.wantsToRun) { | |
if (!this.clientSockets.isEmpty()) { | |
ChaseServer.PlayerPosition chaseserver$playerposition1 = this.getPlayerPosition(); | |
if (chaseserver$playerposition1 != null && !chaseserver$playerposition1.equals(chaseserver$playerposition)) { | |
chaseserver$playerposition = chaseserver$playerposition1; | |
byte[] abyte = chaseserver$playerposition1.format().getBytes(StandardCharsets.US_ASCII); | |
for (Socket socket : this.clientSockets) { | |
if (!socket.isClosed()) { | |
Util.ioPool().execute(() -> { | |
try { | |
OutputStream outputstream = socket.getOutputStream(); | |
outputstream.write(abyte); | |
outputstream.flush(); | |
} catch (IOException ioexception) { | |
LOGGER.info("Remote control client socket got an IO exception and will be closed", (Throwable)ioexception); | |
IOUtils.closeQuietly(socket); | |
} | |
}); | |
} | |
} | |
} | |
List<Socket> list = this.clientSockets.stream().filter(Socket::isClosed).collect(Collectors.toList()); | |
this.clientSockets.removeAll(list); | |
} | |
if (this.wantsToRun) { | |
try { | |
Thread.sleep((long)this.broadcastIntervalMs); | |
} catch (InterruptedException interruptedexception) { | |
} | |
} | |
} | |
} | |
public void stop() { | |
this.wantsToRun = false; | |
IOUtils.closeQuietly(this.serverSocket); | |
this.serverSocket = null; | |
} | |
private void runAcceptor() { | |
try { | |
while (this.wantsToRun) { | |
if (this.serverSocket != null) { | |
LOGGER.info("Remote control server is listening for connections on port {}", this.serverPort); | |
Socket socket = this.serverSocket.accept(); | |
LOGGER.info("Remote control server received client connection on port {}", socket.getPort()); | |
this.clientSockets.add(socket); | |
} | |
} | |
} catch (ClosedByInterruptException closedbyinterruptexception) { | |
if (this.wantsToRun) { | |
LOGGER.info("Remote control server closed by interrupt"); | |
} | |
} catch (IOException ioexception) { | |
if (this.wantsToRun) { | |
LOGGER.error("Remote control server closed because of an IO exception", (Throwable)ioexception); | |
} | |
} finally { | |
IOUtils.closeQuietly(this.serverSocket); | |
} | |
LOGGER.info("Remote control server is now stopped"); | |
this.wantsToRun = false; | |
} | |
private ChaseServer.PlayerPosition getPlayerPosition() { | |
List<ServerPlayer> list = this.playerList.getPlayers(); | |
if (list.isEmpty()) { | |
return null; | |
} else { | |
ServerPlayer serverplayer = list.get(0); | |
String s = ChaseCommand.DIMENSION_NAMES.inverse().get(serverplayer.level().dimension()); | |
return s == null | |
? null | |
: new ChaseServer.PlayerPosition( | |
s, serverplayer.getX(), serverplayer.getY(), serverplayer.getZ(), serverplayer.getYRot(), serverplayer.getXRot() | |
); | |
} | |
} | |
static record PlayerPosition(String dimensionName, double x, double y, double z, float yRot, float xRot) { | |
String format() { | |
return String.format( | |
Locale.ROOT, "t %s %.2f %.2f %.2f %.2f %.2f\n", this.dimensionName, this.x, this.y, this.z, this.yRot, this.xRot | |
); | |
} | |
} | |
} |