PlayerAdvancements.java

net.minecraft.server.PlayerAdvancements

信息

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

    TODO

字段/常量

  • LOGGER

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

      TODO

  • GSON

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

      TODO

  • playerList

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

      TODO

  • playerSavePath

    • 类型: Path
    • 修饰符: private final
    • 源码定位: L52
    • 说明:

      TODO

  • tree

    • 类型: AdvancementTree
    • 修饰符: private
    • 源码定位: L53
    • 说明:

      TODO

  • progress

    • 类型: Map<AdvancementHolder,AdvancementProgress>
    • 修饰符: private final
    • 源码定位: L54
    • 说明:

      TODO

  • visible

    • 类型: Set<AdvancementHolder>
    • 修饰符: private final
    • 源码定位: L55
    • 说明:

      TODO

  • progressChanged

    • 类型: Set<AdvancementHolder>
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

  • rootsToUpdate

    • 类型: Set<AdvancementNode>
    • 修饰符: private final
    • 源码定位: L57
    • 说明:

      TODO

  • player

    • 类型: ServerPlayer
    • 修饰符: private
    • 源码定位: L58
    • 说明:

      TODO

  • lastSelectedTab

    • 类型: AdvancementHolder
    • 修饰符: private
    • 源码定位: L59
    • 说明:

      TODO

  • isFirstPacket

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

      TODO

  • codec

    • 类型: Codec<PlayerAdvancements.Data>
    • 修饰符: private final
    • 源码定位: L61
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.PlayerAdvancements.Data
    • 类型: record
    • 修饰符: private
    • 源码定位: L316
    • 说明:

      TODO

构造器

public PlayerAdvancements(DataFixer dataFixer, PlayerList playerList, ServerAdvancementManager manager, Path playerSavePath, ServerPlayer player) @ L63

  • 构造器名:PlayerAdvancements
  • 源码定位:L63
  • 修饰符:public

参数:

  • dataFixer: DataFixer
  • playerList: PlayerList
  • manager: ServerAdvancementManager
  • playerSavePath: Path
  • player: ServerPlayer

说明:

TODO

方法

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

public void setPlayer(ServerPlayer player) @ L73

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

参数:

  • player: ServerPlayer

说明:

TODO

public void stopListening() @ L77

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

参数:

说明:

TODO

public void reload(ServerAdvancementManager manager) @ L83

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

参数:

  • manager: ServerAdvancementManager

说明:

TODO

private void registerListeners(ServerAdvancementManager manager) @ L95

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

参数:

  • manager: ServerAdvancementManager

说明:

TODO

private void checkForAutomaticTriggers(ServerAdvancementManager manager) @ L101

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

参数:

  • manager: ServerAdvancementManager

说明:

TODO

private void load(ServerAdvancementManager manager) @ L111

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

参数:

  • manager: ServerAdvancementManager

说明:

TODO

public void save() @ L128

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

参数:

说明:

TODO

private void applyFrom(ServerAdvancementManager manager, PlayerAdvancements.Data data) @ L142

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

参数:

  • manager: ServerAdvancementManager
  • data: PlayerAdvancements.Data

说明:

TODO

private PlayerAdvancements.Data asData() @ L155

  • 方法名:asData
  • 源码定位:L155
  • 返回类型:PlayerAdvancements.Data
  • 修饰符:private

参数:

说明:

TODO

public boolean award(AdvancementHolder holder, String criterion) @ L165

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

参数:

  • holder: AdvancementHolder
  • criterion: String

说明:

TODO

public boolean revoke(AdvancementHolder advancement, String criterion) @ L190

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

参数:

  • advancement: AdvancementHolder
  • criterion: String

说明:

TODO

private void markForVisibilityUpdate(AdvancementHolder advancement) @ L207

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

参数:

  • advancement: AdvancementHolder

说明:

TODO

private void registerListeners(AdvancementHolder holder) @ L214

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

参数:

  • holder: AdvancementHolder

说明:

TODO

private <T extends CriterionTriggerInstance> void registerListener(AdvancementHolder holder, String key, Criterion<T> criterion) @ L226

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

参数:

  • holder: AdvancementHolder
  • key: String
  • criterion: Criterion

说明:

TODO

private void unregisterListeners(AdvancementHolder holder) @ L230

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

参数:

  • holder: AdvancementHolder

说明:

TODO

private <T extends CriterionTriggerInstance> void removeListener(AdvancementHolder holder, String key, Criterion<T> criterion) @ L241

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

参数:

  • holder: AdvancementHolder
  • key: String
  • criterion: Criterion

说明:

TODO

public void flushDirty(ServerPlayer player, boolean showAdvancements) @ L245

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

参数:

  • player: ServerPlayer
  • showAdvancements: boolean

说明:

TODO

public void setSelectedTab(AdvancementHolder holder) @ L272

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

参数:

  • holder: AdvancementHolder

说明:

TODO

public AdvancementProgress getOrStartProgress(AdvancementHolder advancement) @ L285

  • 方法名:getOrStartProgress
  • 源码定位:L285
  • 返回类型:AdvancementProgress
  • 修饰符:public

参数:

  • advancement: AdvancementHolder

说明:

TODO

private void startProgress(AdvancementHolder holder, AdvancementProgress progress) @ L295

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

参数:

  • holder: AdvancementHolder
  • progress: AdvancementProgress

说明:

TODO

private void updateTreeVisibility(AdvancementNode root, Set<AdvancementHolder> added, Set<Identifier> removed) @ L300

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

参数:

  • root: AdvancementNode
  • added: Set
  • removed: Set

说明:

TODO

代码

public class PlayerAdvancements {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
    private final PlayerList playerList;
    private final Path playerSavePath;
    private AdvancementTree tree;
    private final Map<AdvancementHolder, AdvancementProgress> progress = new LinkedHashMap<>();
    private final Set<AdvancementHolder> visible = new HashSet<>();
    private final Set<AdvancementHolder> progressChanged = new HashSet<>();
    private final Set<AdvancementNode> rootsToUpdate = new HashSet<>();
    private ServerPlayer player;
    private @Nullable AdvancementHolder lastSelectedTab;
    private boolean isFirstPacket = true;
    private final Codec<PlayerAdvancements.Data> codec;
 
    public PlayerAdvancements(DataFixer dataFixer, PlayerList playerList, ServerAdvancementManager manager, Path playerSavePath, ServerPlayer player) {
        this.playerList = playerList;
        this.playerSavePath = playerSavePath;
        this.player = player;
        this.tree = manager.tree();
        int defaultVersion = 1343;
        this.codec = DataFixTypes.ADVANCEMENTS.wrapCodec(PlayerAdvancements.Data.CODEC, dataFixer, 1343);
        this.load(manager);
    }
 
    public void setPlayer(ServerPlayer player) {
        this.player = player;
    }
 
    public void stopListening() {
        for (CriterionTrigger<?> trigger : BuiltInRegistries.TRIGGER_TYPES) {
            trigger.removePlayerListeners(this);
        }
    }
 
    public void reload(ServerAdvancementManager manager) {
        this.stopListening();
        this.progress.clear();
        this.visible.clear();
        this.rootsToUpdate.clear();
        this.progressChanged.clear();
        this.isFirstPacket = true;
        this.lastSelectedTab = null;
        this.tree = manager.tree();
        this.load(manager);
    }
 
    private void registerListeners(ServerAdvancementManager manager) {
        for (AdvancementHolder advancement : manager.getAllAdvancements()) {
            this.registerListeners(advancement);
        }
    }
 
    private void checkForAutomaticTriggers(ServerAdvancementManager manager) {
        for (AdvancementHolder holder : manager.getAllAdvancements()) {
            Advancement advancement = holder.value();
            if (advancement.criteria().isEmpty()) {
                this.award(holder, "");
                advancement.rewards().grant(this.player);
            }
        }
    }
 
    private void load(ServerAdvancementManager manager) {
        if (Files.isRegularFile(this.playerSavePath)) {
            try (Reader reader = Files.newBufferedReader(this.playerSavePath, StandardCharsets.UTF_8)) {
                JsonElement json = StrictJsonParser.parse(reader);
                PlayerAdvancements.Data data = this.codec.parse(JsonOps.INSTANCE, json).getOrThrow(JsonParseException::new);
                this.applyFrom(manager, data);
            } catch (JsonIOException | IOException var7) {
                LOGGER.error("Couldn't access player advancements in {}", this.playerSavePath, var7);
            } catch (JsonParseException var8) {
                LOGGER.error("Couldn't parse player advancements in {}", this.playerSavePath, var8);
            }
        }
 
        this.checkForAutomaticTriggers(manager);
        this.registerListeners(manager);
    }
 
    public void save() {
        JsonElement json = this.codec.encodeStart(JsonOps.INSTANCE, this.asData()).getOrThrow();
 
        try {
            FileUtil.createDirectoriesSafe(this.playerSavePath.getParent());
 
            try (Writer outputWriter = Files.newBufferedWriter(this.playerSavePath, StandardCharsets.UTF_8)) {
                GSON.toJson(json, GSON.newJsonWriter(outputWriter));
            }
        } catch (JsonIOException | IOException var7) {
            LOGGER.error("Couldn't save player advancements to {}", this.playerSavePath, var7);
        }
    }
 
    private void applyFrom(ServerAdvancementManager manager, PlayerAdvancements.Data data) {
        data.forEach((id, progress) -> {
            AdvancementHolder advancement = manager.get(id);
            if (advancement == null) {
                LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", id, this.playerSavePath);
            } else {
                this.startProgress(advancement, progress);
                this.progressChanged.add(advancement);
                this.markForVisibilityUpdate(advancement);
            }
        });
    }
 
    private PlayerAdvancements.Data asData() {
        Map<Identifier, AdvancementProgress> map = new LinkedHashMap<>();
        this.progress.forEach((advancement, progress) -> {
            if (progress.hasProgress()) {
                map.put(advancement.id(), progress);
            }
        });
        return new PlayerAdvancements.Data(map);
    }
 
    public boolean award(AdvancementHolder holder, String criterion) {
        boolean result = false;
        AdvancementProgress progress = this.getOrStartProgress(holder);
        boolean wasDone = progress.isDone();
        if (progress.grantProgress(criterion)) {
            this.unregisterListeners(holder);
            this.progressChanged.add(holder);
            result = true;
            if (!wasDone && progress.isDone()) {
                holder.value().rewards().grant(this.player);
                holder.value().display().ifPresent(display -> {
                    if (display.shouldAnnounceChat() && this.player.level().getGameRules().get(GameRules.SHOW_ADVANCEMENT_MESSAGES)) {
                        this.playerList.broadcastSystemMessage(display.getType().createAnnouncement(holder, this.player), false);
                    }
                });
            }
        }
 
        if (!wasDone && progress.isDone()) {
            this.markForVisibilityUpdate(holder);
        }
 
        return result;
    }
 
    public boolean revoke(AdvancementHolder advancement, String criterion) {
        boolean result = false;
        AdvancementProgress progress = this.getOrStartProgress(advancement);
        boolean wasDone = progress.isDone();
        if (progress.revokeProgress(criterion)) {
            this.registerListeners(advancement);
            this.progressChanged.add(advancement);
            result = true;
        }
 
        if (wasDone && !progress.isDone()) {
            this.markForVisibilityUpdate(advancement);
        }
 
        return result;
    }
 
    private void markForVisibilityUpdate(AdvancementHolder advancement) {
        AdvancementNode node = this.tree.get(advancement);
        if (node != null) {
            this.rootsToUpdate.add(node.root());
        }
    }
 
    private void registerListeners(AdvancementHolder holder) {
        AdvancementProgress advancementProgress = this.getOrStartProgress(holder);
        if (!advancementProgress.isDone()) {
            for (Entry<String, Criterion<?>> entry : holder.value().criteria().entrySet()) {
                CriterionProgress criterionProgress = advancementProgress.getCriterion(entry.getKey());
                if (criterionProgress != null && !criterionProgress.isDone()) {
                    this.registerListener(holder, entry.getKey(), entry.getValue());
                }
            }
        }
    }
 
    private <T extends CriterionTriggerInstance> void registerListener(AdvancementHolder holder, String key, Criterion<T> criterion) {
        criterion.trigger().addPlayerListener(this, new CriterionTrigger.Listener<>(criterion.triggerInstance(), holder, key));
    }
 
    private void unregisterListeners(AdvancementHolder holder) {
        AdvancementProgress advancementProgress = this.getOrStartProgress(holder);
 
        for (Entry<String, Criterion<?>> entry : holder.value().criteria().entrySet()) {
            CriterionProgress criterionProgress = advancementProgress.getCriterion(entry.getKey());
            if (criterionProgress != null && (criterionProgress.isDone() || advancementProgress.isDone())) {
                this.removeListener(holder, entry.getKey(), entry.getValue());
            }
        }
    }
 
    private <T extends CriterionTriggerInstance> void removeListener(AdvancementHolder holder, String key, Criterion<T> criterion) {
        criterion.trigger().removePlayerListener(this, new CriterionTrigger.Listener<>(criterion.triggerInstance(), holder, key));
    }
 
    public void flushDirty(ServerPlayer player, boolean showAdvancements) {
        if (this.isFirstPacket || !this.rootsToUpdate.isEmpty() || !this.progressChanged.isEmpty()) {
            Map<Identifier, AdvancementProgress> progress = new HashMap<>();
            Set<AdvancementHolder> added = new HashSet<>();
            Set<Identifier> removed = new HashSet<>();
 
            for (AdvancementNode root : this.rootsToUpdate) {
                this.updateTreeVisibility(root, added, removed);
            }
 
            this.rootsToUpdate.clear();
 
            for (AdvancementHolder holder : this.progressChanged) {
                if (this.visible.contains(holder)) {
                    progress.put(holder.id(), this.progress.get(holder));
                }
            }
 
            this.progressChanged.clear();
            if (!progress.isEmpty() || !added.isEmpty() || !removed.isEmpty()) {
                player.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, added, removed, progress, showAdvancements));
            }
        }
 
        this.isFirstPacket = false;
    }
 
    public void setSelectedTab(@Nullable AdvancementHolder holder) {
        AdvancementHolder old = this.lastSelectedTab;
        if (holder != null && holder.value().isRoot() && holder.value().display().isPresent()) {
            this.lastSelectedTab = holder;
        } else {
            this.lastSelectedTab = null;
        }
 
        if (old != this.lastSelectedTab) {
            this.player.connection.send(new ClientboundSelectAdvancementsTabPacket(this.lastSelectedTab == null ? null : this.lastSelectedTab.id()));
        }
    }
 
    public AdvancementProgress getOrStartProgress(AdvancementHolder advancement) {
        AdvancementProgress progress = this.progress.get(advancement);
        if (progress == null) {
            progress = new AdvancementProgress();
            this.startProgress(advancement, progress);
        }
 
        return progress;
    }
 
    private void startProgress(AdvancementHolder holder, AdvancementProgress progress) {
        progress.update(holder.value().requirements());
        this.progress.put(holder, progress);
    }
 
    private void updateTreeVisibility(AdvancementNode root, Set<AdvancementHolder> added, Set<Identifier> removed) {
        AdvancementVisibilityEvaluator.evaluateVisibility(root, node -> this.getOrStartProgress(node.holder()).isDone(), (node, shouldBeVisible) -> {
            AdvancementHolder advancement = node.holder();
            if (shouldBeVisible) {
                if (this.visible.add(advancement)) {
                    added.add(advancement);
                    if (this.progress.containsKey(advancement)) {
                        this.progressChanged.add(advancement);
                    }
                }
            } else if (this.visible.remove(advancement)) {
                removed.add(advancement.id());
            }
        });
    }
 
    private record Data(Map<Identifier, AdvancementProgress> map) {
        public static final Codec<PlayerAdvancements.Data> CODEC = Codec.unboundedMap(Identifier.CODEC, AdvancementProgress.CODEC)
            .xmap(PlayerAdvancements.Data::new, PlayerAdvancements.Data::map);
 
        public void forEach(BiConsumer<Identifier, AdvancementProgress> consumer) {
            this.map.entrySet().stream().sorted(Entry.comparingByValue()).forEach(entry -> consumer.accept(entry.getKey(), entry.getValue()));
        }
    }
}

引用的其他类