479 lines
18 KiB
Java
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 };
|
|
}
|
|
}
|