137 lines
5.2 KiB
Java
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));
|
|
}
|
|
}
|
|
}
|