trurwsuieghfdskg
This commit is contained in:
@@ -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 p_12686_) {
|
||||
this.known.clear();
|
||||
this.highlight.clear();
|
||||
this.bookSettings.replaceFrom(p_12686_.bookSettings);
|
||||
this.known.addAll(p_12686_.known);
|
||||
this.highlight.addAll(p_12686_.highlight);
|
||||
}
|
||||
|
||||
public void add(Recipe<?> p_12701_) {
|
||||
if (!p_12701_.isSpecial()) {
|
||||
this.add(p_12701_.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void add(ResourceLocation p_12703_) {
|
||||
this.known.add(p_12703_);
|
||||
}
|
||||
|
||||
public boolean contains(@Nullable Recipe<?> p_12710_) {
|
||||
return p_12710_ == null ? false : this.known.contains(p_12710_.getId());
|
||||
}
|
||||
|
||||
public boolean contains(ResourceLocation p_12712_) {
|
||||
return this.known.contains(p_12712_);
|
||||
}
|
||||
|
||||
public void remove(Recipe<?> p_12714_) {
|
||||
this.remove(p_12714_.getId());
|
||||
}
|
||||
|
||||
protected void remove(ResourceLocation p_12716_) {
|
||||
this.known.remove(p_12716_);
|
||||
this.highlight.remove(p_12716_);
|
||||
}
|
||||
|
||||
public boolean willHighlight(Recipe<?> p_12718_) {
|
||||
return this.highlight.contains(p_12718_.getId());
|
||||
}
|
||||
|
||||
public void removeHighlight(Recipe<?> p_12722_) {
|
||||
this.highlight.remove(p_12722_.getId());
|
||||
}
|
||||
|
||||
public void addHighlight(Recipe<?> p_12724_) {
|
||||
this.addHighlight(p_12724_.getId());
|
||||
}
|
||||
|
||||
protected void addHighlight(ResourceLocation p_12720_) {
|
||||
this.highlight.add(p_12720_);
|
||||
}
|
||||
|
||||
public boolean isOpen(RecipeBookType p_12692_) {
|
||||
return this.bookSettings.isOpen(p_12692_);
|
||||
}
|
||||
|
||||
public void setOpen(RecipeBookType p_12694_, boolean p_12695_) {
|
||||
this.bookSettings.setOpen(p_12694_, p_12695_);
|
||||
}
|
||||
|
||||
public boolean isFiltering(RecipeBookMenu<?> p_12690_) {
|
||||
return this.isFiltering(p_12690_.getRecipeBookType());
|
||||
}
|
||||
|
||||
public boolean isFiltering(RecipeBookType p_12705_) {
|
||||
return this.bookSettings.isFiltering(p_12705_);
|
||||
}
|
||||
|
||||
public void setFiltering(RecipeBookType p_12707_, boolean p_12708_) {
|
||||
this.bookSettings.setFiltering(p_12707_, p_12708_);
|
||||
}
|
||||
|
||||
public void setBookSettings(RecipeBookSettings p_12688_) {
|
||||
this.bookSettings.replaceFrom(p_12688_);
|
||||
}
|
||||
|
||||
public RecipeBookSettings getBookSettings() {
|
||||
return this.bookSettings.copy();
|
||||
}
|
||||
|
||||
public void setBookSetting(RecipeBookType p_12697_, boolean p_12698_, boolean p_12699_) {
|
||||
this.bookSettings.setOpen(p_12697_, p_12698_);
|
||||
this.bookSettings.setFiltering(p_12697_, p_12699_);
|
||||
}
|
||||
}
|
||||
@@ -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> p_12730_) {
|
||||
this.states = p_12730_;
|
||||
}
|
||||
|
||||
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 p_12735_) {
|
||||
return (this.states.get(p_12735_)).open;
|
||||
}
|
||||
|
||||
public void setOpen(RecipeBookType p_12737_, boolean p_12738_) {
|
||||
(this.states.get(p_12737_)).open = p_12738_;
|
||||
}
|
||||
|
||||
public boolean isFiltering(RecipeBookType p_12755_) {
|
||||
return (this.states.get(p_12755_)).filtering;
|
||||
}
|
||||
|
||||
public void setFiltering(RecipeBookType p_12757_, boolean p_12758_) {
|
||||
(this.states.get(p_12757_)).filtering = p_12758_;
|
||||
}
|
||||
|
||||
public static RecipeBookSettings read(FriendlyByteBuf p_12753_) {
|
||||
Map<RecipeBookType, RecipeBookSettings.TypeSettings> map = Maps.newEnumMap(RecipeBookType.class);
|
||||
|
||||
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
|
||||
boolean flag = p_12753_.readBoolean();
|
||||
boolean flag1 = p_12753_.readBoolean();
|
||||
map.put(recipebooktype, new RecipeBookSettings.TypeSettings(flag, flag1));
|
||||
}
|
||||
|
||||
return new RecipeBookSettings(map);
|
||||
}
|
||||
|
||||
public void write(FriendlyByteBuf p_12762_) {
|
||||
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
|
||||
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = this.states.get(recipebooktype);
|
||||
if (recipebooksettings$typesettings == null) {
|
||||
p_12762_.writeBoolean(false);
|
||||
p_12762_.writeBoolean(false);
|
||||
} else {
|
||||
p_12762_.writeBoolean(recipebooksettings$typesettings.open);
|
||||
p_12762_.writeBoolean(recipebooksettings$typesettings.filtering);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static RecipeBookSettings read(CompoundTag p_12742_) {
|
||||
Map<RecipeBookType, RecipeBookSettings.TypeSettings> map = Maps.newEnumMap(RecipeBookType.class);
|
||||
TAG_FIELDS.forEach((p_12750_, p_12751_) -> {
|
||||
boolean flag = p_12742_.getBoolean(p_12751_.getFirst());
|
||||
boolean flag1 = p_12742_.getBoolean(p_12751_.getSecond());
|
||||
map.put(p_12750_, new RecipeBookSettings.TypeSettings(flag, flag1));
|
||||
});
|
||||
return new RecipeBookSettings(map);
|
||||
}
|
||||
|
||||
public void write(CompoundTag p_12760_) {
|
||||
TAG_FIELDS.forEach((p_12745_, p_12746_) -> {
|
||||
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = this.states.get(p_12745_);
|
||||
p_12760_.putBoolean(p_12746_.getFirst(), recipebooksettings$typesettings.open);
|
||||
p_12760_.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 p_12733_) {
|
||||
this.states.clear();
|
||||
|
||||
for(RecipeBookType recipebooktype : RecipeBookType.values()) {
|
||||
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = p_12733_.states.get(recipebooktype);
|
||||
this.states.put(recipebooktype, recipebooksettings$typesettings.copy());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean equals(Object p_12764_) {
|
||||
return this == p_12764_ || p_12764_ instanceof RecipeBookSettings && this.states.equals(((RecipeBookSettings)p_12764_).states);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.states.hashCode();
|
||||
}
|
||||
|
||||
static final class TypeSettings {
|
||||
boolean open;
|
||||
boolean filtering;
|
||||
|
||||
public TypeSettings(boolean p_12769_, boolean p_12770_) {
|
||||
this.open = p_12769_;
|
||||
this.filtering = p_12770_;
|
||||
}
|
||||
|
||||
public RecipeBookSettings.TypeSettings copy() {
|
||||
return new RecipeBookSettings.TypeSettings(this.open, this.filtering);
|
||||
}
|
||||
|
||||
public boolean equals(Object p_12783_) {
|
||||
if (this == p_12783_) {
|
||||
return true;
|
||||
} else if (!(p_12783_ instanceof RecipeBookSettings.TypeSettings)) {
|
||||
return false;
|
||||
} else {
|
||||
RecipeBookSettings.TypeSettings recipebooksettings$typesettings = (RecipeBookSettings.TypeSettings)p_12783_;
|
||||
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<?>> p_12792_, ServerPlayer p_12793_) {
|
||||
List<ResourceLocation> list = Lists.newArrayList();
|
||||
int i = 0;
|
||||
|
||||
for(Recipe<?> recipe : p_12792_) {
|
||||
ResourceLocation resourcelocation = recipe.getId();
|
||||
if (!this.known.contains(resourcelocation) && !recipe.isSpecial()) {
|
||||
this.add(resourcelocation);
|
||||
this.addHighlight(resourcelocation);
|
||||
list.add(resourcelocation);
|
||||
CriteriaTriggers.RECIPE_UNLOCKED.trigger(p_12793_, recipe);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (list.size() > 0) {
|
||||
this.sendRecipes(ClientboundRecipePacket.State.ADD, p_12793_, list);
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
public int removeRecipes(Collection<Recipe<?>> p_12807_, ServerPlayer p_12808_) {
|
||||
List<ResourceLocation> list = Lists.newArrayList();
|
||||
int i = 0;
|
||||
|
||||
for(Recipe<?> recipe : p_12807_) {
|
||||
ResourceLocation resourcelocation = recipe.getId();
|
||||
if (this.known.contains(resourcelocation)) {
|
||||
this.remove(resourcelocation);
|
||||
list.add(resourcelocation);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
this.sendRecipes(ClientboundRecipePacket.State.REMOVE, p_12808_, list);
|
||||
return i;
|
||||
}
|
||||
|
||||
private void sendRecipes(ClientboundRecipePacket.State p_12802_, ServerPlayer p_12803_, List<ResourceLocation> p_12804_) {
|
||||
p_12803_.connection.send(new ClientboundRecipePacket(p_12802_, p_12804_, 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 p_12795_, RecipeManager p_12796_) {
|
||||
this.setBookSettings(RecipeBookSettings.read(p_12795_));
|
||||
ListTag listtag = p_12795_.getList("recipes", 8);
|
||||
this.loadRecipes(listtag, this::add, p_12796_);
|
||||
ListTag listtag1 = p_12795_.getList("toBeDisplayed", 8);
|
||||
this.loadRecipes(listtag1, this::addHighlight, p_12796_);
|
||||
}
|
||||
|
||||
private void loadRecipes(ListTag p_12798_, Consumer<Recipe<?>> p_12799_, RecipeManager p_12800_) {
|
||||
for(int i = 0; i < p_12798_.size(); ++i) {
|
||||
String s = p_12798_.getString(i);
|
||||
|
||||
try {
|
||||
ResourceLocation resourcelocation = new ResourceLocation(s);
|
||||
Optional<? extends Recipe<?>> optional = p_12800_.byKey(resourcelocation);
|
||||
if (!optional.isPresent()) {
|
||||
LOGGER.error("Tried to load unrecognized recipe: {} removed now.", (Object)resourcelocation);
|
||||
} else {
|
||||
p_12799_.accept(optional.get());
|
||||
}
|
||||
} catch (ResourceLocationException resourcelocationexception) {
|
||||
LOGGER.error("Tried to load improperly formatted recipe: {} removed now.", (Object)s);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void sendInitialRecipeBook(ServerPlayer p_12790_) {
|
||||
p_12790_.connection.send(new ClientboundRecipePacket(ClientboundRecipePacket.State.INIT, this.known, this.highlight, this.getBookSettings()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
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;
|
||||
|
||||
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 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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()) {
|
||||
CompoundTag compoundtag = fromJson(jsonelement.getAsJsonObject());
|
||||
compoundtag = DataFixTypes.STATS.updateToCurrentVersion(p_12833_, 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> p_12824_, String p_12825_) {
|
||||
return Optional.ofNullable(ResourceLocation.tryParse(p_12825_)).flatMap(p_12824_.getRegistry()::getOptional).map(p_12824_::get);
|
||||
}
|
||||
|
||||
private static CompoundTag fromJson(JsonObject p_12831_) {
|
||||
CompoundTag compoundtag = new CompoundTag();
|
||||
|
||||
for(Map.Entry<String, JsonElement> entry : p_12831_.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> p_12847_) {
|
||||
return p_12847_.getType().getRegistry().getKey(p_12847_.getValue());
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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;
|
||||
|
||||
public class Stat<T> extends ObjectiveCriteria {
|
||||
private final StatFormatter formatter;
|
||||
private final T value;
|
||||
private final StatType<T> type;
|
||||
|
||||
protected Stat(StatType<T> p_12856_, T p_12857_, StatFormatter p_12858_) {
|
||||
super(buildName(p_12856_, p_12857_));
|
||||
this.type = p_12856_;
|
||||
this.formatter = p_12858_;
|
||||
this.value = p_12857_;
|
||||
}
|
||||
|
||||
public static <T> String buildName(StatType<T> p_12863_, T p_12864_) {
|
||||
return locationToKey(BuiltInRegistries.STAT_TYPE.getKey(p_12863_)) + ":" + locationToKey(p_12863_.getRegistry().getKey(p_12864_));
|
||||
}
|
||||
|
||||
private static <T> String locationToKey(@Nullable ResourceLocation p_12866_) {
|
||||
return p_12866_.toString().replace(':', '.');
|
||||
}
|
||||
|
||||
public StatType<T> getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String format(int p_12861_) {
|
||||
return this.formatter.format(p_12861_);
|
||||
}
|
||||
|
||||
public boolean equals(Object p_12869_) {
|
||||
return this == p_12869_ || p_12869_ instanceof Stat && Objects.equals(this.getName(), ((Stat)p_12869_).getName());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.getName().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "Stat{name=" + this.getName() + ", formatter=" + this.formatter + "}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package net.minecraft.stats;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.DecimalFormatSymbols;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Locale;
|
||||
import net.minecraft.Util;
|
||||
|
||||
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";
|
||||
}
|
||||
};
|
||||
|
||||
String format(int p_12887_);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
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;
|
||||
|
||||
public class StatType<T> implements Iterable<Stat<T>> {
|
||||
private final Registry<T> registry;
|
||||
private final Map<T, Stat<T>> map = new IdentityHashMap<>();
|
||||
@Nullable
|
||||
private Component displayName;
|
||||
|
||||
public StatType(Registry<T> p_12892_) {
|
||||
this.registry = p_12892_;
|
||||
}
|
||||
|
||||
public boolean contains(T p_12898_) {
|
||||
return this.map.containsKey(p_12898_);
|
||||
}
|
||||
|
||||
public Stat<T> get(T p_12900_, StatFormatter p_12901_) {
|
||||
return this.map.computeIfAbsent(p_12900_, (p_12896_) -> {
|
||||
return new Stat<>(this, p_12896_, p_12901_);
|
||||
});
|
||||
}
|
||||
|
||||
public Registry<T> getRegistry() {
|
||||
return this.registry;
|
||||
}
|
||||
|
||||
public Iterator<Stat<T>> iterator() {
|
||||
return this.map.values().iterator();
|
||||
}
|
||||
|
||||
public Stat<T> get(T p_12903_) {
|
||||
return this.get(p_12903_, 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 p_13008_, StatFormatter p_13009_) {
|
||||
ResourceLocation resourcelocation = new ResourceLocation(p_13008_);
|
||||
Registry.register(BuiltInRegistries.CUSTOM_STAT, p_13008_, resourcelocation);
|
||||
CUSTOM.get(resourcelocation, p_13009_);
|
||||
return resourcelocation;
|
||||
}
|
||||
|
||||
private static <T> StatType<T> makeRegistryStatType(String p_13011_, Registry<T> p_13012_) {
|
||||
return Registry.register(BuiltInRegistries.STAT_TYPE, p_13011_, new StatType<>(p_13012_));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
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;
|
||||
|
||||
public class StatsCounter {
|
||||
protected final Object2IntMap<Stat<?>> stats = Object2IntMaps.synchronize(new Object2IntOpenHashMap<>());
|
||||
|
||||
public StatsCounter() {
|
||||
this.stats.defaultReturnValue(0);
|
||||
}
|
||||
|
||||
public void increment(Player p_13024_, Stat<?> p_13025_, int p_13026_) {
|
||||
int i = (int)Math.min((long)this.getValue(p_13025_) + (long)p_13026_, 2147483647L);
|
||||
this.setValue(p_13024_, p_13025_, i);
|
||||
}
|
||||
|
||||
public void setValue(Player p_13020_, Stat<?> p_13021_, int p_13022_) {
|
||||
this.stats.put(p_13021_, p_13022_);
|
||||
}
|
||||
|
||||
public <T> int getValue(StatType<T> p_13018_, T p_13019_) {
|
||||
return p_13018_.contains(p_13019_) ? this.getValue(p_13018_.get(p_13019_)) : 0;
|
||||
}
|
||||
|
||||
public int getValue(Stat<?> p_13016_) {
|
||||
return this.stats.getInt(p_13016_);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@ParametersAreNonnullByDefault
|
||||
@MethodsReturnNonnullByDefault
|
||||
@FieldsAreNonnullByDefault
|
||||
package net.minecraft.stats;
|
||||
|
||||
import javax.annotation.ParametersAreNonnullByDefault;
|
||||
import net.minecraft.FieldsAreNonnullByDefault;
|
||||
import net.minecraft.MethodsReturnNonnullByDefault;
|
||||
Reference in New Issue
Block a user