ChaseServer.java

net.minecraft.server.chase.ChaseServer

信息

  • 全限定名:net.minecraft.server.chase.ChaseServer
  • 类型:public class
  • 包:net.minecraft.server.chase
  • 源码路径:src/main/java/net/minecraft/server/chase/ChaseServer.java
  • 起始行号:L23
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L24
    • 说明:

      TODO

  • serverBindAddress

    • 类型: String
    • 修饰符: private final
    • 源码定位: L25
    • 说明:

      TODO

  • serverPort

    • 类型: int
    • 修饰符: private final
    • 源码定位: L26
    • 说明:

      TODO

  • playerList

    • 类型: PlayerList
    • 修饰符: private final
    • 源码定位: L27
    • 说明:

      TODO

  • broadcastIntervalMs

    • 类型: int
    • 修饰符: private final
    • 源码定位: L28
    • 说明:

      TODO

  • wantsToRun

    • 类型: boolean
    • 修饰符: private volatile
    • 源码定位: L29
    • 说明:

      TODO

  • serverSocket

    • 类型: ServerSocket
    • 修饰符: private
    • 源码定位: L30
    • 说明:

      TODO

  • clientSockets

    • 类型: CopyOnWriteArrayList<Socket>
    • 修饰符: private final
    • 源码定位: L31
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.chase.ChaseServer.PlayerPosition
    • 类型: record
    • 修饰符: private
    • 源码定位: L139
    • 说明:

      TODO

构造器

public ChaseServer(String serverBindAddress, int serverPort, PlayerList playerList, int broadcastIntervalMs) @ L33

  • 构造器名:ChaseServer
  • 源码定位:L33
  • 修饰符:public

参数:

  • serverBindAddress: String
  • serverPort: int
  • playerList: PlayerList
  • broadcastIntervalMs: int

说明:

TODO

方法

下面的方法块按源码顺序生成。

public void start() @ L40

  • 方法名:start
  • 源码定位:L40
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private void runSender() @ L55

  • 方法名:runSender
  • 源码定位:L55
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

public void stop() @ L94

  • 方法名:stop
  • 源码定位:L94
  • 返回类型:void
  • 修饰符:public

参数:

说明:

TODO

private void runAcceptor() @ L100

  • 方法名:runAcceptor
  • 源码定位:L100
  • 返回类型:void
  • 修饰符:private

参数:

说明:

TODO

private ChaseServer.PlayerPosition getPlayerPosition() @ L126

  • 方法名:getPlayerPosition
  • 源码定位:L126
  • 返回类型:ChaseServer.PlayerPosition
  • 修饰符:private

参数:

说明:

TODO

代码

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 @Nullable ServerSocket serverSocket;
    private final CopyOnWriteArrayList<Socket> clientSockets = new CopyOnWriteArrayList<>();
 
    public ChaseServer(String serverBindAddress, int serverPort, PlayerList playerList, int broadcastIntervalMs) {
        this.serverBindAddress = serverBindAddress;
        this.serverPort = serverPort;
        this.playerList = playerList;
        this.broadcastIntervalMs = broadcastIntervalMs;
    }
 
    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 acceptor = new Thread(this::runAcceptor, "chase-server-acceptor");
            acceptor.setDaemon(true);
            acceptor.start();
            Thread sender = new Thread(this::runSender, "chase-server-sender");
            sender.setDaemon(true);
            sender.start();
        }
    }
 
    private void runSender() {
        ChaseServer.PlayerPosition oldPlayerPosition = null;
 
        while (this.wantsToRun) {
            if (!this.clientSockets.isEmpty()) {
                ChaseServer.PlayerPosition playerPosition = this.getPlayerPosition();
                if (playerPosition != null && !playerPosition.equals(oldPlayerPosition)) {
                    oldPlayerPosition = playerPosition;
                    byte[] messageBytes = playerPosition.format().getBytes(StandardCharsets.US_ASCII);
 
                    for (Socket clientSocket : this.clientSockets) {
                        if (!clientSocket.isClosed()) {
                            Util.ioPool().execute(() -> {
                                try {
                                    OutputStream output = clientSocket.getOutputStream();
                                    output.write(messageBytes);
                                    output.flush();
                                } catch (IOException var3x) {
                                    LOGGER.info("Remote control client socket got an IO exception and will be closed", (Throwable)var3x);
                                    IOUtils.closeQuietly(clientSocket);
                                }
                            });
                        }
                    }
                }
 
                List<Socket> closed = this.clientSockets.stream().filter(Socket::isClosed).collect(Collectors.toList());
                this.clientSockets.removeAll(closed);
            }
 
            if (this.wantsToRun) {
                try {
                    Thread.sleep(this.broadcastIntervalMs);
                } catch (InterruptedException var6) {
                }
            }
        }
    }
 
    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 clientSocket = this.serverSocket.accept();
                    LOGGER.info("Remote control server received client connection on port {}", clientSocket.getPort());
                    this.clientSockets.add(clientSocket);
                }
            }
        } catch (ClosedByInterruptException var6) {
            if (this.wantsToRun) {
                LOGGER.info("Remote control server closed by interrupt");
            }
        } catch (IOException var7) {
            if (this.wantsToRun) {
                LOGGER.error("Remote control server closed because of an IO exception", (Throwable)var7);
            }
        } finally {
            IOUtils.closeQuietly(this.serverSocket);
        }
 
        LOGGER.info("Remote control server is now stopped");
        this.wantsToRun = false;
    }
 
    private ChaseServer.@Nullable PlayerPosition getPlayerPosition() {
        List<ServerPlayer> players = this.playerList.getPlayers();
        if (players.isEmpty()) {
            return null;
        } else {
            ServerPlayer player = players.get(0);
            String dimensionName = ChaseCommand.DIMENSION_NAMES.inverse().get(player.level().dimension());
            return dimensionName == null
                ? null
                : new ChaseServer.PlayerPosition(dimensionName, player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
        }
    }
 
    private record PlayerPosition(String dimensionName, double x, double y, double z, float yRot, float xRot) {
        private 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);
        }
    }
}

引用的其他类

  • PlayerList

    • 引用位置: 参数/字段
  • Util

    • 引用位置: 方法调用
    • 关联成员: Util.ioPool()