Code/net/minecraft/world/level/block/entity/BrushableBlockEntity.java

249 lines
10 KiB
Java

package net.minecraft.world.level.block.entity;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Objects;
import javax.annotation.Nullable;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.RegistryOps;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.BrushableBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
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;
import net.minecraft.world.phys.Vec3;
import org.slf4j.Logger;
public class BrushableBlockEntity extends BlockEntity {
private static final Logger LOGGER = LogUtils.getLogger();
private static final String LOOT_TABLE_TAG = "LootTable";
private static final String LOOT_TABLE_SEED_TAG = "LootTableSeed";
private static final String HIT_DIRECTION_TAG = "hit_direction";
private static final String ITEM_TAG = "item";
private static final int BRUSH_COOLDOWN_TICKS = 10;
private static final int BRUSH_RESET_TICKS = 40;
private static final int REQUIRED_BRUSHES_TO_BREAK = 10;
private int brushCount;
private long brushCountResetsAtTick;
private long coolDownEndsAtTick;
private ItemStack item = ItemStack.EMPTY;
@Nullable
private Direction hitDirection;
@Nullable
private ResourceKey<LootTable> lootTable;
private long lootTableSeed;
public BrushableBlockEntity(BlockPos p_277558_, BlockState p_278093_) {
super(BlockEntityType.BRUSHABLE_BLOCK, p_277558_, p_278093_);
}
public boolean brush(long p_277786_, ServerLevel p_368993_, LivingEntity p_393398_, Direction p_277424_, ItemStack p_363346_) {
if (this.hitDirection == null) {
this.hitDirection = p_277424_;
}
this.brushCountResetsAtTick = p_277786_ + 40L;
if (p_277786_ < this.coolDownEndsAtTick) {
return false;
} else {
this.coolDownEndsAtTick = p_277786_ + 10L;
this.unpackLootTable(p_368993_, p_393398_, p_363346_);
int i = this.getCompletionState();
if (++this.brushCount >= 10) {
this.brushingCompleted(p_368993_, p_393398_, p_363346_);
return true;
} else {
p_368993_.scheduleTick(this.getBlockPos(), this.getBlockState().getBlock(), 2);
int j = this.getCompletionState();
if (i != j) {
BlockState blockstate = this.getBlockState();
BlockState blockstate1 = blockstate.setValue(BlockStateProperties.DUSTED, j);
p_368993_.setBlock(this.getBlockPos(), blockstate1, 3);
}
return false;
}
}
}
private void unpackLootTable(ServerLevel p_367709_, LivingEntity p_392563_, ItemStack p_365744_) {
if (this.lootTable != null) {
LootTable loottable = p_367709_.getServer().reloadableRegistries().getLootTable(this.lootTable);
if (p_392563_ instanceof ServerPlayer serverplayer) {
CriteriaTriggers.GENERATE_LOOT.trigger(serverplayer, this.lootTable);
}
LootParams lootparams = new LootParams.Builder(p_367709_)
.withParameter(LootContextParams.ORIGIN, Vec3.atCenterOf(this.worldPosition))
.withLuck(p_392563_.getLuck())
.withParameter(LootContextParams.THIS_ENTITY, p_392563_)
.withParameter(LootContextParams.TOOL, p_365744_)
.create(LootContextParamSets.ARCHAEOLOGY);
ObjectArrayList<ItemStack> objectarraylist = loottable.getRandomItems(lootparams, this.lootTableSeed);
this.item = switch (objectarraylist.size()) {
case 0 -> ItemStack.EMPTY;
case 1 -> (ItemStack)objectarraylist.getFirst();
default -> {
LOGGER.warn("Expected max 1 loot from loot table {}, but got {}", this.lootTable.location(), objectarraylist.size());
yield objectarraylist.getFirst();
}
};
this.lootTable = null;
this.setChanged();
}
}
private void brushingCompleted(ServerLevel p_369249_, LivingEntity p_395246_, ItemStack p_364625_) {
this.dropContent(p_369249_, p_395246_, p_364625_);
BlockState blockstate = this.getBlockState();
p_369249_.levelEvent(3008, this.getBlockPos(), Block.getId(blockstate));
Block block;
if (this.getBlockState().getBlock() instanceof BrushableBlock brushableblock) {
block = brushableblock.getTurnsInto();
} else {
block = Blocks.AIR;
}
p_369249_.setBlock(this.worldPosition, block.defaultBlockState(), 3);
}
private void dropContent(ServerLevel p_360769_, LivingEntity p_391963_, ItemStack p_369575_) {
this.unpackLootTable(p_360769_, p_391963_, p_369575_);
if (!this.item.isEmpty()) {
double d0 = EntityType.ITEM.getWidth();
double d1 = 1.0 - d0;
double d2 = d0 / 2.0;
Direction direction = Objects.requireNonNullElse(this.hitDirection, Direction.UP);
BlockPos blockpos = this.worldPosition.relative(direction, 1);
double d3 = blockpos.getX() + 0.5 * d1 + d2;
double d4 = blockpos.getY() + 0.5 + EntityType.ITEM.getHeight() / 2.0F;
double d5 = blockpos.getZ() + 0.5 * d1 + d2;
ItemEntity itementity = new ItemEntity(p_360769_, d3, d4, d5, this.item.split(p_360769_.random.nextInt(21) + 10));
itementity.setDeltaMovement(Vec3.ZERO);
p_360769_.addFreshEntity(itementity);
this.item = ItemStack.EMPTY;
}
}
public void checkReset(ServerLevel p_367879_) {
if (this.brushCount != 0 && p_367879_.getGameTime() >= this.brushCountResetsAtTick) {
int i = this.getCompletionState();
this.brushCount = Math.max(0, this.brushCount - 2);
int j = this.getCompletionState();
if (i != j) {
p_367879_.setBlock(this.getBlockPos(), this.getBlockState().setValue(BlockStateProperties.DUSTED, j), 3);
}
int k = 4;
this.brushCountResetsAtTick = p_367879_.getGameTime() + 4L;
}
if (this.brushCount == 0) {
this.hitDirection = null;
this.brushCountResetsAtTick = 0L;
this.coolDownEndsAtTick = 0L;
} else {
p_367879_.scheduleTick(this.getBlockPos(), this.getBlockState().getBlock(), 2);
}
}
private boolean tryLoadLootTable(CompoundTag p_277740_) {
this.lootTable = p_277740_.read("LootTable", LootTable.KEY_CODEC).orElse(null);
this.lootTableSeed = p_277740_.getLongOr("LootTableSeed", 0L);
return this.lootTable != null;
}
private boolean trySaveLootTable(CompoundTag p_277591_) {
if (this.lootTable == null) {
return false;
} else {
p_277591_.store("LootTable", LootTable.KEY_CODEC, this.lootTable);
if (this.lootTableSeed != 0L) {
p_277591_.putLong("LootTableSeed", this.lootTableSeed);
}
return true;
}
}
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider p_329297_) {
CompoundTag compoundtag = super.getUpdateTag(p_329297_);
compoundtag.storeNullable("hit_direction", Direction.LEGACY_ID_CODEC, this.hitDirection);
if (!this.item.isEmpty()) {
RegistryOps<Tag> registryops = p_329297_.createSerializationContext(NbtOps.INSTANCE);
compoundtag.store("item", ItemStack.CODEC, registryops, this.item);
}
return compoundtag;
}
public ClientboundBlockEntityDataPacket getUpdatePacket() {
return ClientboundBlockEntityDataPacket.create(this);
}
@Override
protected void loadAdditional(CompoundTag p_335386_, HolderLookup.Provider p_334199_) {
super.loadAdditional(p_335386_, p_334199_);
RegistryOps<Tag> registryops = p_334199_.createSerializationContext(NbtOps.INSTANCE);
if (!this.tryLoadLootTable(p_335386_)) {
this.item = p_335386_.read("item", ItemStack.CODEC, registryops).orElse(ItemStack.EMPTY);
} else {
this.item = ItemStack.EMPTY;
}
this.hitDirection = p_335386_.read("hit_direction", Direction.LEGACY_ID_CODEC).orElse(null);
}
@Override
protected void saveAdditional(CompoundTag p_277339_, HolderLookup.Provider p_329463_) {
super.saveAdditional(p_277339_, p_329463_);
if (!this.trySaveLootTable(p_277339_) && !this.item.isEmpty()) {
RegistryOps<Tag> registryops = p_329463_.createSerializationContext(NbtOps.INSTANCE);
p_277339_.store("item", ItemStack.CODEC, registryops, this.item);
}
}
public void setLootTable(ResourceKey<LootTable> p_330093_, long p_277991_) {
this.lootTable = p_330093_;
this.lootTableSeed = p_277991_;
}
private int getCompletionState() {
if (this.brushCount == 0) {
return 0;
} else if (this.brushCount < 3) {
return 1;
} else {
return this.brushCount < 6 ? 2 : 3;
}
}
@Nullable
public Direction getHitDirection() {
return this.hitDirection;
}
public ItemStack getItem() {
return this.item;
}
}