Code/net/minecraft/stats/ServerStatsCounter.java

140 lines
5.8 KiB
Java

package net.minecraft.stats;
import com.google.common.collect.Sets;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonReader;
import com.mojang.datafixers.DataFixer;
import com.mojang.logging.LogUtils;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.Dynamic;
import com.mojang.serialization.JsonOps;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.protocol.game.ClientboundAwardStatsPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.player.Player;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
public class ServerStatsCounter extends StatsCounter {
private static final Logger LOGGER = LogUtils.getLogger();
private static final Codec<Map<Stat<?>, Integer>> STATS_CODEC = Codec.dispatchedMap(
BuiltInRegistries.STAT_TYPE.byNameCodec(), Util.memoize(ServerStatsCounter::createTypedStatsCodec)
)
.xmap(p_390196_ -> {
Map<Stat<?>, Integer> map = new HashMap<>();
p_390196_.forEach((p_390199_, p_390200_) -> map.putAll((Map<? extends Stat<?>, ? extends Integer>)p_390200_));
return map;
}, p_390195_ -> p_390195_.entrySet().stream().collect(Collectors.groupingBy(p_390201_ -> p_390201_.getKey().getType(), Util.toMap())));
private final MinecraftServer server;
private final File file;
private final Set<Stat<?>> dirty = Sets.newHashSet();
private static <T> Codec<Map<Stat<?>, Integer>> createTypedStatsCodec(StatType<T> p_395191_) {
Codec<T> codec = p_395191_.getRegistry().byNameCodec();
Codec<Stat<?>> codec1 = codec.flatComapMap(
p_395191_::get,
p_390205_ -> p_390205_.getType() == p_395191_
? DataResult.success((T)p_390205_.getValue())
: DataResult.error(() -> "Expected type " + p_395191_ + ", but got " + p_390205_.getType())
);
return Codec.unboundedMap(codec1, Codec.INT);
}
public ServerStatsCounter(MinecraftServer p_12816_, File p_12817_) {
this.server = p_12816_;
this.file = p_12817_;
if (p_12817_.isFile()) {
try {
this.parseLocal(p_12816_.getFixerUpper(), FileUtils.readFileToString(p_12817_));
} catch (IOException ioexception) {
LOGGER.error("Couldn't read statistics file {}", p_12817_, ioexception);
} catch (JsonParseException jsonparseexception) {
LOGGER.error("Couldn't parse statistics file {}", p_12817_, jsonparseexception);
}
}
}
public void save() {
try {
FileUtils.writeStringToFile(this.file, this.toJson());
} catch (IOException ioexception) {
LOGGER.error("Couldn't save stats", (Throwable)ioexception);
}
}
@Override
public void setValue(Player p_12827_, Stat<?> p_12828_, int p_12829_) {
super.setValue(p_12827_, p_12828_, p_12829_);
this.dirty.add(p_12828_);
}
private Set<Stat<?>> getDirty() {
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
this.dirty.clear();
return set;
}
public void parseLocal(DataFixer p_12833_, String p_12834_) {
try {
try (JsonReader jsonreader = new JsonReader(new StringReader(p_12834_))) {
jsonreader.setLenient(false);
JsonElement jsonelement = Streams.parse(jsonreader);
if (!jsonelement.isJsonNull()) {
Dynamic<JsonElement> dynamic = new Dynamic<>(JsonOps.INSTANCE, jsonelement);
dynamic = DataFixTypes.STATS.updateToCurrentVersion(p_12833_, dynamic, NbtUtils.getDataVersion(dynamic, 1343));
this.stats
.putAll(
STATS_CODEC.parse(dynamic.get("stats").orElseEmptyMap())
.resultOrPartial(p_390197_ -> LOGGER.error("Failed to parse statistics for {}: {}", this.file, p_390197_))
.orElse(Map.of())
);
return;
}
LOGGER.error("Unable to parse Stat data from {}", this.file);
}
} catch (IOException | JsonParseException jsonparseexception) {
LOGGER.error("Unable to parse Stat data from {}", this.file, jsonparseexception);
}
}
protected String toJson() {
JsonObject jsonobject = new JsonObject();
jsonobject.add("stats", STATS_CODEC.encodeStart(JsonOps.INSTANCE, this.stats).getOrThrow());
jsonobject.addProperty("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion());
return jsonobject.toString();
}
public void markAllDirty() {
this.dirty.addAll(this.stats.keySet());
}
public void sendStats(ServerPlayer p_12820_) {
Object2IntMap<Stat<?>> object2intmap = new Object2IntOpenHashMap<>();
for (Stat<?> stat : this.getDirty()) {
object2intmap.put(stat, this.getValue(stat));
}
p_12820_.connection.send(new ClientboundAwardStatsPacket(object2intmap));
}
}