minecraft-source/src/net/minecraft/server/PlayerAdvancements.java

388 lines
16 KiB
Java

package net.minecraft.server;
import java.lang.reflect.Type;
import com.google.gson.GsonBuilder;
import org.apache.logging.log4j.LogManager;
import net.minecraft.network.protocol.game.ClientboundSelectAdvancementsTabPacket;
import net.minecraft.network.protocol.Packet;
import java.util.Collection;
import net.minecraft.network.protocol.game.ClientboundUpdateAdvancementsPacket;
import net.minecraft.advancements.CriterionProgress;
import net.minecraft.advancements.CriterionTriggerInstance;
import net.minecraft.advancements.Criterion;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.TranslatableComponent;
import net.minecraft.world.level.GameRules;
import java.io.Writer;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import com.google.common.base.Charsets;
import java.io.FileOutputStream;
import java.util.stream.Stream;
import java.io.IOException;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Comparator;
import com.google.gson.JsonParseException;
import com.google.gson.JsonElement;
import net.minecraft.SharedConstants;
import net.minecraft.util.datafix.DataFixTypes;
import com.mojang.datafixers.types.DynamicOps;
import com.mojang.datafixers.Dynamic;
import com.google.gson.internal.Streams;
import com.mojang.datafixers.types.JsonOps;
import java.io.Reader;
import com.google.gson.stream.JsonReader;
import java.io.StringReader;
import com.google.common.io.Files;
import java.nio.charset.StandardCharsets;
import java.util.List;
import com.google.common.collect.Lists;
import java.util.Iterator;
import net.minecraft.advancements.CriterionTrigger;
import net.minecraft.advancements.CriteriaTriggers;
import com.google.common.collect.Sets;
import com.google.common.collect.Maps;
import javax.annotation.Nullable;
import net.minecraft.server.level.ServerPlayer;
import java.util.Set;
import net.minecraft.advancements.Advancement;
import java.io.File;
import net.minecraft.advancements.AdvancementProgress;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import com.google.gson.reflect.TypeToken;
import com.google.gson.Gson;
import org.apache.logging.log4j.Logger;
public class PlayerAdvancements {
private static final Logger LOGGER;
private static final Gson GSON;
private static final TypeToken<Map<ResourceLocation, AdvancementProgress>> TYPE_TOKEN;
private final MinecraftServer server;
private final File file;
private final Map<Advancement, AdvancementProgress> advancements;
private final Set<Advancement> visible;
private final Set<Advancement> visibilityChanged;
private final Set<Advancement> progressChanged;
private ServerPlayer player;
@Nullable
private Advancement lastSelectedTab;
private boolean isFirstPacket;
public PlayerAdvancements(final MinecraftServer minecraftServer, final File file, final ServerPlayer xe) {
this.advancements = Maps.newLinkedHashMap();
this.visible = Sets.newLinkedHashSet();
this.visibilityChanged = Sets.newLinkedHashSet();
this.progressChanged = Sets.newLinkedHashSet();
this.isFirstPacket = true;
this.server = minecraftServer;
this.file = file;
this.player = xe;
this.load();
}
public void setPlayer(final ServerPlayer xe) {
this.player = xe;
}
public void stopListening() {
for (final CriterionTrigger<?> ab3 : CriteriaTriggers.all()) {
ab3.removePlayerListeners(this);
}
}
public void reload() {
this.stopListening();
this.advancements.clear();
this.visible.clear();
this.visibilityChanged.clear();
this.progressChanged.clear();
this.isFirstPacket = true;
this.lastSelectedTab = null;
this.load();
}
private void registerListeners() {
for (final Advancement u3 : this.server.getAdvancements().getAllAdvancements()) {
this.registerListeners(u3);
}
}
private void ensureAllVisible() {
final List<Advancement> list2 = Lists.newArrayList();
for (final Map.Entry<Advancement, AdvancementProgress> entry4 : this.advancements.entrySet()) {
if (entry4.getValue().isDone()) {
list2.add(entry4.getKey());
this.progressChanged.add(entry4.getKey());
}
}
for (final Advancement u4 : list2) {
this.ensureVisibility(u4);
}
}
private void checkForAutomaticTriggers() {
for (final Advancement u3 : this.server.getAdvancements().getAllAdvancements()) {
if (u3.getCriteria().isEmpty()) {
this.award(u3, "");
u3.getRewards().grant(this.player);
}
}
}
private void load() {
if (this.file.isFile()) {
try (final JsonReader jsonReader2 = new JsonReader(new StringReader(Files.toString(this.file, StandardCharsets.UTF_8)))) {
jsonReader2.setLenient(false);
Dynamic<JsonElement> dynamic4 = (Dynamic<JsonElement>)new Dynamic((DynamicOps)JsonOps.INSTANCE, Streams.parse(jsonReader2));
if (!dynamic4.get("DataVersion").asNumber().isPresent()) {
dynamic4 = (Dynamic<JsonElement>)dynamic4.set("DataVersion", dynamic4.createInt(1343));
}
dynamic4 = (Dynamic<JsonElement>)this.server.getFixerUpper().update(DataFixTypes.ADVANCEMENTS.getType(), (Dynamic)dynamic4, dynamic4.get("DataVersion").asInt(0), SharedConstants.getCurrentVersion().getWorldVersion());
dynamic4 = (Dynamic<JsonElement>)dynamic4.remove("DataVersion");
final Map<ResourceLocation, AdvancementProgress> map5 = PlayerAdvancements.GSON.<Map<ResourceLocation, AdvancementProgress>>getAdapter(PlayerAdvancements.TYPE_TOKEN).fromJsonTree((JsonElement)dynamic4.getValue());
if (map5 == null) {
throw new JsonParseException("Found null for advancements");
}
final Stream<Map.Entry<ResourceLocation, AdvancementProgress>> stream6 = map5.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getValue));
for (final Map.Entry<ResourceLocation, AdvancementProgress> entry8 : stream6.collect(Collectors.<Map.Entry<ResourceLocation, AdvancementProgress>>toList())) {
final Advancement u9 = this.server.getAdvancements().getAdvancement(entry8.getKey());
if (u9 == null) {
PlayerAdvancements.LOGGER.warn("Ignored advancement '{}' in progress file {} - it doesn't exist anymore?", entry8.getKey(), this.file);
}
else {
this.startProgress(u9, entry8.getValue());
}
}
}
catch (JsonParseException jsonParseException2) {
PlayerAdvancements.LOGGER.error("Couldn't parse player advancements in {}", this.file, jsonParseException2);
}
catch (IOException iOException2) {
PlayerAdvancements.LOGGER.error("Couldn't access player advancements in {}", this.file, iOException2);
}
}
this.checkForAutomaticTriggers();
this.ensureAllVisible();
this.registerListeners();
}
public void save() {
final Map<ResourceLocation, AdvancementProgress> map2 = Maps.newHashMap();
for (final Map.Entry<Advancement, AdvancementProgress> entry4 : this.advancements.entrySet()) {
final AdvancementProgress w5 = entry4.getValue();
if (w5.hasProgress()) {
map2.put(entry4.getKey().getId(), w5);
}
}
if (this.file.getParentFile() != null) {
this.file.getParentFile().mkdirs();
}
final JsonElement jsonElement3 = PlayerAdvancements.GSON.toJsonTree(map2);
jsonElement3.getAsJsonObject().addProperty("DataVersion", SharedConstants.getCurrentVersion().getWorldVersion());
try (final OutputStream outputStream4 = new FileOutputStream(this.file);
final Writer writer6 = new OutputStreamWriter(outputStream4, Charsets.UTF_8.newEncoder())) {
PlayerAdvancements.GSON.toJson(jsonElement3, writer6);
}
catch (IOException iOException4) {
PlayerAdvancements.LOGGER.error("Couldn't save player advancements to {}", this.file, iOException4);
}
}
public boolean award(final Advancement u, final String string) {
boolean boolean4 = false;
final AdvancementProgress w5 = this.getOrStartProgress(u);
final boolean boolean5 = w5.isDone();
if (w5.grantProgress(string)) {
this.unregisterListeners(u);
this.progressChanged.add(u);
boolean4 = true;
if (!boolean5 && w5.isDone()) {
u.getRewards().grant(this.player);
if (u.getDisplay() != null && u.getDisplay().shouldAnnounceChat() && this.player.level.getGameRules().getBoolean(GameRules.RULE_ANNOUNCE_ADVANCEMENTS)) {
this.server.getPlayerList().broadcastMessage(new TranslatableComponent("chat.type.advancement." + u.getDisplay().getFrame().getName(), new Object[] { this.player.getDisplayName(), u.getChatComponent() }));
}
}
}
if (w5.isDone()) {
this.ensureVisibility(u);
}
return boolean4;
}
public boolean revoke(final Advancement u, final String string) {
boolean boolean4 = false;
final AdvancementProgress w5 = this.getOrStartProgress(u);
if (w5.revokeProgress(string)) {
this.registerListeners(u);
this.progressChanged.add(u);
boolean4 = true;
}
if (!w5.hasProgress()) {
this.ensureVisibility(u);
}
return boolean4;
}
private void registerListeners(final Advancement u) {
final AdvancementProgress w3 = this.getOrStartProgress(u);
if (w3.isDone()) {
return;
}
for (final Map.Entry<String, Criterion> entry5 : u.getCriteria().entrySet()) {
final CriterionProgress aa6 = w3.getCriterion(entry5.getKey());
if (aa6 != null) {
if (aa6.isDone()) {
continue;
}
final CriterionTriggerInstance ac7 = entry5.getValue().getTrigger();
if (ac7 == null) {
continue;
}
final CriterionTrigger<CriterionTriggerInstance> ab8 = CriteriaTriggers.<CriterionTriggerInstance>getCriterion(ac7.getCriterion());
if (ab8 == null) {
continue;
}
ab8.addPlayerListener(this, new CriterionTrigger.Listener<CriterionTriggerInstance>(ac7, u, entry5.getKey()));
}
}
}
private void unregisterListeners(final Advancement u) {
final AdvancementProgress w3 = this.getOrStartProgress(u);
for (final Map.Entry<String, Criterion> entry5 : u.getCriteria().entrySet()) {
final CriterionProgress aa6 = w3.getCriterion(entry5.getKey());
if (aa6 != null) {
if (!aa6.isDone() && !w3.isDone()) {
continue;
}
final CriterionTriggerInstance ac7 = entry5.getValue().getTrigger();
if (ac7 == null) {
continue;
}
final CriterionTrigger<CriterionTriggerInstance> ab8 = CriteriaTriggers.<CriterionTriggerInstance>getCriterion(ac7.getCriterion());
if (ab8 == null) {
continue;
}
ab8.removePlayerListener(this, new CriterionTrigger.Listener<CriterionTriggerInstance>(ac7, u, entry5.getKey()));
}
}
}
public void flushDirty(final ServerPlayer xe) {
if (this.isFirstPacket || !this.visibilityChanged.isEmpty() || !this.progressChanged.isEmpty()) {
final Map<ResourceLocation, AdvancementProgress> map3 = Maps.newHashMap();
final Set<Advancement> set4 = Sets.newLinkedHashSet();
final Set<ResourceLocation> set5 = Sets.newLinkedHashSet();
for (final Advancement u7 : this.progressChanged) {
if (this.visible.contains(u7)) {
map3.put(u7.getId(), this.advancements.get(u7));
}
}
for (final Advancement u7 : this.visibilityChanged) {
if (this.visible.contains(u7)) {
set4.add(u7);
}
else {
set5.add(u7.getId());
}
}
if (this.isFirstPacket || !map3.isEmpty() || !set4.isEmpty() || !set5.isEmpty()) {
xe.connection.send(new ClientboundUpdateAdvancementsPacket(this.isFirstPacket, set4, set5, map3));
this.visibilityChanged.clear();
this.progressChanged.clear();
}
}
this.isFirstPacket = false;
}
public void setSelectedTab(@Nullable final Advancement u) {
final Advancement u2 = this.lastSelectedTab;
if (u != null && u.getParent() == null && u.getDisplay() != null) {
this.lastSelectedTab = u;
}
else {
this.lastSelectedTab = null;
}
if (u2 != this.lastSelectedTab) {
this.player.connection.send(new ClientboundSelectAdvancementsTabPacket((this.lastSelectedTab == null) ? null : this.lastSelectedTab.getId()));
}
}
public AdvancementProgress getOrStartProgress(final Advancement u) {
AdvancementProgress w3 = this.advancements.get(u);
if (w3 == null) {
w3 = new AdvancementProgress();
this.startProgress(u, w3);
}
return w3;
}
private void startProgress(final Advancement u, final AdvancementProgress w) {
w.update(u.getCriteria(), u.getRequirements());
this.advancements.put(u, w);
}
private void ensureVisibility(final Advancement u) {
final boolean boolean3 = this.shouldBeVisible(u);
final boolean boolean4 = this.visible.contains(u);
if (boolean3 && !boolean4) {
this.visible.add(u);
this.visibilityChanged.add(u);
if (this.advancements.containsKey(u)) {
this.progressChanged.add(u);
}
}
else if (!boolean3 && boolean4) {
this.visible.remove(u);
this.visibilityChanged.add(u);
}
if (boolean3 != boolean4 && u.getParent() != null) {
this.ensureVisibility(u.getParent());
}
for (final Advancement u2 : u.getChildren()) {
this.ensureVisibility(u2);
}
}
private boolean shouldBeVisible(Advancement u) {
for (int integer3 = 0; u != null && integer3 <= 2; u = u.getParent(), ++integer3) {
if (integer3 == 0 && this.hasCompletedChildrenOrSelf(u)) {
return true;
}
if (u.getDisplay() == null) {
return false;
}
final AdvancementProgress w4 = this.getOrStartProgress(u);
if (w4.isDone()) {
return true;
}
if (u.getDisplay().isHidden()) {
return false;
}
}
return false;
}
private boolean hasCompletedChildrenOrSelf(final Advancement u) {
final AdvancementProgress w3 = this.getOrStartProgress(u);
if (w3.isDone()) {
return true;
}
for (final Advancement u2 : u.getChildren()) {
if (this.hasCompletedChildrenOrSelf(u2)) {
return true;
}
}
return false;
}
static {
LOGGER = LogManager.getLogger();
GSON = new GsonBuilder().registerTypeAdapter(AdvancementProgress.class, new AdvancementProgress.Serializer()).registerTypeAdapter(ResourceLocation.class, new ResourceLocation.Serializer()).setPrettyPrinting().create();
TYPE_TOKEN = new TypeToken<Map<ResourceLocation, AdvancementProgress>>() {};
}
}