Initial Commit

This commit is contained in:
richard committed 2026-11-13 22:25:04 +01:00
1 parent 377b32db6e
commit 2d9a5eecba
14134 files changed
+1160982

No files matched your search

@@ -0,0 +1,100 @@
package net.minecraft.stats;
import com.google.common.collect.Sets;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.inventory.RecipeBookMenu;
import net.minecraft.world.inventory.RecipeBookType;
import net.minecraft.world.item.crafting.Recipe;
public class RecipeBook {
protected final Set<ResourceLocation> known = Sets.newHashSet();
protected final Set<ResourceLocation> highlight = Sets.newHashSet();
private final RecipeBookSettings bookSettings = new RecipeBookSettings();
public void copyOverData(RecipeBook pOther) {
this.known.clear();
this.highlight.clear();
this.bookSettings.replaceFrom(pOther.bookSettings);
this.known.addAll(pOther.known);
this.highlight.addAll(pOther.highlight);
}
public void add(Recipe<?> pRecipe) {
if (!pRecipe.isSpecial()) {
this.add(pRecipe.getId());
}
}
protected void add(ResourceLocation pRecipeId) {
this.known.add(pRecipeId);
}
public boolean contains(@Nullable Recipe<?> pRecipe) {
return pRecipe == null ? false : this.known.contains(pRecipe.getId());
}
public boolean contains(ResourceLocation pRecipeId) {
return this.known.contains(pRecipeId);
}
public void remove(Recipe<?> pRecipe) {
this.remove(pRecipe.getId());
}
protected void remove(ResourceLocation pRecipeId) {
this.known.remove(pRecipeId);
this.highlight.remove(pRecipeId);
}
public boolean willHighlight(Recipe<?> pRecipe) {
return this.highlight.contains(pRecipe.getId());
}
public void removeHighlight(Recipe<?> pRecipe) {
this.highlight.remove(pRecipe.getId());
}
public void addHighlight(Recipe<?> pRecipe) {
this.addHighlight(pRecipe.getId());
}
protected void addHighlight(ResourceLocation pRecipeId) {
this.highlight.add(pRecipeId);
}
public boolean isOpen(RecipeBookType pBookType) {
return this.bookSettings.isOpen(pBookType);
}
public void setOpen(RecipeBookType pBookType, boolean pOpen) {
this.bookSettings.setOpen(pBookType, pOpen);
}
public boolean isFiltering(RecipeBookMenu<?> pBookMenu) {
return this.isFiltering(pBookMenu.getRecipeBookType());
}
public boolean isFiltering(RecipeBookType pBookType) {
return this.bookSettings.isFiltering(pBookType);
}
public void setFiltering(RecipeBookType pBookType, boolean pFiltering) {
this.bookSettings.setFiltering(pBookType, pFiltering);
}
public void setBookSettings(RecipeBookSettings pSettings) {
this.bookSettings.replaceFrom(pSettings);
}
public RecipeBookSettings getBookSettings() {
return this.bookSettings.copy();
}
public void setBookSetting(RecipeBookType pBookType, boolean pOpen, boolean pFiltering) {
this.bookSettings.setOpen(pBookType, pOpen);
this.bookSettings.setFiltering(pBookType, pFiltering);
}
}
@@ -0,0 +1,155 @@
package net.minecraft.stats;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Pair;
import java.util.Map;
import net.minecraft.Util;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.world.inventory.RecipeBookType;
public final class RecipeBookSettings {
private static final Map<RecipeBookType, Pair<String, String>> TAG_FIELDS = new java.util.HashMap<>(ImmutableMap.of(RecipeBookType.CRAFTING, Pair.of("isGuiOpen", "isFilteringCraftable"), RecipeBookType.FURNACE, Pair.of("isFurnaceGuiOpen", "isFurnaceFilteringCraftable"), RecipeBookType.BLAST_FURNACE, Pair.of("isBlastingFurnaceGuiOpen", "isBlastingFurnaceFilteringCraftable"), RecipeBookType.SMOKER, Pair.of("isSmokerGuiOpen", "isSmokerFilteringCraftable")));
private final Map<RecipeBookType, RecipeBookSettings.TypeSettings> states;
private RecipeBookSettings(Map<RecipeBookType, RecipeBookSettings.TypeSettings> pStates) {
this.states = pStates;
}
public RecipeBookSettings() {
this(Util.make(Maps.newEnumMap(RecipeBookType.class), (p_12740_) -> {
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
p_12740_.put(recipebooktype, new RecipeBookSettings.TypeSettings(false, false));
}
}));
}
public boolean isOpen(RecipeBookType pBookType) {
return (this.states.get(pBookType)).open;
}
public void setOpen(RecipeBookType pBookType, boolean pOpen) {
(this.states.get(pBookType)).open = pOpen;
}
public boolean isFiltering(RecipeBookType pBookType) {
return (this.states.get(pBookType)).filtering;
}
public void setFiltering(RecipeBookType pBookType, boolean pFiltering) {
(this.states.get(pBookType)).filtering = pFiltering;
}
public static RecipeBookSettings read(FriendlyByteBuf pBuffer) {
Map<RecipeBookType, RecipeBookSettings.TypeSettings> map = Maps.newEnumMap(RecipeBookType.class);
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
boolean flag = pBuffer.readBoolean();
boolean flag1 = pBuffer.readBoolean();
map.put(recipebooktype, new RecipeBookSettings.TypeSettings(flag, flag1));
}
return new RecipeBookSettings(map);
}
public void write(FriendlyByteBuf pBuffer) {
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = this.states.get(recipebooktype);
if (recipebooksettings$typesettings == null) {
pBuffer.writeBoolean(false);
pBuffer.writeBoolean(false);
} else {
pBuffer.writeBoolean(recipebooksettings$typesettings.open);
pBuffer.writeBoolean(recipebooksettings$typesettings.filtering);
}
}
}
public static RecipeBookSettings read(CompoundTag pTag) {
Map<RecipeBookType, RecipeBookSettings.TypeSettings> map = Maps.newEnumMap(RecipeBookType.class);
TAG_FIELDS.forEach((p_12750_, p_12751_) -> {
boolean flag = pTag.getBoolean(p_12751_.getFirst());
boolean flag1 = pTag.getBoolean(p_12751_.getSecond());
map.put(p_12750_, new RecipeBookSettings.TypeSettings(flag, flag1));
});
return new RecipeBookSettings(map);
}
public void write(CompoundTag pTag) {
TAG_FIELDS.forEach((p_12745_, p_12746_) -> {
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = this.states.get(p_12745_);
pTag.putBoolean(p_12746_.getFirst(), recipebooksettings$typesettings.open);
pTag.putBoolean(p_12746_.getSecond(), recipebooksettings$typesettings.filtering);
});
}
public RecipeBookSettings copy() {
Map<RecipeBookType, RecipeBookSettings.TypeSettings> map = Maps.newEnumMap(RecipeBookType.class);
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = this.states.get(recipebooktype);
map.put(recipebooktype, recipebooksettings$typesettings.copy());
}
return new RecipeBookSettings(map);
}
public void replaceFrom(RecipeBookSettings pOther) {
this.states.clear();
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = pOther.states.get(recipebooktype);
this.states.put(recipebooktype, recipebooksettings$typesettings.copy());
}
}
public boolean equals(Object pOther) {
return this == pOther || pOther instanceof RecipeBookSettings && this.states.equals(((RecipeBookSettings)pOther).states);
}
public int hashCode() {
return this.states.hashCode();
}
static final class TypeSettings {
boolean open;
boolean filtering;
public TypeSettings(boolean pOpen, boolean pFiltering) {
this.open = pOpen;
this.filtering = pFiltering;
}
public RecipeBookSettings.TypeSettings copy() {
return new RecipeBookSettings.TypeSettings(this.open, this.filtering);
}
public boolean equals(Object pOther) {
if (this == pOther) {
return true;
} else if (!(pOther instanceof RecipeBookSettings.TypeSettings)) {
return false;
} else {
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = (RecipeBookSettings.TypeSettings)pOther;
return this.open == recipebooksettings$typesettings.open && this.filtering == recipebooksettings$typesettings.filtering;
}
}
public int hashCode() {
int i = this.open ? 1 : 0;
return 31 * i + (this.filtering ? 1 : 0);
}
public String toString() {
return "[open=" + this.open + ", filtering=" + this.filtering + "]";
}
}
//FORGE -- called automatically on Enum creation - used for serialization
public static void addTagsForType(RecipeBookType type, String openTag, String filteringTag) {
TAG_FIELDS.put(type, Pair.of(openTag, filteringTag));
}
}
@@ -0,0 +1,119 @@
package net.minecraft.stats;
import com.google.common.collect.Lists;
import com.mojang.logging.LogUtils;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import net.minecraft.ResourceLocationException;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.network.protocol.game.ClientboundRecipePacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.item.crafting.RecipeManager;
import org.slf4j.Logger;
public class ServerRecipeBook extends RecipeBook {
public static final String RECIPE_BOOK_TAG = "recipeBook";
private static final Logger LOGGER = LogUtils.getLogger();
public int addRecipes(Collection<Recipe<?>> pRecipes, ServerPlayer pPlayer) {
List<ResourceLocation> list = Lists.newArrayList();
int i = 0;
for(Recipe<?> recipe : pRecipes) {
ResourceLocation resourcelocation = recipe.getId();
if (!this.known.contains(resourcelocation) && !recipe.isSpecial()) {
this.add(resourcelocation);
this.addHighlight(resourcelocation);
list.add(resourcelocation);
CriteriaTriggers.RECIPE_UNLOCKED.trigger(pPlayer, recipe);
++i;
}
}
if (list.size() > 0) {
this.sendRecipes(ClientboundRecipePacket.State.ADD, pPlayer, list);
}
return i;
}
public int removeRecipes(Collection<Recipe<?>> pRecipes, ServerPlayer pPlayer) {
List<ResourceLocation> list = Lists.newArrayList();
int i = 0;
for(Recipe<?> recipe : pRecipes) {
ResourceLocation resourcelocation = recipe.getId();
if (this.known.contains(resourcelocation)) {
this.remove(resourcelocation);
list.add(resourcelocation);
++i;
}
}
this.sendRecipes(ClientboundRecipePacket.State.REMOVE, pPlayer, list);
return i;
}
private void sendRecipes(ClientboundRecipePacket.State pState, ServerPlayer pPlayer, List<ResourceLocation> pRecipes) {
pPlayer.connection.send(new ClientboundRecipePacket(pState, pRecipes, Collections.emptyList(), this.getBookSettings()));
}
public CompoundTag toNbt() {
CompoundTag compoundtag = new CompoundTag();
this.getBookSettings().write(compoundtag);
ListTag listtag = new ListTag();
for(ResourceLocation resourcelocation : this.known) {
listtag.add(StringTag.valueOf(resourcelocation.toString()));
}
compoundtag.put("recipes", listtag);
ListTag listtag1 = new ListTag();
for(ResourceLocation resourcelocation1 : this.highlight) {
listtag1.add(StringTag.valueOf(resourcelocation1.toString()));
}
compoundtag.put("toBeDisplayed", listtag1);
return compoundtag;
}
public void fromNbt(CompoundTag pTag, RecipeManager pRecipeManager) {
this.setBookSettings(RecipeBookSettings.read(pTag));
ListTag listtag = pTag.getList("recipes", 8);
this.loadRecipes(listtag, this::add, pRecipeManager);
ListTag listtag1 = pTag.getList("toBeDisplayed", 8);
this.loadRecipes(listtag1, this::addHighlight, pRecipeManager);
}
private void loadRecipes(ListTag pTags, Consumer<Recipe<?>> pRecipeConsumer, RecipeManager pRecipeManager) {
for(int i = 0; i < pTags.size(); ++i) {
String s = pTags.getString(i);
try {
ResourceLocation resourcelocation = new ResourceLocation(s);
Optional<? extends Recipe<?>> optional = pRecipeManager.byKey(resourcelocation);
if (!optional.isPresent()) {
LOGGER.error("Tried to load unrecognized recipe: {} removed now.", (Object)resourcelocation);
} else {
pRecipeConsumer.accept(optional.get());
}
} catch (ResourceLocationException resourcelocationexception) {
LOGGER.error("Tried to load improperly formatted recipe: {} removed now.", (Object)s);
}
}
}
public void sendInitialRecipeBook(ServerPlayer pPlayer) {
pPlayer.connection.send(new ClientboundRecipePacket(ClientboundRecipePacket.State.INIT, this.known, this.highlight, this.getBookSettings()));
}
}
@@ -0,0 +1,190 @@
package net.minecraft.stats;
import com.google.common.collect.Maps;
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.JsonPrimitive;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonReader;
import com.mojang.datafixers.DataFixer;
import com.mojang.logging.LogUtils;
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.Map;
import java.util.Optional;
import java.util.Set;
import net.minecraft.SharedConstants;
import net.minecraft.Util;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtUtils;
import net.minecraft.network.protocol.game.ClientboundAwardStatsPacket;
import net.minecraft.resources.ResourceLocation;
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;
/**
* Server-side implementation of {@link net.minecraft.stats.StatsCounter}; handles counting, serialising, and de-
* serialising statistics, as well as sending them to connected clients via the {@linkplain
* net.minecraft.network.protocol.game.ClientboundAwardStatsPacket award stats packet}.
*/
public class ServerStatsCounter extends StatsCounter {
private static final Logger LOGGER = LogUtils.getLogger();
private final MinecraftServer server;
private final File file;
private final Set<Stat<?>> dirty = Sets.newHashSet();
public ServerStatsCounter(MinecraftServer pServer, File pFile) {
this.server = pServer;
this.file = pFile;
if (pFile.isFile()) {
try {
this.parseLocal(pServer.getFixerUpper(), FileUtils.readFileToString(pFile));
} catch (IOException ioexception) {
LOGGER.error("Couldn't read statistics file {}", pFile, ioexception);
} catch (JsonParseException jsonparseexception) {
LOGGER.error("Couldn't parse statistics file {}", pFile, jsonparseexception);
}
}
}
public void save() {
try {
FileUtils.writeStringToFile(this.file, this.toJson());
} catch (IOException ioexception) {
LOGGER.error("Couldn't save stats", (Throwable)ioexception);
}
}
public void setValue(Player pPlayer, Stat<?> pStat, int pValue) {
super.setValue(pPlayer, pStat, pValue);
this.dirty.add(pStat);
}
private Set<Stat<?>> getDirty() {
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
this.dirty.clear();
return set;
}
public void parseLocal(DataFixer pFixerUpper, String pJson) {
try {
try (JsonReader jsonreader = new JsonReader(new StringReader(pJson))) {
jsonreader.setLenient(false);
JsonElement jsonelement = Streams.parse(jsonreader);
if (!jsonelement.isJsonNull()) {
CompoundTag compoundtag = fromJson(jsonelement.getAsJsonObject());
compoundtag = DataFixTypes.STATS.updateToCurrentVersion(pFixerUpper, compoundtag, NbtUtils.getDataVersion(compoundtag, 1343));
if (!compoundtag.contains("stats", 10)) {
return;
}
CompoundTag compoundtag1 = compoundtag.getCompound("stats");
for(String s : compoundtag1.getAllKeys()) {
if (compoundtag1.contains(s, 10)) {
Util.ifElse(BuiltInRegistries.STAT_TYPE.getOptional(new ResourceLocation(s)), (p_12844_) -> {
CompoundTag compoundtag2 = compoundtag1.getCompound(s);
for(String s1 : compoundtag2.getAllKeys()) {
if (compoundtag2.contains(s1, 99)) {
Util.ifElse(this.getStat(p_12844_, s1), (p_144252_) -> {
this.stats.put(p_144252_, compoundtag2.getInt(s1));
}, () -> {
LOGGER.warn("Invalid statistic in {}: Don't know what {} is", this.file, s1);
});
} else {
LOGGER.warn("Invalid statistic value in {}: Don't know what {} is for key {}", this.file, compoundtag2.get(s1), s1);
}
}
}, () -> {
LOGGER.warn("Invalid statistic type in {}: Don't know what {} is", this.file, s);
});
}
}
return;
}
LOGGER.error("Unable to parse Stat data from {}", (Object)this.file);
}
} catch (IOException | JsonParseException jsonparseexception) {
LOGGER.error("Unable to parse Stat data from {}", this.file, jsonparseexception);
}
}
private <T> Optional<Stat<T>> getStat(StatType<T> pType, String pLocation) {
return Optional.ofNullable(ResourceLocation.tryParse(pLocation)).flatMap(pType.getRegistry()::getOptional).map(pType::get);
}
private static CompoundTag fromJson(JsonObject pJson) {
CompoundTag compoundtag = new CompoundTag();
for(Map.Entry<String, JsonElement> entry : pJson.entrySet()) {
JsonElement jsonelement = entry.getValue();
if (jsonelement.isJsonObject()) {
compoundtag.put(entry.getKey(), fromJson(jsonelement.getAsJsonObject()));
} else if (jsonelement.isJsonPrimitive()) {
JsonPrimitive jsonprimitive = jsonelement.getAsJsonPrimitive();
if (jsonprimitive.isNumber()) {
compoundtag.putInt(entry.getKey(), jsonprimitive.getAsInt());
}
}
}
return compoundtag;
}
protected String toJson() {
Map<StatType<?>, JsonObject> map = Maps.newHashMap();
for(Object2IntMap.Entry<Stat<?>> entry : this.stats.object2IntEntrySet()) {
Stat<?> stat = entry.getKey();
map.computeIfAbsent(stat.getType(), (p_12822_) -> {
return new JsonObject();
}).addProperty(getKey(stat).toString(), entry.getIntValue());
}
JsonObject jsonobject = new JsonObject();
for(Map.Entry<StatType<?>, JsonObject> entry1 : map.entrySet()) {
jsonobject.add(BuiltInRegistries.STAT_TYPE.getKey(entry1.getKey()).toString(), entry1.getValue());
}
JsonObject jsonobject1 = new JsonObject();
jsonobject1.add("stats", jsonobject);
jsonobject1.addProperty("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion());
return jsonobject1.toString();
}
private static <T> ResourceLocation getKey(Stat<T> pStat) {
return pStat.getType().getRegistry().getKey(pStat.getValue());
}
public void markAllDirty() {
this.dirty.addAll(this.stats.keySet());
}
public void sendStats(ServerPlayer pPlayer) {
Object2IntMap<Stat<?>> object2intmap = new Object2IntOpenHashMap<>();
for(Stat<?> stat : this.getDirty()) {
object2intmap.put(stat, this.getValue(stat));
}
pPlayer.connection.send(new ClientboundAwardStatsPacket(object2intmap));
}
}
@@ -0,0 +1,72 @@
package net.minecraft.stats;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.scores.criteria.ObjectiveCriteria;
/**
* An immutable statistic to be counted for a particular entry in the {@linkplain #type}'s registry. This is used as a
* key in a {@link net.minecraft.stats.StatsCounter} for a corresponding count.
* <p>
* By default, the statistic's {@linkplain #getName() name} is formatted {@code <stat type namespace>.<stat type
* path>:<value namespace>.<value path>}, as created by {@link #buildName(StatType, Object)}.
*
* @param <T> the type of the registry entry for this statistic
* @see net.minecraft.stats.StatType
* @see net.minecraft.stats.Stats
*/
public class Stat<T> extends ObjectiveCriteria {
private final StatFormatter formatter;
/** The registry entry for this statistic. */
private final T value;
/** The parent statistic type. */
private final StatType<T> type;
protected Stat(StatType<T> pType, T pValue, StatFormatter pFormatter) {
super(buildName(pType, pValue));
this.type = pType;
this.formatter = pFormatter;
this.value = pValue;
}
/**
* @return the name for the specified {@code type} and {@code value} in the form {@code <stat type namespace>.<stat
* type path>:<value namespace>.<value path>}
*/
public static <T> String buildName(StatType<T> pType, T pValue) {
return locationToKey(BuiltInRegistries.STAT_TYPE.getKey(pType)) + ":" + locationToKey(pType.getRegistry().getKey(pValue));
}
/**
* @return the specified {@code location} as a string with {@code .} as the separator character
*/
private static <T> String locationToKey(@Nullable ResourceLocation pLocation) {
return pLocation.toString().replace(':', '.');
}
public StatType<T> getType() {
return this.type;
}
public T getValue() {
return this.value;
}
public String format(int pValue) {
return this.formatter.format(pValue);
}
public boolean equals(Object pOther) {
return this == pOther || pOther instanceof Stat && Objects.equals(this.getName(), ((Stat)pOther).getName());
}
public int hashCode() {
return this.getName().hashCode();
}
public String toString() {
return "Stat{name=" + this.getName() + ", formatter=" + this.formatter + "}";
}
}
@@ -0,0 +1,53 @@
package net.minecraft.stats;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import net.minecraft.Util;
/**
* A formatter for a {@linkplain Stat statistic}'s corresponding count.
*/
public interface StatFormatter {
DecimalFormat DECIMAL_FORMAT = Util.make(new DecimalFormat("########0.00"), (p_12881_) -> {
p_12881_.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT));
});
StatFormatter DEFAULT = NumberFormat.getIntegerInstance(Locale.US)::format;
StatFormatter DIVIDE_BY_TEN = (p_12885_) -> {
return DECIMAL_FORMAT.format((double)p_12885_ * 0.1D);
};
StatFormatter DISTANCE = (p_12883_) -> {
double d0 = (double)p_12883_ / 100.0D;
double d1 = d0 / 1000.0D;
if (d1 > 0.5D) {
return DECIMAL_FORMAT.format(d1) + " km";
} else {
return d0 > 0.5D ? DECIMAL_FORMAT.format(d0) + " m" : p_12883_ + " cm";
}
};
StatFormatter TIME = (p_12879_) -> {
double d0 = (double)p_12879_ / 20.0D;
double d1 = d0 / 60.0D;
double d2 = d1 / 60.0D;
double d3 = d2 / 24.0D;
double d4 = d3 / 365.0D;
if (d4 > 0.5D) {
return DECIMAL_FORMAT.format(d4) + " y";
} else if (d3 > 0.5D) {
return DECIMAL_FORMAT.format(d3) + " d";
} else if (d2 > 0.5D) {
return DECIMAL_FORMAT.format(d2) + " h";
} else {
return d1 > 0.5D ? DECIMAL_FORMAT.format(d1) + " m" : d0 + " s";
}
};
/**
* Formats the specified {@code value} of a statistic.
*
* @return the formatted {@code value}
* @param pValue the statistic's associated count to format
*/
String format(int pValue);
}
@@ -0,0 +1,75 @@
package net.minecraft.stats;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import javax.annotation.Nullable;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
/**
* Holds a map of {@linkplain net.minecraft.stats.Stat statistics} with type {@code T} for a corresponding {@link
* #registry}.
* <p>
* A single type usually defines a particular thing to be counted, such as {@linkplain
* net.minecraft.stats.Stats#ITEM_USED the number of items used} or {@link net.minecraft.stats.Stats#BLOCK_MINED the
* number of blocks mined}. However, there is also a {@link net.minecraft.stats.Stats#CUSTOM custom type} which uses
* entries from the {@linkplain Registry#CUSTOM_STAT custom stat registry}. This is keyed by a {@link
* net.minecraft.resources.ResourceLocation} and can be used to count any statistic that doesn't require an associated
* {@link net.minecraft.core.Registry} entry.
*
* @param <T> the type of the associated registry's entry values
* @see net.minecraft.stats.Stat
* @see net.minecraft.stats.Stats
* @see net.minecraft.core.Registry#STAT_TYPE
* @see net.minecraft.core.Registry#CUSTOM_STAT
*/
public class StatType<T> implements Iterable<Stat<T>> {
private final Registry<T> registry;
/**
* A map of registry entries to their corresponding {@link Stat statistic}. Lazily populated by {@link #get(Object,
* StatFormatter)}.
*/
private final Map<T, Stat<T>> map = new IdentityHashMap<>();
@Nullable
private Component displayName;
public StatType(Registry<T> pRegistry) {
this.registry = pRegistry;
}
public boolean contains(T pValue) {
return this.map.containsKey(pValue);
}
public Stat<T> get(T pValue, StatFormatter pFormatter) {
return this.map.computeIfAbsent(pValue, (p_12896_) -> {
return new Stat<>(this, p_12896_, pFormatter);
});
}
public Registry<T> getRegistry() {
return this.registry;
}
public Iterator<Stat<T>> iterator() {
return this.map.values().iterator();
}
public Stat<T> get(T pValue) {
return this.get(pValue, StatFormatter.DEFAULT);
}
public String getTranslationKey() {
return "stat_type." + BuiltInRegistries.STAT_TYPE.getKey(this).toString().replace(':', '.');
}
public Component getDisplayName() {
if (this.displayName == null) {
this.displayName = Component.translatable(this.getTranslationKey());
}
return this.displayName;
}
}
@@ -0,0 +1,106 @@
package net.minecraft.stats;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
public class Stats {
public static final StatType<Block> BLOCK_MINED = makeRegistryStatType("mined", BuiltInRegistries.BLOCK);
public static final StatType<Item> ITEM_CRAFTED = makeRegistryStatType("crafted", BuiltInRegistries.ITEM);
public static final StatType<Item> ITEM_USED = makeRegistryStatType("used", BuiltInRegistries.ITEM);
public static final StatType<Item> ITEM_BROKEN = makeRegistryStatType("broken", BuiltInRegistries.ITEM);
public static final StatType<Item> ITEM_PICKED_UP = makeRegistryStatType("picked_up", BuiltInRegistries.ITEM);
public static final StatType<Item> ITEM_DROPPED = makeRegistryStatType("dropped", BuiltInRegistries.ITEM);
public static final StatType<EntityType<?>> ENTITY_KILLED = makeRegistryStatType("killed", BuiltInRegistries.ENTITY_TYPE);
public static final StatType<EntityType<?>> ENTITY_KILLED_BY = makeRegistryStatType("killed_by", BuiltInRegistries.ENTITY_TYPE);
public static final StatType<ResourceLocation> CUSTOM = makeRegistryStatType("custom", BuiltInRegistries.CUSTOM_STAT);
public static final ResourceLocation LEAVE_GAME = makeCustomStat("leave_game", StatFormatter.DEFAULT);
public static final ResourceLocation PLAY_TIME = makeCustomStat("play_time", StatFormatter.TIME);
public static final ResourceLocation TOTAL_WORLD_TIME = makeCustomStat("total_world_time", StatFormatter.TIME);
public static final ResourceLocation TIME_SINCE_DEATH = makeCustomStat("time_since_death", StatFormatter.TIME);
public static final ResourceLocation TIME_SINCE_REST = makeCustomStat("time_since_rest", StatFormatter.TIME);
public static final ResourceLocation CROUCH_TIME = makeCustomStat("sneak_time", StatFormatter.TIME);
public static final ResourceLocation WALK_ONE_CM = makeCustomStat("walk_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation CROUCH_ONE_CM = makeCustomStat("crouch_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation SPRINT_ONE_CM = makeCustomStat("sprint_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation WALK_ON_WATER_ONE_CM = makeCustomStat("walk_on_water_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation FALL_ONE_CM = makeCustomStat("fall_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation CLIMB_ONE_CM = makeCustomStat("climb_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation FLY_ONE_CM = makeCustomStat("fly_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation WALK_UNDER_WATER_ONE_CM = makeCustomStat("walk_under_water_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation MINECART_ONE_CM = makeCustomStat("minecart_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation BOAT_ONE_CM = makeCustomStat("boat_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation PIG_ONE_CM = makeCustomStat("pig_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation HORSE_ONE_CM = makeCustomStat("horse_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation AVIATE_ONE_CM = makeCustomStat("aviate_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation SWIM_ONE_CM = makeCustomStat("swim_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation STRIDER_ONE_CM = makeCustomStat("strider_one_cm", StatFormatter.DISTANCE);
public static final ResourceLocation JUMP = makeCustomStat("jump", StatFormatter.DEFAULT);
public static final ResourceLocation DROP = makeCustomStat("drop", StatFormatter.DEFAULT);
public static final ResourceLocation DAMAGE_DEALT = makeCustomStat("damage_dealt", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_DEALT_ABSORBED = makeCustomStat("damage_dealt_absorbed", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_DEALT_RESISTED = makeCustomStat("damage_dealt_resisted", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_TAKEN = makeCustomStat("damage_taken", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_BLOCKED_BY_SHIELD = makeCustomStat("damage_blocked_by_shield", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_ABSORBED = makeCustomStat("damage_absorbed", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DAMAGE_RESISTED = makeCustomStat("damage_resisted", StatFormatter.DIVIDE_BY_TEN);
public static final ResourceLocation DEATHS = makeCustomStat("deaths", StatFormatter.DEFAULT);
public static final ResourceLocation MOB_KILLS = makeCustomStat("mob_kills", StatFormatter.DEFAULT);
public static final ResourceLocation ANIMALS_BRED = makeCustomStat("animals_bred", StatFormatter.DEFAULT);
public static final ResourceLocation PLAYER_KILLS = makeCustomStat("player_kills", StatFormatter.DEFAULT);
public static final ResourceLocation FISH_CAUGHT = makeCustomStat("fish_caught", StatFormatter.DEFAULT);
public static final ResourceLocation TALKED_TO_VILLAGER = makeCustomStat("talked_to_villager", StatFormatter.DEFAULT);
public static final ResourceLocation TRADED_WITH_VILLAGER = makeCustomStat("traded_with_villager", StatFormatter.DEFAULT);
public static final ResourceLocation EAT_CAKE_SLICE = makeCustomStat("eat_cake_slice", StatFormatter.DEFAULT);
public static final ResourceLocation FILL_CAULDRON = makeCustomStat("fill_cauldron", StatFormatter.DEFAULT);
public static final ResourceLocation USE_CAULDRON = makeCustomStat("use_cauldron", StatFormatter.DEFAULT);
public static final ResourceLocation CLEAN_ARMOR = makeCustomStat("clean_armor", StatFormatter.DEFAULT);
public static final ResourceLocation CLEAN_BANNER = makeCustomStat("clean_banner", StatFormatter.DEFAULT);
public static final ResourceLocation CLEAN_SHULKER_BOX = makeCustomStat("clean_shulker_box", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_BREWINGSTAND = makeCustomStat("interact_with_brewingstand", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_BEACON = makeCustomStat("interact_with_beacon", StatFormatter.DEFAULT);
public static final ResourceLocation INSPECT_DROPPER = makeCustomStat("inspect_dropper", StatFormatter.DEFAULT);
public static final ResourceLocation INSPECT_HOPPER = makeCustomStat("inspect_hopper", StatFormatter.DEFAULT);
public static final ResourceLocation INSPECT_DISPENSER = makeCustomStat("inspect_dispenser", StatFormatter.DEFAULT);
public static final ResourceLocation PLAY_NOTEBLOCK = makeCustomStat("play_noteblock", StatFormatter.DEFAULT);
public static final ResourceLocation TUNE_NOTEBLOCK = makeCustomStat("tune_noteblock", StatFormatter.DEFAULT);
public static final ResourceLocation POT_FLOWER = makeCustomStat("pot_flower", StatFormatter.DEFAULT);
public static final ResourceLocation TRIGGER_TRAPPED_CHEST = makeCustomStat("trigger_trapped_chest", StatFormatter.DEFAULT);
public static final ResourceLocation OPEN_ENDERCHEST = makeCustomStat("open_enderchest", StatFormatter.DEFAULT);
public static final ResourceLocation ENCHANT_ITEM = makeCustomStat("enchant_item", StatFormatter.DEFAULT);
public static final ResourceLocation PLAY_RECORD = makeCustomStat("play_record", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_FURNACE = makeCustomStat("interact_with_furnace", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_CRAFTING_TABLE = makeCustomStat("interact_with_crafting_table", StatFormatter.DEFAULT);
public static final ResourceLocation OPEN_CHEST = makeCustomStat("open_chest", StatFormatter.DEFAULT);
public static final ResourceLocation SLEEP_IN_BED = makeCustomStat("sleep_in_bed", StatFormatter.DEFAULT);
public static final ResourceLocation OPEN_SHULKER_BOX = makeCustomStat("open_shulker_box", StatFormatter.DEFAULT);
public static final ResourceLocation OPEN_BARREL = makeCustomStat("open_barrel", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_BLAST_FURNACE = makeCustomStat("interact_with_blast_furnace", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_SMOKER = makeCustomStat("interact_with_smoker", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_LECTERN = makeCustomStat("interact_with_lectern", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_CAMPFIRE = makeCustomStat("interact_with_campfire", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_CARTOGRAPHY_TABLE = makeCustomStat("interact_with_cartography_table", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_LOOM = makeCustomStat("interact_with_loom", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_STONECUTTER = makeCustomStat("interact_with_stonecutter", StatFormatter.DEFAULT);
public static final ResourceLocation BELL_RING = makeCustomStat("bell_ring", StatFormatter.DEFAULT);
public static final ResourceLocation RAID_TRIGGER = makeCustomStat("raid_trigger", StatFormatter.DEFAULT);
public static final ResourceLocation RAID_WIN = makeCustomStat("raid_win", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_ANVIL = makeCustomStat("interact_with_anvil", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_GRINDSTONE = makeCustomStat("interact_with_grindstone", StatFormatter.DEFAULT);
public static final ResourceLocation TARGET_HIT = makeCustomStat("target_hit", StatFormatter.DEFAULT);
public static final ResourceLocation INTERACT_WITH_SMITHING_TABLE = makeCustomStat("interact_with_smithing_table", StatFormatter.DEFAULT);
private static ResourceLocation makeCustomStat(String pKey, StatFormatter pFormatter) {
ResourceLocation resourcelocation = new ResourceLocation(pKey);
Registry.register(BuiltInRegistries.CUSTOM_STAT, pKey, resourcelocation);
CUSTOM.get(resourcelocation, pFormatter);
return resourcelocation;
}
private static <T> StatType<T> makeRegistryStatType(String pKey, Registry<T> pRegistry) {
return Registry.register(BuiltInRegistries.STAT_TYPE, pKey, new StatType<>(pRegistry));
}
}
@@ -0,0 +1,38 @@
package net.minecraft.stats;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntMaps;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import net.minecraft.world.entity.player.Player;
/**
* Manages counting a set of {@link net.minecraft.stats.Stat} objects, stored by a map of statistics to their count.
* <p>
* This base {@code StatsCounter} is only used client-side for keeping track of and reading counts sent from the server.
*
* @see net.minecraft.stats.ServerStatsCounter
*/
public class StatsCounter {
protected final Object2IntMap<Stat<?>> stats = Object2IntMaps.synchronize(new Object2IntOpenHashMap<>());
public StatsCounter() {
this.stats.defaultReturnValue(0);
}
public void increment(Player pPlayer, Stat<?> pStat, int pAmount) {
int i = (int)Math.min((long)this.getValue(pStat) + (long)pAmount, 2147483647L);
this.setValue(pPlayer, pStat, i);
}
public void setValue(Player pPlayer, Stat<?> pStat, int pValue) {
this.stats.put(pStat, pValue);
}
public <T> int getValue(StatType<T> pType, T pValue) {
return pType.contains(pValue) ? this.getValue(pType.get(pValue)) : 0;
}
public int getValue(Stat<?> pStat) {
return this.stats.getInt(pStat);
}
}
@@ -0,0 +1,8 @@
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
@FieldsAreNonnullByDefault
package net.minecraft.stats;
import javax.annotation.ParametersAreNonnullByDefault;
import net.minecraft.FieldsAreNonnullByDefault;
import net.minecraft.MethodsReturnNonnullByDefault;