PrepareSpawnTask.java

net.minecraft.server.network.config.PrepareSpawnTask

信息

  • 全限定名:net.minecraft.server.network.config.PrepareSpawnTask
  • 类型:public class
  • 包:net.minecraft.server.network.config
  • 源码路径:src/main/java/net/minecraft/server/network/config/PrepareSpawnTask.java
  • 起始行号:L31
  • 实现:ConfigurationTask
  • 职责:

    TODO

字段/常量

  • LOGGER

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

      TODO

  • TYPE

    • 类型: ConfigurationTask.Type
    • 修饰符: public static final
    • 源码定位: L33
    • 说明:

      TODO

  • PREPARE_CHUNK_RADIUS

    • 类型: int
    • 修饰符: public static final
    • 源码定位: L34
    • 说明:

      TODO

  • server

    • 类型: MinecraftServer
    • 修饰符: private final
    • 源码定位: L35
    • 说明:

      TODO

  • nameAndId

    • 类型: NameAndId
    • 修饰符: private final
    • 源码定位: L36
    • 说明:

      TODO

  • loadListener

    • 类型: LevelLoadListener
    • 修饰符: private final
    • 源码定位: L37
    • 说明:

      TODO

  • state

    • 类型: PrepareSpawnTask.State
    • 修饰符: private
    • 源码定位: L38
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.network.config.PrepareSpawnTask.Preparing

    • 类型: class
    • 修饰符: private final
    • 源码定位: L113
    • 说明:

      TODO

  • net.minecraft.server.network.config.PrepareSpawnTask.Ready

    • 类型: class
    • 修饰符: private final
    • 源码定位: L161
    • 说明:

      TODO

  • net.minecraft.server.network.config.PrepareSpawnTask.State

    • 类型: interface
    • 修饰符: private sealed
    • 源码定位: L203
    • 说明:

      TODO

构造器

public PrepareSpawnTask(MinecraftServer server, NameAndId nameAndId) @ L40

  • 构造器名:PrepareSpawnTask
  • 源码定位:L40
  • 修饰符:public

参数:

  • server: MinecraftServer
  • nameAndId: NameAndId

说明:

TODO

方法

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

public void start(Consumer<Packet<?>> connection) @ L46

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

参数:

  • connection: Consumer<Packet<?>>

说明:

TODO

public boolean tick() @ L68

  • 方法名:tick
  • 源码定位:L68
  • 返回类型:boolean
  • 修饰符:public

参数:

说明:

TODO

  • 方法名:spawnPlayer
  • 源码定位:L86
  • 返回类型:ServerPlayer
  • 修饰符:public

参数:

  • connection: Connection
  • cookie: CommonListenerCookie

说明:

TODO

public void keepAlive() @ L94

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

参数:

说明:

TODO

public void close() @ L100

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

参数:

说明:

TODO

public ConfigurationTask.Type type() @ L108

  • 方法名:type
  • 源码定位:L108
  • 返回类型:ConfigurationTask.Type
  • 修饰符:public

参数:

说明:

TODO

代码

public class PrepareSpawnTask implements ConfigurationTask {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final ConfigurationTask.Type TYPE = new ConfigurationTask.Type("prepare_spawn");
    public static final int PREPARE_CHUNK_RADIUS = 3;
    private final MinecraftServer server;
    private final NameAndId nameAndId;
    private final LevelLoadListener loadListener;
    private PrepareSpawnTask.@Nullable State state;
 
    public PrepareSpawnTask(MinecraftServer server, NameAndId nameAndId) {
        this.server = server;
        this.nameAndId = nameAndId;
        this.loadListener = server.getLevelLoadListener();
    }
 
    @Override
    public void start(Consumer<Packet<?>> connection) {
        try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(LOGGER)) {
            Optional<ValueInput> loadedData = this.server
                .getPlayerList()
                .loadPlayerData(this.nameAndId)
                .map(tag -> TagValueInput.create(reporter, this.server.registryAccess(), tag));
            ServerPlayer.SavedPosition loadedPosition = loadedData.<ServerPlayer.SavedPosition>flatMap(tag -> tag.read(ServerPlayer.SavedPosition.MAP_CODEC))
                .orElse(ServerPlayer.SavedPosition.EMPTY);
            LevelData.RespawnData respawnData = this.server.getWorldData().overworldData().getRespawnData();
            ServerLevel spawnLevel = loadedPosition.dimension().map(this.server::getLevel).orElseGet(() -> {
                ServerLevel spawnDataLevel = this.server.getLevel(respawnData.dimension());
                return spawnDataLevel != null ? spawnDataLevel : this.server.overworld();
            });
            CompletableFuture<Vec3> spawnPosition = loadedPosition.position()
                .map(CompletableFuture::completedFuture)
                .orElseGet(() -> PlayerSpawnFinder.findSpawn(spawnLevel, respawnData.pos()));
            Vec2 spawnAngle = loadedPosition.rotation().orElse(new Vec2(respawnData.yaw(), respawnData.pitch()));
            this.state = new PrepareSpawnTask.Preparing(spawnLevel, spawnPosition, spawnAngle);
        }
    }
 
    @Override
    public boolean tick() {
        return switch (this.state) {
            case null -> false;
            case PrepareSpawnTask.Preparing preparing -> {
                PrepareSpawnTask.Ready ready = preparing.tick();
                if (ready != null) {
                    this.state = ready;
                    yield true;
                } else {
                    yield false;
                }
            }
            case PrepareSpawnTask.Ready ignored -> true;
            default -> throw new MatchException(null, null);
        };
    }
 
    public ServerPlayer spawnPlayer(Connection connection, CommonListenerCookie cookie) {
        if (this.state instanceof PrepareSpawnTask.Ready ready) {
            return ready.spawn(connection, cookie);
        } else {
            throw new IllegalStateException("Player spawn was not ready");
        }
    }
 
    public void keepAlive() {
        if (this.state instanceof PrepareSpawnTask.Ready ready) {
            ready.keepAlive();
        }
    }
 
    public void close() {
        if (this.state instanceof PrepareSpawnTask.Preparing preparing) {
            preparing.cancel();
        }
 
        this.state = null;
    }
 
    @Override
    public ConfigurationTask.Type type() {
        return TYPE;
    }
 
    private final class Preparing implements PrepareSpawnTask.State {
        private final ServerLevel spawnLevel;
        private final CompletableFuture<Vec3> spawnPosition;
        private final Vec2 spawnAngle;
        private @Nullable CompletableFuture<?> chunkLoadFuture;
        private final ChunkLoadCounter chunkLoadCounter;
 
        private Preparing(ServerLevel spawnLevel, CompletableFuture<Vec3> spawnPosition, Vec2 spawnAngle) {
            Objects.requireNonNull(PrepareSpawnTask.this);
            super();
            this.chunkLoadCounter = new ChunkLoadCounter();
            this.spawnLevel = spawnLevel;
            this.spawnPosition = spawnPosition;
            this.spawnAngle = spawnAngle;
        }
 
        public void cancel() {
            this.spawnPosition.cancel(false);
        }
 
        public PrepareSpawnTask.@Nullable Ready tick() {
            if (!this.spawnPosition.isDone()) {
                return null;
            } else {
                Vec3 spawnPosition = this.spawnPosition.join();
                if (this.chunkLoadFuture == null) {
                    ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(spawnPosition));
                    this.chunkLoadCounter
                        .track(
                            this.spawnLevel,
                            () -> this.chunkLoadFuture = this.spawnLevel.getChunkSource().addTicketAndLoadWithRadius(TicketType.PLAYER_SPAWN, spawnChunk, 3)
                        );
                    PrepareSpawnTask.this.loadListener.start(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS, this.chunkLoadCounter.totalChunks());
                    PrepareSpawnTask.this.loadListener.updateFocus(this.spawnLevel.dimension(), spawnChunk);
                }
 
                PrepareSpawnTask.this.loadListener
                    .update(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS, this.chunkLoadCounter.readyChunks(), this.chunkLoadCounter.totalChunks());
                if (!this.chunkLoadFuture.isDone()) {
                    return null;
                } else {
                    PrepareSpawnTask.this.loadListener.finish(LevelLoadListener.Stage.LOAD_PLAYER_CHUNKS);
                    return PrepareSpawnTask.this.new Ready(this.spawnLevel, spawnPosition, this.spawnAngle);
                }
            }
        }
    }
 
    private final class Ready implements PrepareSpawnTask.State {
        private final ServerLevel spawnLevel;
        private final Vec3 spawnPosition;
        private final Vec2 spawnAngle;
 
        private Ready(ServerLevel spawnLevel, Vec3 spawnPosition, Vec2 spawnAngle) {
            Objects.requireNonNull(PrepareSpawnTask.this);
            super();
            this.spawnLevel = spawnLevel;
            this.spawnPosition = spawnPosition;
            this.spawnAngle = spawnAngle;
        }
 
        public void keepAlive() {
            this.spawnLevel.getChunkSource().addTicketWithRadius(TicketType.PLAYER_SPAWN, ChunkPos.containing(BlockPos.containing(this.spawnPosition)), 3);
        }
 
        public ServerPlayer spawn(Connection connection, CommonListenerCookie cookie) {
            ChunkPos spawnChunk = ChunkPos.containing(BlockPos.containing(this.spawnPosition));
            this.spawnLevel.waitForEntities(spawnChunk, 3);
            ServerPlayer player = new ServerPlayer(PrepareSpawnTask.this.server, this.spawnLevel, cookie.gameProfile(), cookie.clientInformation());
 
            ServerPlayer var7;
            try (ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(player.problemPath(), PrepareSpawnTask.LOGGER)) {
                Optional<ValueInput> input = PrepareSpawnTask.this.server
                    .getPlayerList()
                    .loadPlayerData(PrepareSpawnTask.this.nameAndId)
                    .map(tag -> TagValueInput.create(reporter, PrepareSpawnTask.this.server.registryAccess(), tag));
                input.ifPresent(player::load);
                player.snapTo(this.spawnPosition, this.spawnAngle.x, this.spawnAngle.y);
                PrepareSpawnTask.this.server.getPlayerList().placeNewPlayer(connection, player, cookie);
                input.ifPresent(tag -> {
                    player.loadAndSpawnEnderPearls(tag);
                    player.loadAndSpawnParentVehicle(tag);
                });
                var7 = player;
            }
 
            return var7;
        }
    }
 
    private sealed interface State permits PrepareSpawnTask.Preparing, PrepareSpawnTask.Ready {
    }
}

引用的其他类

  • BlockPos

    • 引用位置: 方法调用
    • 关联成员: BlockPos.containing()
  • Connection

    • 引用位置: 参数
  • Packet

    • 引用位置: 参数
  • MinecraftServer

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

    • 引用位置: 构造调用
    • 关联成员: ChunkLoadCounter()
  • PlayerSpawnFinder

    • 引用位置: 方法调用
    • 关联成员: PlayerSpawnFinder.findSpawn()
  • ServerPlayer

    • 引用位置: 构造调用/返回值
    • 关联成员: ServerPlayer()
  • LevelLoadListener

    • 引用位置: 字段
  • CommonListenerCookie

    • 引用位置: 参数
  • ConfigurationTask

    • 引用位置: 字段/实现/方法调用/构造调用/返回值
    • 关联成员: ConfigurationTask.Type(), Type()
  • NameAndId

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

    • 引用位置: 方法调用/构造调用
    • 关联成员: ProblemReporter.ScopedCollector(), ScopedCollector()
  • ChunkPos

    • 引用位置: 方法调用
    • 关联成员: ChunkPos.containing()
  • TagValueInput

    • 引用位置: 方法调用
    • 关联成员: TagValueInput.create()
  • Vec2

    • 引用位置: 构造调用
    • 关联成员: Vec2()