minecraft-src/net/minecraft/advancements/AdvancementRewards.java
2025-07-04 02:00:41 +03:00

137 lines
5.2 KiB
Java

package net.minecraft.advancements;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.util.List;
import java.util.Optional;
import net.minecraft.commands.CacheableFunction;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.sounds.SoundSource;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.level.storage.loot.LootParams;
import net.minecraft.world.level.storage.loot.LootTable;
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
public record AdvancementRewards(int experience, List<ResourceKey<LootTable>> loot, List<ResourceKey<Recipe<?>>> recipes, Optional<CacheableFunction> function) {
public static final Codec<AdvancementRewards> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Codec.INT.optionalFieldOf("experience", 0).forGetter(AdvancementRewards::experience),
ResourceKey.codec(Registries.LOOT_TABLE).listOf().optionalFieldOf("loot", List.of()).forGetter(AdvancementRewards::loot),
ResourceKey.codec(Registries.RECIPE).listOf().optionalFieldOf("recipes", List.of()).forGetter(AdvancementRewards::recipes),
CacheableFunction.CODEC.optionalFieldOf("function").forGetter(AdvancementRewards::function)
)
.apply(instance, AdvancementRewards::new)
);
public static final AdvancementRewards EMPTY = new AdvancementRewards(0, List.of(), List.of(), Optional.empty());
public void grant(ServerPlayer player) {
player.giveExperiencePoints(this.experience);
LootParams lootParams = new LootParams.Builder(player.serverLevel())
.withParameter(LootContextParams.THIS_ENTITY, player)
.withParameter(LootContextParams.ORIGIN, player.position())
.create(LootContextParamSets.ADVANCEMENT_REWARD);
boolean bl = false;
for (ResourceKey<LootTable> resourceKey : this.loot) {
for (ItemStack itemStack : player.server.reloadableRegistries().getLootTable(resourceKey).getRandomItems(lootParams)) {
if (player.addItem(itemStack)) {
player.level()
.playSound(
null,
player.getX(),
player.getY(),
player.getZ(),
SoundEvents.ITEM_PICKUP,
SoundSource.PLAYERS,
0.2F,
((player.getRandom().nextFloat() - player.getRandom().nextFloat()) * 0.7F + 1.0F) * 2.0F
);
bl = true;
} else {
ItemEntity itemEntity = player.drop(itemStack, false);
if (itemEntity != null) {
itemEntity.setNoPickUpDelay();
itemEntity.setTarget(player.getUUID());
}
}
}
}
if (bl) {
player.containerMenu.broadcastChanges();
}
if (!this.recipes.isEmpty()) {
player.awardRecipesByKey(this.recipes);
}
MinecraftServer minecraftServer = player.server;
this.function
.flatMap(cacheableFunction -> cacheableFunction.get(minecraftServer.getFunctions()))
.ifPresent(
commandFunction -> minecraftServer.getFunctions().execute(commandFunction, player.createCommandSourceStack().withSuppressedOutput().withPermission(2))
);
}
public static class Builder {
private int experience;
private final ImmutableList.Builder<ResourceKey<LootTable>> loot = ImmutableList.builder();
private final ImmutableList.Builder<ResourceKey<Recipe<?>>> recipes = ImmutableList.builder();
private Optional<ResourceLocation> function = Optional.empty();
/**
* Creates a new builder with the given amount of experience as a reward
*/
public static AdvancementRewards.Builder experience(int experience) {
return new AdvancementRewards.Builder().addExperience(experience);
}
/**
* Adds the given amount of experience. (Not a direct setter)
*/
public AdvancementRewards.Builder addExperience(int experience) {
this.experience += experience;
return this;
}
public static AdvancementRewards.Builder loot(ResourceKey<LootTable> lootTable) {
return new AdvancementRewards.Builder().addLootTable(lootTable);
}
public AdvancementRewards.Builder addLootTable(ResourceKey<LootTable> lootTable) {
this.loot.add(lootTable);
return this;
}
public static AdvancementRewards.Builder recipe(ResourceKey<Recipe<?>> resourceKey) {
return new AdvancementRewards.Builder().addRecipe(resourceKey);
}
public AdvancementRewards.Builder addRecipe(ResourceKey<Recipe<?>> resourceKey) {
this.recipes.add(resourceKey);
return this;
}
public static AdvancementRewards.Builder function(ResourceLocation functionId) {
return new AdvancementRewards.Builder().runs(functionId);
}
public AdvancementRewards.Builder runs(ResourceLocation functionId) {
this.function = Optional.of(functionId);
return this;
}
public AdvancementRewards build() {
return new AdvancementRewards(this.experience, this.loot.build(), this.recipes.build(), this.function.map(CacheableFunction::new));
}
}
}