minecraft-source/src/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity....

479 lines
18 KiB
Java

package net.minecraft.world.level.block.entity;
import net.minecraft.world.level.block.state.AbstractStateHolder;
import net.minecraft.world.entity.player.StackedContents;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ExperienceOrb;
import java.util.Collection;
import com.google.common.collect.Lists;
import net.minecraft.world.entity.player.Player;
import java.util.List;
import net.minecraft.core.Direction;
import java.util.function.Function;
import javax.annotation.Nullable;
import net.minecraft.world.level.block.state.properties.Property;
import net.minecraft.world.level.block.AbstractFurnaceBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.util.Mth;
import net.minecraft.world.item.crafting.Recipe;
import net.minecraft.world.ContainerHelper;
import net.minecraft.nbt.CompoundTag;
import java.util.Iterator;
import net.minecraft.tags.Tag;
import net.minecraft.tags.ItemTags;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.Item;
import com.google.common.collect.Maps;
import net.minecraft.world.item.crafting.AbstractCookingRecipe;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.resources.ResourceLocation;
import java.util.Map;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.core.NonNullList;
import net.minecraft.world.inventory.StackedContentsCompatible;
import net.minecraft.world.inventory.RecipeHolder;
import net.minecraft.world.WorldlyContainer;
public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntity implements WorldlyContainer, RecipeHolder, StackedContentsCompatible, TickableBlockEntity {
private static final int[] SLOTS_FOR_UP;
private static final int[] SLOTS_FOR_DOWN;
private static final int[] SLOTS_FOR_SIDES;
protected NonNullList<ItemStack> items;
private int litTime;
private int litDuration;
private int cookingProgress;
private int cookingTotalTime;
protected final ContainerData dataAccess;
private final Map<ResourceLocation, Integer> recipesUsed;
protected final RecipeType<? extends AbstractCookingRecipe> recipeType;
protected AbstractFurnaceBlockEntity(final BlockEntityType<?> bwj, final RecipeType<? extends AbstractCookingRecipe> bgw) {
super(bwj);
this.items = NonNullList.<ItemStack>withSize(3, ItemStack.EMPTY);
this.dataAccess = new ContainerData() {
@Override
public int get(final int integer) {
switch (integer) {
case 0: {
return AbstractFurnaceBlockEntity.this.litTime;
}
case 1: {
return AbstractFurnaceBlockEntity.this.litDuration;
}
case 2: {
return AbstractFurnaceBlockEntity.this.cookingProgress;
}
case 3: {
return AbstractFurnaceBlockEntity.this.cookingTotalTime;
}
default: {
return 0;
}
}
}
@Override
public void set(final int integer1, final int integer2) {
switch (integer1) {
case 0: {
AbstractFurnaceBlockEntity.this.litTime = integer2;
break;
}
case 1: {
AbstractFurnaceBlockEntity.this.litDuration = integer2;
break;
}
case 2: {
AbstractFurnaceBlockEntity.this.cookingProgress = integer2;
break;
}
case 3: {
AbstractFurnaceBlockEntity.this.cookingTotalTime = integer2;
break;
}
}
}
@Override
public int getCount() {
return 4;
}
};
this.recipesUsed = Maps.newHashMap();
this.recipeType = bgw;
}
public static Map<Item, Integer> getFuel() {
final Map<Item, Integer> map1 = Maps.newLinkedHashMap();
add(map1, Items.LAVA_BUCKET, 20000);
add(map1, Blocks.COAL_BLOCK, 16000);
add(map1, Items.BLAZE_ROD, 2400);
add(map1, Items.COAL, 1600);
add(map1, Items.CHARCOAL, 1600);
add(map1, ItemTags.LOGS, 300);
add(map1, ItemTags.PLANKS, 300);
add(map1, ItemTags.WOODEN_STAIRS, 300);
add(map1, ItemTags.WOODEN_SLABS, 150);
add(map1, ItemTags.WOODEN_TRAPDOORS, 300);
add(map1, ItemTags.WOODEN_PRESSURE_PLATES, 300);
add(map1, Blocks.OAK_FENCE, 300);
add(map1, Blocks.BIRCH_FENCE, 300);
add(map1, Blocks.SPRUCE_FENCE, 300);
add(map1, Blocks.JUNGLE_FENCE, 300);
add(map1, Blocks.DARK_OAK_FENCE, 300);
add(map1, Blocks.ACACIA_FENCE, 300);
add(map1, Blocks.OAK_FENCE_GATE, 300);
add(map1, Blocks.BIRCH_FENCE_GATE, 300);
add(map1, Blocks.SPRUCE_FENCE_GATE, 300);
add(map1, Blocks.JUNGLE_FENCE_GATE, 300);
add(map1, Blocks.DARK_OAK_FENCE_GATE, 300);
add(map1, Blocks.ACACIA_FENCE_GATE, 300);
add(map1, Blocks.NOTE_BLOCK, 300);
add(map1, Blocks.BOOKSHELF, 300);
add(map1, Blocks.LECTERN, 300);
add(map1, Blocks.JUKEBOX, 300);
add(map1, Blocks.CHEST, 300);
add(map1, Blocks.TRAPPED_CHEST, 300);
add(map1, Blocks.CRAFTING_TABLE, 300);
add(map1, Blocks.DAYLIGHT_DETECTOR, 300);
add(map1, ItemTags.BANNERS, 300);
add(map1, Items.BOW, 300);
add(map1, Items.FISHING_ROD, 300);
add(map1, Blocks.LADDER, 300);
add(map1, ItemTags.SIGNS, 200);
add(map1, Items.WOODEN_SHOVEL, 200);
add(map1, Items.WOODEN_SWORD, 200);
add(map1, Items.WOODEN_HOE, 200);
add(map1, Items.WOODEN_AXE, 200);
add(map1, Items.WOODEN_PICKAXE, 200);
add(map1, ItemTags.WOODEN_DOORS, 200);
add(map1, ItemTags.BOATS, 1200);
add(map1, ItemTags.WOOL, 100);
add(map1, ItemTags.WOODEN_BUTTONS, 100);
add(map1, Items.STICK, 100);
add(map1, ItemTags.SAPLINGS, 100);
add(map1, Items.BOWL, 100);
add(map1, ItemTags.CARPETS, 67);
add(map1, Blocks.DRIED_KELP_BLOCK, 4001);
add(map1, Items.CROSSBOW, 300);
add(map1, Blocks.BAMBOO, 50);
add(map1, Blocks.DEAD_BUSH, 100);
add(map1, Blocks.SCAFFOLDING, 400);
add(map1, Blocks.LOOM, 300);
add(map1, Blocks.BARREL, 300);
add(map1, Blocks.CARTOGRAPHY_TABLE, 300);
add(map1, Blocks.FLETCHING_TABLE, 300);
add(map1, Blocks.SMITHING_TABLE, 300);
add(map1, Blocks.COMPOSTER, 300);
return map1;
}
private static void add(final Map<Item, Integer> map, final Tag<Item> aaz, final int integer) {
for (final Item bef5 : aaz.getValues()) {
map.put(bef5, integer);
}
}
private static void add(final Map<Item, Integer> map, final ItemLike bjs, final int integer) {
map.put(bjs.asItem(), integer);
}
private boolean isLit() {
return this.litTime > 0;
}
@Override
public void load(final CompoundTag jt) {
super.load(jt);
ContainerHelper.loadAllItems(jt, this.items = NonNullList.<ItemStack>withSize(this.getContainerSize(), ItemStack.EMPTY));
this.litTime = jt.getShort("BurnTime");
this.cookingProgress = jt.getShort("CookTime");
this.cookingTotalTime = jt.getShort("CookTimeTotal");
this.litDuration = this.getBurnDuration(this.items.get(1));
for (int integer3 = jt.getShort("RecipesUsedSize"), integer4 = 0; integer4 < integer3; ++integer4) {
final ResourceLocation sm5 = new ResourceLocation(jt.getString("RecipeLocation" + integer4));
final int integer5 = jt.getInt("RecipeAmount" + integer4);
this.recipesUsed.put(sm5, integer5);
}
}
@Override
public CompoundTag save(final CompoundTag jt) {
super.save(jt);
jt.putShort("BurnTime", (short)this.litTime);
jt.putShort("CookTime", (short)this.cookingProgress);
jt.putShort("CookTimeTotal", (short)this.cookingTotalTime);
ContainerHelper.saveAllItems(jt, this.items);
jt.putShort("RecipesUsedSize", (short)this.recipesUsed.size());
int integer3 = 0;
for (final Map.Entry<ResourceLocation, Integer> entry5 : this.recipesUsed.entrySet()) {
jt.putString("RecipeLocation" + integer3, entry5.getKey().toString());
jt.putInt("RecipeAmount" + integer3, entry5.getValue());
++integer3;
}
return jt;
}
@Override
public void tick() {
final boolean boolean2 = this.isLit();
boolean boolean3 = false;
if (this.isLit()) {
--this.litTime;
}
if (!this.level.isClientSide) {
final ItemStack bek4 = this.items.get(1);
if (this.isLit() || (!bek4.isEmpty() && !this.items.get(0).isEmpty())) {
final Recipe<?> bgt5 = this.level.getRecipeManager().getRecipeFor(this.recipeType, this, this.level).orElse((AbstractCookingRecipe)null);
if (!this.isLit() && this.canBurn(bgt5)) {
this.litTime = this.getBurnDuration(bek4);
this.litDuration = this.litTime;
if (this.isLit()) {
boolean3 = true;
if (!bek4.isEmpty()) {
final Item bef6 = bek4.getItem();
bek4.shrink(1);
if (bek4.isEmpty()) {
final Item bef7 = bef6.getCraftingRemainingItem();
this.items.set(1, (bef7 == null) ? ItemStack.EMPTY : new ItemStack(bef7));
}
}
}
}
if (this.isLit() && this.canBurn(bgt5)) {
++this.cookingProgress;
if (this.cookingProgress == this.cookingTotalTime) {
this.cookingProgress = 0;
this.cookingTotalTime = this.getTotalCookTime();
this.burn(bgt5);
boolean3 = true;
}
}
else {
this.cookingProgress = 0;
}
}
else if (!this.isLit() && this.cookingProgress > 0) {
this.cookingProgress = Mth.clamp(this.cookingProgress - 2, 0, this.cookingTotalTime);
}
if (boolean2 != this.isLit()) {
boolean3 = true;
this.level.setBlock(this.worldPosition, ((AbstractStateHolder<O, BlockState>)this.level.getBlockState(this.worldPosition)).<Comparable, Boolean>setValue((Property<Comparable>)AbstractFurnaceBlock.LIT, this.isLit()), 3);
}
}
if (boolean3) {
this.setChanged();
}
}
protected boolean canBurn(@Nullable final Recipe<?> bgt) {
if (this.items.get(0).isEmpty() || bgt == null) {
return false;
}
final ItemStack bek3 = bgt.getResultItem();
if (bek3.isEmpty()) {
return false;
}
final ItemStack bek4 = this.items.get(2);
return bek4.isEmpty() || (bek4.sameItem(bek3) && ((bek4.getCount() < this.getMaxStackSize() && bek4.getCount() < bek4.getMaxStackSize()) || bek4.getCount() < bek3.getMaxStackSize()));
}
private void burn(@Nullable final Recipe<?> bgt) {
if (bgt == null || !this.canBurn(bgt)) {
return;
}
final ItemStack bek3 = this.items.get(0);
final ItemStack bek4 = bgt.getResultItem();
final ItemStack bek5 = this.items.get(2);
if (bek5.isEmpty()) {
this.items.set(2, bek4.copy());
}
else if (bek5.getItem() == bek4.getItem()) {
bek5.grow(1);
}
if (!this.level.isClientSide) {
this.setRecipeUsed(bgt);
}
if (bek3.getItem() == Blocks.WET_SPONGE.asItem() && !this.items.get(1).isEmpty() && this.items.get(1).getItem() == Items.BUCKET) {
this.items.set(1, new ItemStack(Items.WATER_BUCKET));
}
bek3.shrink(1);
}
protected int getBurnDuration(final ItemStack bek) {
if (bek.isEmpty()) {
return 0;
}
final Item bef3 = bek.getItem();
return getFuel().getOrDefault(bef3, 0);
}
protected int getTotalCookTime() {
return this.level.getRecipeManager().getRecipeFor(this.recipeType, this, this.level).<Integer>map(AbstractCookingRecipe::getCookingTime).orElse(200);
}
public static boolean isFuel(final ItemStack bek) {
return getFuel().containsKey(bek.getItem());
}
@Override
public int[] getSlotsForFace(final Direction fp) {
if (fp == Direction.DOWN) {
return AbstractFurnaceBlockEntity.SLOTS_FOR_DOWN;
}
if (fp == Direction.UP) {
return AbstractFurnaceBlockEntity.SLOTS_FOR_UP;
}
return AbstractFurnaceBlockEntity.SLOTS_FOR_SIDES;
}
@Override
public boolean canPlaceItemThroughFace(final int integer, final ItemStack bek, @Nullable final Direction fp) {
return this.canPlaceItem(integer, bek);
}
@Override
public boolean canTakeItemThroughFace(final int integer, final ItemStack bek, final Direction fp) {
if (fp == Direction.DOWN && integer == 1) {
final Item bef5 = bek.getItem();
if (bef5 != Items.WATER_BUCKET && bef5 != Items.BUCKET) {
return false;
}
}
return true;
}
@Override
public int getContainerSize() {
return this.items.size();
}
@Override
public boolean isEmpty() {
for (final ItemStack bek3 : this.items) {
if (!bek3.isEmpty()) {
return false;
}
}
return true;
}
@Override
public ItemStack getItem(final int integer) {
return this.items.get(integer);
}
@Override
public ItemStack removeItem(final int integer1, final int integer2) {
return ContainerHelper.removeItem(this.items, integer1, integer2);
}
@Override
public ItemStack removeItemNoUpdate(final int integer) {
return ContainerHelper.takeItem(this.items, integer);
}
@Override
public void setItem(final int integer, final ItemStack bek) {
final ItemStack bek2 = this.items.get(integer);
final boolean boolean5 = !bek.isEmpty() && bek.sameItem(bek2) && ItemStack.tagMatches(bek, bek2);
this.items.set(integer, bek);
if (bek.getCount() > this.getMaxStackSize()) {
bek.setCount(this.getMaxStackSize());
}
if (integer == 0 && !boolean5) {
this.cookingTotalTime = this.getTotalCookTime();
this.cookingProgress = 0;
this.setChanged();
}
}
@Override
public boolean stillValid(final Player ayg) {
return this.level.getBlockEntity(this.worldPosition) == this && ayg.distanceToSqr(this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 0.5, this.worldPosition.getZ() + 0.5) <= 64.0;
}
@Override
public boolean canPlaceItem(final int integer, final ItemStack bek) {
if (integer == 2) {
return false;
}
if (integer == 1) {
final ItemStack bek2 = this.items.get(1);
return isFuel(bek) || (bek.getItem() == Items.BUCKET && bek2.getItem() != Items.BUCKET);
}
return true;
}
@Override
public void clearContent() {
this.items.clear();
}
@Override
public void setRecipeUsed(@Nullable final Recipe<?> bgt) {
if (bgt != null) {
this.recipesUsed.compute(bgt.getId(), (sm, integer) -> 1 + ((integer == null) ? 0 : integer));
}
}
@Nullable
@Override
public Recipe<?> getRecipeUsed() {
return null;
}
@Override
public void awardAndReset(final Player ayg) {
}
public void awardResetAndExperience(final Player ayg) {
final List<Recipe<?>> list3 = Lists.newArrayList();
for (final Map.Entry<ResourceLocation, Integer> entry5 : this.recipesUsed.entrySet()) {
final List<AbstractCookingRecipe> list4;
final Map.Entry<K, Integer> entry6;
ayg.level.getRecipeManager().byKey(entry5.getKey()).ifPresent(bgt -> {
list4.add(bgt);
createExperience(ayg, entry6.getValue(), bgt.getExperience());
return;
});
}
ayg.awardRecipes(list3);
this.recipesUsed.clear();
}
private static void createExperience(final Player ayg, int integer, final float float3) {
if (float3 == 0.0f) {
integer = 0;
}
else if (float3 < 1.0f) {
int integer2 = Mth.floor(integer * float3);
if (integer2 < Mth.ceil(integer * float3) && Math.random() < integer * float3 - integer2) {
++integer2;
}
integer = integer2;
}
while (integer > 0) {
final int integer2 = ExperienceOrb.getExperienceValue(integer);
integer -= integer2;
ayg.level.addFreshEntity(new ExperienceOrb(ayg.level, ayg.getX(), ayg.getY() + 0.5, ayg.getZ() + 0.5, integer2));
}
}
@Override
public void fillStackedContents(final StackedContents ayi) {
for (final ItemStack bek4 : this.items) {
ayi.accountStack(bek4);
}
}
static {
SLOTS_FOR_UP = new int[] { 0 };
SLOTS_FOR_DOWN = new int[] { 2, 1 };
SLOTS_FOR_SIDES = new int[] { 1 };
}
}