当前位置:网站首页>Minecraft 1.16.5 module development (51) tile entity
Minecraft 1.16.5 module development (51) tile entity
2022-07-01 07:26:00 【Jay_ fearless】
Minecraft1.12.2 Square solid tutorial
Minecraft1.18.2 Square solid tutorial
MC There are many interesting square entities such as billboards 、 Brewing table 、 Enchant table … We are here today 1.16 Implementation of a block entity similar to a furnace .
1. stay blocks Create a new box entity package in the package virusgenerator, Create a new block class in the package VirusGeneratorBlock
:
VirusGeneratorBlock.java
package com.joy187.re8joymod.common.blocks.virusgenerator;
import net.minecraft.block.*;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.item.BlockItemUseContext;
import net.minecraft.state.BooleanProperty;
import net.minecraft.state.DirectionProperty;
import net.minecraft.state.StateContainer;
import net.minecraft.state.properties.BlockStateProperties;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.*;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.math.shapes.ISelectionContext;
import net.minecraft.util.math.shapes.VoxelShape;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
import javax.annotation.Nullable;
public class VirusGeneratorBlock extends ContainerBlock {
// Parameters of the placement orientation of the block entity
public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;
public static final BooleanProperty LIT = BlockStateProperties.LIT;
private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 15, 16);
public VirusGeneratorBlock(AbstractBlock.Properties properties) {
super(properties);
this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(LIT, Boolean.valueOf(false)));
}
@Override
public VoxelShape getShape(BlockState pState, IBlockReader pLevel, BlockPos pPos, ISelectionContext pContext) {
return SHAPE;
}
/* FACING */
@Override
public BlockState getStateForPlacement(BlockItemUseContext pContext) {
return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());
}
@Override
public BlockState rotate(BlockState pState, Rotation pRotation) {
return pState.setValue(FACING, pRotation.rotate(pState.getValue(FACING)));
}
@Override
public BlockState mirror(BlockState pState, Mirror pMirror) {
return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));
}
@Override
protected void createBlockStateDefinition(StateContainer.Builder<Block, BlockState> pBuilder) {
pBuilder.add(FACING,LIT);
}
@Override
public BlockRenderType getRenderShape(BlockState pState) {
return BlockRenderType.MODEL;
}
@Override
public void onRemove(BlockState pState, World pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {
if (pState.getBlock() != pNewState.getBlock()) {
TileEntity blockEntity = pLevel.getBlockEntity(pPos);
if (blockEntity instanceof VirusGeneratorBlockEntity) {
((VirusGeneratorBlockEntity) blockEntity).dropContents(); //.drops();
//InventoryHelper.dropContents(pLevel, pPos, (VirusGeneratorBlockEntity)blockEntity);
}
}
super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);
}
@Override
public ActionResultType use(BlockState pState, World pLevel, BlockPos pPos,
PlayerEntity pPlayer, Hand pHand, BlockRayTraceResult pHit) {
if (!pLevel.isClientSide()) {
TileEntity entity = pLevel.getBlockEntity(pPos);
if(entity instanceof VirusGeneratorBlockEntity) {
// Execute open gui The operation of
NetworkHooks.openGui(((ServerPlayerEntity)pPlayer), (VirusGeneratorBlockEntity) entity, pPos);
} else {
throw new IllegalStateException("Our Container provider is missing!");
}
}
return ActionResultType.sidedSuccess(pLevel.isClientSide());
}
@Nullable
@Override
public TileEntity newBlockEntity(IBlockReader p_196283_1_) {
return new VirusGeneratorBlockEntity();
}
}
stay BlockInit Register our blocks in :
public static RegistryObject<Block> VIRUS_GENERATOR_BLOCK = BLOCKS.register("virus_generator",
()-> new VirusGeneratorBlock(AbstractBlock.Properties.copy(Blocks.IRON_BLOCK).harvestTool(ToolType.PICKAXE).harvestLevel(1).requiresCorrectToolForDrops()));
2. stay virusgenerator Create a new entity class in the package VirusGeneratorBlockEntity
:
VirusGeneratorBlockEntity.java
package com.joy187.re8joymod.common.blocks.virusgenerator;
import com.joy187.re8joymod.common.init.BlockEntityInit;
import com.joy187.re8joymod.common.init.ModItems;
import com.joy187.re8joymod.common.recipe.VirusGeneratorRecipe;
import com.joy187.re8joymod.common.screen.VirusGeneratorMenu;
import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.InventoryHelper;
import net.minecraft.inventory.ItemStackHelper;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.INamedContainerProvider;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.item.crafting.IRecipeType;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.LockableTileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.IIntArray;
import net.minecraft.util.NonNullList;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.World;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.ItemStackHandler;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nonnull;
import java.util.Optional;
public class VirusGeneratorBlockEntity extends LockableTileEntity implements INamedContainerProvider, ITickableTileEntity {
protected NonNullList<ItemStack> items = NonNullList.withSize(4, ItemStack.EMPTY);
protected IRecipeType<? extends VirusGeneratorRecipe> recipeType;
private final ItemStackHandler itemHandler = new ItemStackHandler(4) {
@Override
protected void onContentsChanged(int slot) {
setChanged();
}
};
private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty();
// Our block has two data: current reaction progress and total reaction progress
protected IIntArray data = new IIntArray() {
public int get(int index) {
switch (index) {
case 0: return VirusGeneratorBlockEntity.this.progress;
case 1: return VirusGeneratorBlockEntity.this.maxProgress;
default: return 0;
}
}
public void set(int index, int value) {
switch(index) {
case 0: VirusGeneratorBlockEntity.this.progress = value; break;
case 1: VirusGeneratorBlockEntity.this.maxProgress = value; break;
}
}
public int getCount() {
return 2;
}
};
private int progress = 0;
private int maxProgress = 72;
public VirusGeneratorBlockEntity() {
super(BlockEntityInit.VIRUS_GENERATOR_BLOCK_ENTITY.get());
this.data=new IIntArray() {
public int get(int index) {
switch (index) {
case 0: return VirusGeneratorBlockEntity.this.progress;
case 1: return VirusGeneratorBlockEntity.this.maxProgress;
default: return 0;
}
}
public void set(int index, int value) {
switch(index) {
case 0: VirusGeneratorBlockEntity.this.progress = value; break;
case 1: VirusGeneratorBlockEntity.this.maxProgress = value; break;
}
}
public int getCount() {
return 2;
}
};
}
@Override
public int getContainerSize() {
return this.items.size();
}
// The name of your machine
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("container.virus_generator");
}
@Override
protected ITextComponent getDefaultName() {
return new TranslationTextComponent("container.virus_generator");
}
@Override
protected Container createMenu(int pContainerId, PlayerInventory pInventory) {
return new VirusGeneratorMenu(pContainerId, pInventory, this, this.data);
}
@Nonnull
@Override
public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, @javax.annotation.Nullable Direction side) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
return lazyItemHandler.cast();
}
return super.getCapability(cap, side);
}
@Override
public void onLoad() {
super.onLoad();
lazyItemHandler = LazyOptional.of(() -> itemHandler);
}
@Override
public void invalidateCaps() {
super.invalidateCaps();
lazyItemHandler.invalidate();
}
// Store the current reaction progress of your machine in nbt In the label ,virus_generator.progress Inside the store progress data
@Override
public CompoundNBT save(@NotNull CompoundNBT tag) {
tag.put("inventory", itemHandler.serializeNBT());
tag.putInt("virus_generator.progress", progress);
super.save(tag);
return tag;
}
@Override
public void load(BlockState p_230337_1_,CompoundNBT nbt) {
super.load(p_230337_1_,nbt);
this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
ItemStackHelper.loadAllItems(nbt, this.items);
itemHandler.deserializeNBT(nbt.getCompound("inventory"));
progress = nbt.getInt("virus_generator.progress");
}
public void dropContents() {
Inventory inventory = new Inventory(itemHandler.getSlots());
for (int i = 0; i < itemHandler.getSlots(); i++) {
inventory.setItem(i, itemHandler.getStackInSlot(i));
}
InventoryHelper.dropContents(this.level, this.getBlockPos(), inventory);
}
// public void drops() {
// SimpleContainer inventory = new SimpleContainer(itemHandler.getSlots());
// for (int i = 0; i < itemHandler.getSlots(); i++) {
// inventory.setItem(i, itemHandler.getStackInSlot(i));
// }
//
// Containers.dropContents(this.level, this.worldPosition, inventory);
// }
// Monitor the status of our machines at every moment
@Override
public void tick() {
if(hasRecipe(this)) {
this.getBlockState().setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(true));
this.progress++;
//setChanged(pLevel, pPos, pState);
setChanged();
// The current progress has exceeded the maximum progress , It means that the product is going to be produced
if(this.progress > this.maxProgress) {
// Call the generate product function
craftItem(this);
}
} else {
this.getBlockState().setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(false));
this.resetProgress();
//setChanged(pLevel, pPos, pState);
setChanged();
}
}
// Judge whether the raw material we put is a correct formula
private boolean hasRecipe(VirusGeneratorBlockEntity entity) {
World level = entity.level;
Inventory inventory = new Inventory(entity.itemHandler.getSlots());
for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
}
Optional<VirusGeneratorRecipe> match = level.getRecipeManager()
.getRecipeFor((IRecipeType)VirusGeneratorRecipe.Type.INSTANCE, inventory, level);
return match.isPresent() && canInsertAmountIntoOutputSlot(inventory)
&& canInsertItemIntoOutputSlot(inventory, match.get().getResultItem())
&& hasFuelSlot(entity); // && has0Slot(entity) && has1Slot(entity);
}
// Judge whether our fuel is put into
private static boolean hasFuelSlot(VirusGeneratorBlockEntity entity) {
return entity.itemHandler.getStackInSlot(2).getItem() == ModItems.BLACKSHEEP.get();
}
// Output products , At the same time, the quantity of all raw materials -1
private static void craftItem(VirusGeneratorBlockEntity entity) {
World level = entity.level;
Inventory inventory = new Inventory(entity.itemHandler.getSlots());
for (int i = 0; i < entity.itemHandler.getSlots(); i++) {
inventory.setItem(i, entity.itemHandler.getStackInSlot(i));
}
//IRecipe<?> match = level.getRecipeManager().getRecipeFor(RecipeInit.VIRUS_GENERATOR_SERIALIZER., inventory, level).orElse(null);
// Optional<VirusGeneratorRecipe> match = level.getRecipeManager()
// .getRecipeFor((IRecipeType)RecipeInit.VIRUS_GENERATOR_SERIALIZER.get(), inventory, level);
Optional<VirusGeneratorRecipe> match = level.getRecipeManager()
.getRecipeFor((IRecipeType)VirusGeneratorRecipe.Type.INSTANCE, inventory, level);
//return this.level.getRecipeManager().getRecipeFor((IRecipeType)this.recipeType, new Inventory(p_217057_1_), this.level).isPresent();
if(match.isPresent()) {
//if(has0Slot(entity) && has1Slot(entity) && hasFuelSlot(entity)) {
entity.itemHandler.extractItem(0,1, false);
entity.itemHandler.extractItem(1,1, false);
entity.itemHandler.extractItem(2,1, false);
entity.itemHandler.setStackInSlot(3, new ItemStack(match.get().getResultItem().getItem(),
entity.itemHandler.getStackInSlot(3).getCount() + 1));
// Reset our progress after output , Start producing the next product
entity.resetProgress();
}
}
private void resetProgress() {
this.progress = 0;
}
private boolean canInsertItemIntoOutputSlot(Inventory inventory, ItemStack output) {
return this.getItem(3).getItem() == output.getItem() || this.getItem(3).isEmpty();
}
private boolean canInsertAmountIntoOutputSlot(Inventory inventory) {
return this.getItem(3).getMaxStackSize() > this.getItem(3).getCount();
}
private static boolean notReachLimit(VirusGeneratorBlockEntity entity) {
return entity.itemHandler.getStackInSlot(3).getCount()<64;
}
@Override
public boolean isEmpty() {
for(ItemStack itemstack : this.items) {
if (!itemstack.isEmpty()) {
return false;
}
}
return true;
}
@Override
public ItemStack getItem(int p_70301_1_) {
return this.items.get(p_70301_1_);
}
@Override
public ItemStack removeItem(int p_70298_1_, int p_70298_2_) {
return ItemStackHelper.removeItem(this.items, p_70298_1_, p_70298_2_);
}
@Override
public ItemStack removeItemNoUpdate(int p_70304_1_) {
return ItemStackHelper.takeItem(this.items, p_70304_1_);
}
@Override
public void setItem(int p_70299_1_, ItemStack p_70299_2_) {
ItemStack itemstack = this.items.get(p_70299_1_);
boolean flag = !p_70299_2_.isEmpty() && p_70299_2_.sameItem(itemstack) && ItemStack.tagMatches(p_70299_2_, itemstack);
this.items.set(p_70299_1_, p_70299_2_);
if (p_70299_2_.getCount() > this.getMaxStackSize()) {
p_70299_2_.setCount(this.getMaxStackSize());
}
if (p_70299_1_ == 0 && !flag) {
this.progress = 0;
this.setChanged();
}
}
@Override
public boolean stillValid(PlayerEntity p_70300_1_) {
if (this.level.getBlockEntity(this.worldPosition) != this) {
return false;
} else {
return p_70300_1_.distanceToSqr((double)this.worldPosition.getX() + 0.5D, (double)this.worldPosition.getY() + 0.5D, (double)this.worldPosition.getZ() + 0.5D) <= 64.0D;
} }
@Override
public void clearContent() {
this.items.clear();
}
}
stay init Create a new one in the package BlockEntityInit
class , Register all the block entities in our module :
BlockEntityInit.java
package com.joy187.re8joymod.common.init;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.blocks.virusgenerator.VirusGeneratorBlockEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
public class BlockEntityInit {
public static final DeferredRegister<TileEntityType<?>> BLOCK_ENTITIES =
DeferredRegister.create(ForgeRegistries.TILE_ENTITIES, Utils.MOD_ID);
// Register our block entities
public static RegistryObject<TileEntityType<VirusGeneratorBlockEntity>> VIRUS_GENERATOR_BLOCK_ENTITY =
BLOCK_ENTITIES.register("virus_generator_block_entity", () -> TileEntityType.Builder.of(
VirusGeneratorBlockEntity::new, ModBlocks.VIRUS_GENERATOR_BLOCK.get()).build(null));
public static void register(IEventBus eventBus) {
BLOCK_ENTITIES.register(eventBus);
}
}
In our project main class Main Function will be BlockEntityInit
Class to register :
public Main(){
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
bus.addListener(this::setup);
bus.addListener(this::doClientStuff);
SoundInit.SOUND_TYPES.register(bus);
EntityInit.ENTITY_TYPES.register(bus);
ModItems.ITEMS.register(bus);
ModBlocks.BLOCKS.register(bus);
// Add this
BlockEntityInit.register(bus);
}
3. stay Java Create a new recipe package in the package recipe
-> recipe
New in package VirusGeneratorRecipe
class :
VirusGeneratorRecipe.java
package com.joy187.re8joymod.common.recipe;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.joy187.re8joymod.Utils;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.*;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.JSONUtils;
import net.minecraft.util.NonNullList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public class VirusGeneratorRecipe implements IRecipe<Inventory> {
private final ResourceLocation id;
private final ItemStack output;
private final NonNullList<Ingredient> recipeItems;
public VirusGeneratorRecipe(ResourceLocation id, ItemStack output,
NonNullList<Ingredient> recipeItems) {
this.id = id;
this.output = output;
this.recipeItems = recipeItems;
}
@Override
public NonNullList<Ingredient> getIngredients() {
return recipeItems;
}
// @Override
// public ItemStack assemble(ItemStackHandler pContainer) {
// return output;
// }
// Judge whether our two raw materials are consistent with the corresponding ingredients in the formula
@Override
public boolean matches(Inventory pContainer, World p_77569_2_) {
return recipeItems.get(0).test(pContainer.getItem(1))
&& recipeItems.get(1).test(pContainer.getItem(0));
}
@Override
public ItemStack assemble(Inventory p_77572_1_) {
return output;
}
@Override
public boolean canCraftInDimensions(int pWidth, int pHeight) {
return true;
}
@Override
public ItemStack getResultItem() {
return output.copy();
}
@Override
public ResourceLocation getId() {
return id;
}
@Override
public IRecipeSerializer<?> getSerializer() {
return Serializer.INSTANCE;
}
@Override
public IRecipeType<?> getType() {
return Type.INSTANCE;
}
public static class Type implements IRecipeType<VirusGeneratorRecipe> {
private Type() { }
public static final Type INSTANCE = new Type();
public static final String ID = "virus_generator";
}
// Our recipe is to .json After the file is converted, judge in the game
public static class Serializer implements IRecipeSerializer<VirusGeneratorRecipe> {
public static final Serializer INSTANCE = new Serializer();
// This name is very important , Because we define this recipe type as virus_generator
public static final ResourceLocation ID = new ResourceLocation(Utils.MOD_ID,"virus_generator");
@Override
public VirusGeneratorRecipe fromJson(ResourceLocation id, JsonObject json) {
ItemStack output = ShapedRecipe.itemFromJson(JSONUtils.getAsJsonObject(json, "output"));
JsonArray ingredients = JSONUtils.getAsJsonArray(json, "ingredients");
// Because we have two raw material tanks , So this is 2
NonNullList<Ingredient> inputs = NonNullList.withSize(2, Ingredient.EMPTY);
for (int i = 0; i < inputs.size(); i++) {
inputs.set(i, Ingredient.fromJson(ingredients.get(i)));
}
return new VirusGeneratorRecipe(id, output, inputs);
}
@Override
public VirusGeneratorRecipe fromNetwork(ResourceLocation id, PacketBuffer buf) {
NonNullList<Ingredient> inputs = NonNullList.withSize(buf.readInt(), Ingredient.EMPTY);
for (int i = 0; i < inputs.size(); i++) {
inputs.set(i, Ingredient.fromNetwork(buf));
}
ItemStack output = buf.readItem();
return new VirusGeneratorRecipe(id, output, inputs);
}
@Override
public void toNetwork(PacketBuffer buf, VirusGeneratorRecipe recipe) {
buf.writeInt(recipe.getIngredients().size());
for (Ingredient ing : recipe.getIngredients()) {
ing.toNetwork(buf);
}
buf.writeItemStack(recipe.getResultItem(), false);
}
@Override
public IRecipeSerializer<?> setRegistryName(ResourceLocation name) {
return INSTANCE;
}
@Nullable
@Override
public ResourceLocation getRegistryName() {
return ID;
}
@Override
public Class<IRecipeSerializer<?>> getRegistryType() {
return Serializer.castClass(IRecipeSerializer.class);
}
@SuppressWarnings("unchecked") // Need this wrapper, because generics
private static <G> Class<G> castClass(Class<?> cls) {
return (Class<G>)cls;
}
}
}
stay init New in package RecipeInit
class , Register our recipe class :
RecipeInit.java
package com.joy187.re8joymod.common.init;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.recipe.VirusGeneratorRecipe;
import net.minecraft.item.crafting.IRecipeSerializer;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
public class RecipeInit
{
public static final DeferredRegister<IRecipeSerializer<?>> SERIALIZERS =
DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, Utils.MOD_ID);
// Register our recipe class
public static final RegistryObject<IRecipeSerializer<?>> VIRUS_GENERATOR_SERIALIZER =
SERIALIZERS.register("virus_generator", () -> VirusGeneratorRecipe.Serializer.INSTANCE);
public static void register(IEventBus eventBus) {
SERIALIZERS.register(eventBus);
}
}
In our project main class Main Function will be BlockEntityInit
Class to register :
public Main(){
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
bus.addListener(this::setup);
bus.addListener(this::doClientStuff);
SoundInit.SOUND_TYPES.register(bus);
EntityInit.ENTITY_TYPES.register(bus);
ModItems.ITEMS.register(bus);
ModBlocks.BLOCKS.register(bus);
BlockEntityInit.register(bus);
// Add this
RecipeInit.register(bus);
}
4. The code part of the block and entity ends , Enter into GUI The production process of . stay Java Create a new one in the package screen package -> screen New in package VirusGeneratorScreen
Class indicates that we GUI Where the map is stored :
VirusGeneratorScreen.java
package com.joy187.re8joymod.common.screen;
import com.joy187.re8joymod.Utils;
import com.mojang.blaze3d.matrix.MatrixStack;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.screen.inventory.ContainerScreen;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
public class VirusGeneratorScreen extends ContainerScreen<VirusGeneratorMenu> {
// our gui picture
private static final ResourceLocation TEXTURE =
new ResourceLocation(Utils.MOD_ID, "textures/gui/virus_generator.png");
public VirusGeneratorScreen(VirusGeneratorMenu pMenu, PlayerInventory pPlayerInventory, ITextComponent pTitle) {
super(pMenu, pPlayerInventory, pTitle);
}
// Render our background image
@Override
protected void renderBg(MatrixStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) {
//RenderSystem.(GameRenderer::getPositionTexShader);
RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
this.minecraft.getTextureManager().bind(TEXTURE);
//RenderSystem.(0, TEXTURE);
int x = (width - imageWidth) / 2;
int y = (height - imageHeight) / 2;
this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight);
if(this.menu.isCrafting()) {
// Here is our progress bar , Like a furnace , Please refer to the top for the coordinate correspondence 1.12.2 A tutorial for
blit(pPoseStack, x + 8, y + 54+12-13, 176, 12-13, 14, this.menu.getScaledProgress());
}
}
@Override
public void render(MatrixStack pPoseStack, int mouseX, int mouseY, float delta) {
renderBackground(pPoseStack);
// this.getMinecraft().getTextureManager().bind(TEXTURE);
// this.getMinecraft().getTextureManager().getTexture(TEXTURE);
super.render(pPoseStack, mouseX, mouseY, delta);
//renderTooltip(pPoseStack, mouseX, mouseY);
}
}
screen New in package VirusGeneratorMenu
Class points out the position of all slots :
VirusGeneratorMenu.java
package com.joy187.re8joymod.common.screen;
import com.joy187.re8joymod.common.blocks.virusgenerator.VirusGeneratorBlockEntity;
import com.joy187.re8joymod.common.init.MenuInit;
import com.joy187.re8joymod.common.init.ModBlocks;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IIntArray;
import net.minecraft.util.IWorldPosCallable;
import net.minecraft.util.IntArray;
import net.minecraft.world.World;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.SlotItemHandler;
public class VirusGeneratorMenu extends Container {
private final VirusGeneratorBlockEntity blockEntity;
private final World level;
private final IIntArray data;
public VirusGeneratorMenu(int pContainerId, PlayerInventory inv, PacketBuffer extraData) {
this(pContainerId, inv, inv.player.level.getBlockEntity(extraData.readBlockPos()), new IntArray(2));
}
public VirusGeneratorMenu(int pContainerId, PlayerInventory inv, TileEntity entity, IIntArray data) {
super(MenuInit.VIRUS_GENERATOR_MENU.get(), pContainerId);
// We share 4 Slot , A fuel tank , Two raw material tanks , A product tank
checkContainerSize(inv, 4);
blockEntity = ((VirusGeneratorBlockEntity) entity);
this.level = inv.player.level;
this.data = data;
addPlayerInventory(inv);
addPlayerHotbar(inv);
this.blockEntity.getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY).ifPresent(handler -> {
// Set coordinates
this.addSlot(new SlotItemHandler(handler, 0, 26, 11));
this.addSlot(new SlotItemHandler(handler, 1, 26, 59));
this.addSlot(new SlotItemHandler(handler, 2, 7, 35));
this.addSlot(new ModResultSlot(handler, 3, 81, 36));
});
addDataSlots(data);
}
public boolean isCrafting() {
return data.get(0) > 0;
}
public int getScaledProgress() {
int progress = this.data.get(0);
int maxProgress = this.data.get(1); // Max Progress
//int progressArrowSize = 26; // This is the height in pixels of your arrow
int progressArrowSize = 13;
return maxProgress != 0 && progress != 0 ? progress * progressArrowSize / maxProgress : 0;
}
// CREDIT GOES TO: diesieben07 | https://github.com/diesieben07/SevenCommons
// must assign a slot number to each of the slots used by the GUI.
// For this container, we can see both the tile inventory's slots as well as the player inventory slots and the hotbar.
// Each time we add a Slot to the container, it automatically increases the slotIndex, which means
// 0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers 0 - 8)
// 9 - 35 = player inventory slots (which map to the InventoryPlayer slot numbers 9 - 35)
// 36 - 44 = TileInventory slots, which map to our TileEntity slot numbers 0 - 8)
private static final int HOTBAR_SLOT_COUNT = 9;
private static final int PLAYER_INVENTORY_ROW_COUNT = 3;
private static final int PLAYER_INVENTORY_COLUMN_COUNT = 9;
private static final int PLAYER_INVENTORY_SLOT_COUNT = PLAYER_INVENTORY_COLUMN_COUNT * PLAYER_INVENTORY_ROW_COUNT;
private static final int VANILLA_SLOT_COUNT = HOTBAR_SLOT_COUNT + PLAYER_INVENTORY_SLOT_COUNT;
private static final int VANILLA_FIRST_SLOT_INDEX = 0;
private static final int TE_INVENTORY_FIRST_SLOT_INDEX = VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT;
// This is consistent with the slot position above us 4
private static final int TE_INVENTORY_SLOT_COUNT = 4; // must be the number of slots you have!
@Override
public ItemStack quickMoveStack(PlayerEntity playerIn, int index) {
Slot sourceSlot = slots.get(index);
if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEM
ItemStack sourceStack = sourceSlot.getItem();
ItemStack copyOfSourceStack = sourceStack.copy();
// Check if the slot clicked is one of the vanilla container slots
if (index < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {
// This is a vanilla container slot so merge the stack into the tile inventory
if (!moveItemStackTo(sourceStack, TE_INVENTORY_FIRST_SLOT_INDEX, TE_INVENTORY_FIRST_SLOT_INDEX
+ TE_INVENTORY_SLOT_COUNT, false)) {
return ItemStack.EMPTY; // EMPTY_ITEM
}
} else if (index < TE_INVENTORY_FIRST_SLOT_INDEX + TE_INVENTORY_SLOT_COUNT) {
// This is a TE slot so merge the stack into the players inventory
if (!moveItemStackTo(sourceStack, VANILLA_FIRST_SLOT_INDEX, VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT, false)) {
return ItemStack.EMPTY;
}
} else {
//System.out.println("Invalid slotIndex:" + index);
return ItemStack.EMPTY;
}
// If stack size == 0 (the entire stack was moved) set slot contents to null
if (sourceStack.getCount() == 0) {
sourceSlot.set(ItemStack.EMPTY);
} else {
sourceSlot.setChanged();
}
sourceSlot.onTake(playerIn, sourceStack);
return copyOfSourceStack;
}
@Override
public boolean stillValid(PlayerEntity pPlayer) {
return stillValid(IWorldPosCallable.create(level, blockEntity.getBlockPos()),
pPlayer, ModBlocks.VIRUS_GENERATOR_BLOCK.get());
}
// Render the player's item slot , No need to change
private void addPlayerInventory(PlayerInventory playerInventory) {
for (int i = 0; i < 3; ++i) {
for (int l = 0; l < 9; ++l) {
this.addSlot(new Slot(playerInventory, l + i * 9 + 9, 8 + l * 18, 84 + i * 18));
}
}
}
// Render the player's item slot , No need to change
private void addPlayerHotbar(PlayerInventory playerInventory) {
for (int i = 0; i < 9; ++i) {
this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));
}
}
}
stay screen New in package ModResultSlot
class , Put our products in the preset .
ModResultSlot.java
package com.joy187.re8joymod.common.screen;
import net.minecraft.item.ItemStack;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.SlotItemHandler;
public class ModResultSlot extends SlotItemHandler {
public ModResultSlot(IItemHandler itemHandler, int index, int x, int y) {
super(itemHandler, index, x, y);
}
@Override
public boolean mayPlace(ItemStack stack) {
return false;
}
}
5. stay init New in package MenuInit
class , Register the menu in step 4 :
MenuInit.java
package com.joy187.re8joymod.common.init;
import com.joy187.re8joymod.Utils;
import com.joy187.re8joymod.common.screen.VirusGeneratorMenu;
import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.ContainerType;
import net.minecraftforge.common.extensions.IForgeContainerType;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.RegistryObject;
import net.minecraftforge.fml.network.IContainerFactory;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
public class MenuInit {
public static final DeferredRegister<ContainerType<?>> MENUS =
DeferredRegister.create(ForgeRegistries.CONTAINERS, Utils.MOD_ID);
// Register our screen information
public static final RegistryObject<ContainerType<VirusGeneratorMenu>> VIRUS_GENERATOR_MENU =
registerMenuType(VirusGeneratorMenu::new, "virus_generator_menu");
private static <T extends Container>RegistryObject<ContainerType<T>> registerMenuType(IContainerFactory<T> factory,
String name) {
return MENUS.register(name, () -> IForgeContainerType.create(factory));
}
public static void register(IEventBus eventBus) {
MENUS.register(eventBus);
}
}
In our project main class Main Function will be MenuInit
Class to register :
public Main(){
IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();
bus.addListener(this::setup);
bus.addListener(this::doClientStuff);
SoundInit.SOUND_TYPES.register(bus);
EntityInit.ENTITY_TYPES.register(bus);
ModItems.ITEMS.register(bus);
ModBlocks.BLOCKS.register(bus);
BlockEntityInit.register(bus);
RecipeInit.register(bus);
// Add this
MenuInit.register(bus);
}
In the main class of the project doClientStuff Function will be our gui To register , At the same time, it is bound with screen information
private void doClientStuff(final FMLClientSetupEvent event) {
event.enqueueWork(() -> {
RenderTypeLookup.setRenderLayer(ModBlocks.HERB_BLOCK.get(), RenderType.cutout());
RenderTypeLookup.setRenderLayer(ModBlocks.PINK_ROSE.get(), RenderType.cutout());
RenderTypeLookup.setRenderLayer(ModBlocks.EBONY_LEAVES.get(), RenderType.cutout());
RenderTypeLookup.setRenderLayer(ModBlocks.EBONY_SAPLING.get(), RenderType.cutout());
// Add this
ScreenManager.register(MenuInit.VIRUS_GENERATOR_MENU.get(), VirusGeneratorScreen::new);
});
}
6. The code section ends , Come to resource pack production . stay src\main\resources\assets\ Yours modid\blockstates
Create a new status file for our block in :
virus_generator.json
{
"variants": {
"facing=east,lit=false": {
"model": "re8joymod:block/virus_generator",
"y": 90
},
"facing=east,lit=true": {
"model": "re8joymod:block/virus_generator_on",
"y": 90
},
"facing=north,lit=false": {
"model": "re8joymod:block/virus_generator"
},
"facing=north,lit=true": {
"model": "re8joymod:block/virus_generator_on"
},
"facing=south,lit=false": {
"model": "re8joymod:block/virus_generator",
"y": 180
},
"facing=south,lit=true": {
"model": "re8joymod:block/virus_generator_on",
"y": 180
},
"facing=west,lit=false": {
"model": "re8joymod:block/virus_generator",
"y": 270
},
"facing=west,lit=true": {
"model": "re8joymod:block/virus_generator_on",
"y": 270
}
}
}
stay src\main\resources\assets\ Yours modid\models\block
Create two new block model files in :
The usual model of the block
virus_generator.json
{
"parent": "block/orientable",
"textures": {
"top": "re8joymod:blocks/virus_generator_side",
"front": "re8joymod:blocks/virus_generator",
"side": "re8joymod:blocks/virus_generator_side"
}
}
The model when the block works
virus_generator_on.json
{
"parent": "block/orientable",
"textures": {
"top": "re8joymod:blocks/virus_generator_side",
"front": "re8joymod:blocks/virus_generator_on",
"side": "re8joymod:blocks/virus_generator_side"
}
}
stay models\item
Add the model file when we hold the box
virus_generator.json
{
"parent": "re8joymod:block/virus_generator"
}
stay textures\block
Add the side of our square to the 、 The front does not work 、 The map when the front works :
stay textures New in package gui package -> gui Our... In the bag gui( The size is 256×256 Pixel point ) Put it in :
stay lang In bag en_us.json
Add the name of our block entity and the name shown above after opening the machine to the file :
"block.re8joymod.virus_generator":"Virus Analyser",
"container.virus_generator":"Virus Analyser",
8. stay src\main\resources\data\ Yours modid\recipes
Create several recipes for our cube entities in :
Remember that in the third step, we set the recipe type to virus_generator
, So the formula type It's written as virus_generator
:
evirus.json
{
"type":"re8joymod:virus_generator",
"ingredients":[
{
"item":"re8joymod:humus"
},
{
"item":"re8joymod:herbglass"
}
],
"output":{
"item":"re8joymod:evirus"
}
}
9. Save all files -> Enter game debugging :
First take out our machine and put it down , The appearance is normal
Put the fuel and products into , The product was produced successfully !
边栏推荐
- Apple account password auto fill
- Cadence OrCAD capture "network name" is the same, but it is not connected or connected incorrectly. The usage of nodeName of liberation scheme
- 【推荐系统】美团外卖推荐场景的深度位置交互网络DPIN的突破与畅想
- ctfhub-端口扫描(SSRF)
- 运维管理有什么实用的技巧吗
- Microsoft announces open source (Godel) language model chat robot
- 【电气介数】电气介数及考虑HVDC和FACTS元件的电气介数计算
- 浅谈CVPR2022的几个研究热点
- [recommendation technology] matlab simulation of network information recommendation technology based on collaborative filtering
- AUTOSAR learning record (1) – ECUM_ Init
猜你喜欢
ctfshow-web351(SSRF)
[image processing] image histogram equalization system with GUI interface
[lingo] find the minimum connection diagram of seven cities to minimize the price of natural gas pipelines
1286_FreeRTOS的任务优先级设置实现分析
Inftnews | from "avalanche" to Baidu "xirang", 16 major events of the meta universe in 30 years
热烈祝贺五行和合酒成功挂牌
Alibaba OSS postman invalid according to policy: policy condition failed: ["starts with", "key", "test/"]
[matlab] solve nonlinear programming
【目标检测】目标检测界的扛把子YOLOv5(原理详解+修炼指南)
Custom events of components ②
随机推荐
【编程强训2】排序子序列+倒置字符串
Will Internet talents be scarce in the future? Which technology directions are popular?
Inventory the six second level capabilities of Huawei cloud gaussdb (for redis)
Redisson uses the full solution - redisson official documents + comments (Part 2)
C # read and write customized config file
2022年流动式起重机司机考试练习题及在线模拟考试
2022广东省安全员A证第三批(主要负责人)特种作业证考试题库模拟考试平台操作
组件的自定义事件②
LeetCode+ 71 - 75
Browser local storage
【深圳IO】精确食品称(汇编语言的一些理解)
Detailed explanation of weback5 basic configuration
1286_ Implementation analysis of task priority setting in FreeRTOS
[programming compulsory training 3] find the longest consecutive number string in the string + the number that appears more than half of the times in the array
Redisson uses the full solution - redisson official document + comments (Part 2)
继妹变继母,儿子与自己断绝关系,世界首富马斯克,为何这么惨?
【LINGO】求无向图的最短路问题
电脑有网络,但所有浏览器网页都打不开,是怎么回事?
Redisson uses the complete solution - redisson official documents + Notes (Part 1)
[lingo] find the shortest path problem of undirected graph