700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Minecraft 1.18.1 1.18.2模组开发 22.方块实体(BlockEntity)

Minecraft 1.18.1 1.18.2模组开发 22.方块实体(BlockEntity)

时间:2024-08-16 15:22:30

相关推荐

Minecraft 1.18.1 1.18.2模组开发 22.方块实体(BlockEntity)

Minecraft1.12.2 方块实体教程

MC中有许多很有趣的方块实体如旗帜、钟、附魔台…我们今天在1.18的版本下实现一个类似于熔炉的方块实体。

1.在blocks包中新建一个我们的方块实体包virusgenerator,包中新建一个我们的方块类VirusGeneratorBlock

VirusGeneratorBlock.java

package com.joy187.re8joymod.blocks.virusgenerator;import net.minecraft.world.level.block.BaseEntityBlock;import net.minecraft.world.level.block.state.properties.BlockStateProperties;import net.minecraft.world.level.block.state.properties.BooleanProperty;import net.minecraft.world.level.block.state.properties.DirectionProperty;import net.minecraft.world.phys.shapes.VoxelShape;import net.minecraft.core.BlockPos;import net.minecraft.core.Direction;import net.minecraft.server.level.ServerPlayer;import net.minecraft.world.InteractionHand;import net.minecraft.world.InteractionResult;import net.minecraft.world.entity.player.Player;import net.minecraft.world.item.context.BlockPlaceContext;import net.minecraft.world.level.BlockGetter;import net.minecraft.world.level.Level;import net.minecraft.world.level.block.*;import net.minecraft.world.level.block.entity.BlockEntity;import net.minecraft.world.level.block.entity.BlockEntityTicker;import net.minecraft.world.level.block.entity.BlockEntityType;import net.minecraft.world.level.block.state.BlockState;import net.minecraft.world.level.block.state.StateDefinition;import net.minecraft.world.phys.BlockHitResult;import net.minecraft.world.phys.shapes.CollisionContext;import workHooks;import org.jetbrains.annotations.Nullable;import com.joy187.re8joymod.init.BlockEntityInit;public class VirusGeneratorBlock extends BaseEntityBlock {public static final DirectionProperty FACING = BlockStateProperties.HORIZONTAL_FACING;public static final BooleanProperty LIT = BlockStateProperties.LIT;public VirusGeneratorBlock(Properties properties) {super(properties);this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(LIT, Boolean.valueOf(false)));}private static final VoxelShape SHAPE = Block.box(0, 0, 0, 16, 15, 16);@Overridepublic VoxelShape getShape(BlockState pState, BlockGetter pLevel, BlockPos pPos, CollisionContext pContext) {return SHAPE;}/* FACING */@Overridepublic BlockState getStateForPlacement(BlockPlaceContext pContext) {return this.defaultBlockState().setValue(FACING, pContext.getHorizontalDirection().getOpposite());}@Overridepublic BlockState rotate(BlockState pState, Rotation pRotation) {return pState.setValue(FACING, pRotation.rotate(pState.getValue(FACING)));}@Overridepublic BlockState mirror(BlockState pState, Mirror pMirror) {return pState.rotate(pMirror.getRotation(pState.getValue(FACING)));}@Overrideprotected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> pBuilder) {pBuilder.add(FACING,LIT);}@Overridepublic RenderShape getRenderShape(BlockState pState) {return RenderShape.MODEL;}@Overridepublic void onRemove(BlockState pState, Level pLevel, BlockPos pPos, BlockState pNewState, boolean pIsMoving) {if (pState.getBlock() != pNewState.getBlock()) {BlockEntity blockEntity = pLevel.getBlockEntity(pPos);if (blockEntity instanceof VirusGeneratorBlockEntity) {((VirusGeneratorBlockEntity) blockEntity).drops();}}super.onRemove(pState, pLevel, pPos, pNewState, pIsMoving);}@Overridepublic InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos,Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {if (!pLevel.isClientSide()) {BlockEntity entity = pLevel.getBlockEntity(pPos);if(entity instanceof VirusGeneratorBlockEntity) {NetworkHooks.openGui(((ServerPlayer)pPlayer), (VirusGeneratorBlockEntity)entity, pPos);} else {throw new IllegalStateException("Our Container provider is missing!");}}return InteractionResult.sidedSuccess(pLevel.isClientSide());}@Nullable@Overridepublic BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) {return new VirusGeneratorBlockEntity(pPos, pState);}@Nullable@Overridepublic <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level pLevel, BlockState pState, BlockEntityType<T> pBlockEntityType) {return createTickerHelper(pBlockEntityType, BlockEntityInit.VIRUS_GENERATOR_BLOCK_ENTITY.get(),VirusGeneratorBlockEntity::tick);}}

在BlockInit中注册我们的方块:

public static final RegistryObject<Block> VIRUS_GENERATOR_BLOCK = registerBlock("virus_generator",() -> new VirusGeneratorBlock(BlockBehaviour.Properties.copy(Blocks.IRON_BLOCK).noOcclusion()),Main.TUTORIAL_TAB);

2.在virusgenerator包中新建一个我们的实体类VirusGeneratorBlockEntity:

VirusGeneratorBlockEntity.java

package com.joy187.re8joymod.blocks.virusgenerator;import net.minecraft.core.BlockPos;import net.minecraft.core.Direction;import net.poundTag;import ponent;import work.chat.TextComponent;import work.chat.TranslatableComponent;import net.minecraft.world.Containers;import net.minecraft.world.MenuProvider;import net.minecraft.world.SimpleContainer;import net.minecraft.world.entity.player.Inventory;import net.minecraft.world.entity.player.Player;import net.minecraft.world.inventory.AbstractContainerMenu;import net.minecraft.world.inventory.ContainerData;import net.minecraft.world.item.ItemStack;import net.minecraft.world.item.Items;import net.minecraft.world.item.alchemy.PotionUtils;import net.minecraft.world.item.alchemy.Potions;import net.minecraft.world.level.Level;import net.minecraft.world.level.block.AbstractFurnaceBlock;import net.minecraft.world.level.block.entity.BlockEntity;import net.minecraft.world.level.block.state.BlockState;import mon.capabilities.Capability;import mon.util.LazyOptional;import net.minecraftforge.items.CapabilityItemHandler;import net.minecraftforge.items.IItemHandler;import net.minecraftforge.items.ItemStackHandler;import org.jetbrains.annotations.NotNull;import org.jetbrains.annotations.Nullable;import com.joy187.re8joymod.init.BlockEntityInit;import com.joy187.re8joymod.init.ItemInit;import com.joy187.re8joymod.screen.VirusGeneratorMenu;import javax.annotation.Nonnull;import java.util.Optional;import java.util.Random;public class VirusGeneratorBlockEntity extends BlockEntity implements MenuProvider {private BlockState blockState;private final ItemStackHandler itemHandler = new ItemStackHandler(4) {@Overrideprotected void onContentsChanged(int slot) {setChanged();}};private LazyOptional<IItemHandler> lazyItemHandler = LazyOptional.empty();protected final ContainerData data;private int progress = 0;//你熔炼一个物品所需要的时间刻tickprivate int maxProgress = 72;public VirusGeneratorBlockEntity(BlockPos pWorldPosition, BlockState pBlockState) {super(BlockEntityInit.VIRUS_GENERATOR_BLOCK_ENTITY.get(), pWorldPosition, pBlockState);this.data = new ContainerData() {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;}};}@Overridepublic Component getDisplayName() {return new TranslatableComponent("container.virus_generator");}// protected Component getDefaultName() {// return new TranslatableComponent("container.virus_generator");// }@Nullable@Overridepublic AbstractContainerMenu createMenu(int pContainerId, Inventory pInventory, Player pPlayer) {return new VirusGeneratorMenu(pContainerId, pInventory, this, this.data);}@Nonnull@Overridepublic <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);}@Overridepublic void onLoad() {super.onLoad();lazyItemHandler = LazyOptional.of(() -> itemHandler);}@Overridepublic void invalidateCaps() {super.invalidateCaps();lazyItemHandler.invalidate();}@Overrideprotected void saveAdditional(@NotNull CompoundTag tag) {tag.put("inventory", itemHandler.serializeNBT());tag.putInt("virus_generator.progress", progress);super.saveAdditional(tag);}@Overridepublic void load(CompoundTag nbt) {super.load(nbt);itemHandler.deserializeNBT(nbt.getCompound("inventory"));progress = nbt.getInt("virus_generator.progress");}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);}public static void tick(Level pLevel, BlockPos pPos, BlockState pState, VirusGeneratorBlockEntity pBlockEntity) {if(hasRecipe(pBlockEntity)) {pState.setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(true));pBlockEntity.progress++;setChanged(pLevel, pPos, pState);if(pBlockEntity.progress > pBlockEntity.maxProgress) {craftItem(pBlockEntity);}} else {pState.setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(false));pBlockEntity.resetProgress();setChanged(pLevel, pPos, pState);}// if(hasRecipe(pBlockEntity) && notReachLimit(pBlockEntity)) {// craftItem(pBlockEntity);// }}private static boolean hasRecipe(VirusGeneratorBlockEntity entity) {Level level = entity.level;SimpleContainer inventory = new SimpleContainer(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(VirusGeneratorRecipe.Type.INSTANCE, inventory, level);return match.isPresent() && canInsertAmountIntoOutputSlot(inventory)&& canInsertItemIntoOutputSlot(inventory, match.get().getResultItem())&& hasFuelSlot(entity); // && has0Slot(entity) && has1Slot(entity);// boolean canUse = has0Slot(entity) && hasFuelSlot(entity) && has1Slot(entity);// if(canUse) entity.blockState = entity.blockState.setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(true));// else entity.blockState = entity.blockState.setValue(VirusGeneratorBlock.LIT, Boolean.valueOf(false));// return canUse;}// private static boolean has0Slot(VirusGeneratorBlockEntity entity) {// return entity.itemHandler.getStackInSlot(0).getItem() == Items.ROTTEN_FLESH;// }// private static boolean has1Slot(VirusGeneratorBlockEntity entity) {// return entity.itemHandler.getStackInSlot(1).getItem() == ItemInit.LYEYE.get();// }//你的燃料槽private static boolean hasFuelSlot(VirusGeneratorBlockEntity entity) {return entity.itemHandler.getStackInSlot(2).getItem() == ItemInit.BLACKSHEEP.get()|| entity.itemHandler.getStackInSlot(2).getItem() == Items.FERMENTED_SPIDER_EYE;}//检查物品槽是否放了原料private static void craftItem(VirusGeneratorBlockEntity entity) {Level level = entity.level;SimpleContainer inventory = new SimpleContainer(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(VirusGeneratorRecipe.Type.INSTANCE, inventory, level);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));//entity.itemHandler.setStackInSlot(3, new ItemStack(ItemInit.HUMUS.get(),//entity.itemHandler.getStackInSlot(3).getCount() + 1));entity.resetProgress();}}private void resetProgress() {this.progress = 0;}//我们设定了3号槽是产物槽private static boolean canInsertItemIntoOutputSlot(SimpleContainer inventory, ItemStack output) {return inventory.getItem(3).getItem() == output.getItem() || inventory.getItem(3).isEmpty();}private static boolean canInsertAmountIntoOutputSlot(SimpleContainer inventory) {return inventory.getItem(3).getMaxStackSize() > inventory.getItem(3).getCount();}private static boolean notReachLimit(VirusGeneratorBlockEntity entity) {return entity.itemHandler.getStackInSlot(3).getCount()<64;}// @Override// public BlockState getBlockState() {// return this.blockState;//}}

在init包中新建一个BlockEntityInit类,注册我们模组中所有的方块实体:

BlockEntityInit.java

package com.joy187.re8joymod.init;import com.joy187.re8joymod.Main;import com.joy187.re8joymod.blocks.virusgenerator.VirusGeneratorBlockEntity;import net.minecraft.world.level.block.entity.BlockEntityType;import net.minecraftforge.eventbus.api.IEventBus;import net.minecraftforge.registries.DeferredRegister;import net.minecraftforge.registries.ForgeRegistries;import net.minecraftforge.registries.RegistryObject;public class BlockEntityInit {public static final DeferredRegister<BlockEntityType<?>> BLOCK_ENTITIES =DeferredRegister.create(ForgeRegistries.BLOCK_ENTITIES, Main.MOD_ID);public static final RegistryObject<BlockEntityType<VirusGeneratorBlockEntity>> VIRUS_GENERATOR_BLOCK_ENTITY =BLOCK_ENTITIES.register("virus_generator_block_entity", () ->BlockEntityType.Builder.of(VirusGeneratorBlockEntity::new,BlockInit.VIRUS_GENERATOR_BLOCK.get()).build(null));// public static final RegistryObject<BlockEntityType<GeneratorBlockEntity>> GENERATOR_BLOCK_ENTITY =// BLOCK_ENTITIES.register("generator_block_entity", () ->//BlockEntityType.Builder.of(GeneratorBlockEntity::new,// BlockInit.GENERATOR_BLOCK.get()).build(null)); public static void register(IEventBus eventBus) {BLOCK_ENTITIES.register(eventBus);}}

在我们的项目主类中的Main函数中将BlockEntityInit类进行注册:

public Main() {IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();ItemInit.ITEMS.register(bus);BlockInit.BLOCKS.register(bus);EntityInit.ENTITY_TYPES.register(bus);EffectInit.EFFECTS.register(bus);PotionInit.POTIONS.register(bus);SoundInit.SOUNDS.register(bus);//添加这个BlockEntityInit.register(bus);MinecraftForge.EVENT_BUS.register(this);}

3.在virusgenerator包中新建一个我们的配方类VirusGeneratorRecipe:

VirusGeneratorRecipe.java

package com.joy187.re8joymod.blocks.virusgenerator;import com.google.gson.JsonArray;import com.google.gson.JsonObject;import com.joy187.re8joymod.Main;import com.joy187.re8joymod.init.BlockInit;import com.joy187.re8joymod.init.ItemInit;import net.minecraft.core.NonNullList;import work.FriendlyByteBuf;import net.minecraft.resources.ResourceLocation;import net.minecraft.util.GsonHelper;import net.minecraft.world.SimpleContainer;import net.minecraft.world.item.ItemStack;import net.minecraft.world.item.Items;import net.minecraft.world.item.crafting.*;import net.minecraft.world.level.Level;import net.minecraft.world.level.block.Blocks;import mon.collect.HashBasedTable;import mon.collect.Maps;import mon.collect.Table;import java.util.Map;import java.util.Map.Entry;import javax.annotation.Nullable;public class VirusGeneratorRecipe implements Recipe<SimpleContainer> {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;}@Overridepublic boolean matches(SimpleContainer pContainer, Level pLevel) {return recipeItems.get(0).test(pContainer.getItem(1))&& recipeItems.get(1).test(pContainer.getItem(0));}@Overridepublic NonNullList<Ingredient> getIngredients() {return recipeItems;}@Overridepublic ItemStack assemble(SimpleContainer pContainer) {return output;}@Overridepublic boolean canCraftInDimensions(int pWidth, int pHeight) {return true;}@Overridepublic ItemStack getResultItem() {return output.copy();}@Overridepublic ResourceLocation getId() {return id;}@Overridepublic RecipeSerializer<?> getSerializer() {return Serializer.INSTANCE;}@Overridepublic RecipeType<?> getType() {return Type.INSTANCE;}public static class Type implements RecipeType<VirusGeneratorRecipe> {private Type() { }public static final Type INSTANCE = new Type();//这个就是我们之后的配方类的字段public static final String ID = "virus_generator";}public static class Serializer implements RecipeSerializer<VirusGeneratorRecipe> {public static final Serializer INSTANCE = new Serializer();public static final ResourceLocation ID = new ResourceLocation(Main.MOD_ID,"virus_generator");@Overridepublic VirusGeneratorRecipe fromJson(ResourceLocation id, JsonObject json) {ItemStack output = ShapedRecipe.itemStackFromJson(GsonHelper.getAsJsonObject(json, "output"));JsonArray ingredients = GsonHelper.getAsJsonArray(json, "ingredients");//这里说明一共有几个原料,我们需要2个,就写2,需要3个,就改成3NonNullList<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);}@Overridepublic VirusGeneratorRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf 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);}@Overridepublic void toNetwork(FriendlyByteBuf buf, VirusGeneratorRecipe recipe) {buf.writeInt(recipe.getIngredients().size());for (Ingredient ing : recipe.getIngredients()) {ing.toNetwork(buf);}buf.writeItemStack(recipe.getResultItem(), false);}@Overridepublic RecipeSerializer<?> setRegistryName(ResourceLocation name) {return INSTANCE;}@Nullable@Overridepublic ResourceLocation getRegistryName() {return ID;}@Overridepublic Class<RecipeSerializer<?>> getRegistryType() {return Serializer.castClass(RecipeSerializer.class);}@SuppressWarnings("unchecked") // Need this wrapper, because genericsprivate static <G> Class<G> castClass(Class<?> cls) {return (Class<G>)cls;}}}

4.方块和实体的代码部分结束,进入到GUI的制作环节。在Java包中新建一个screen包 -> screen包中新建VirusGeneratorScreen类指明我们GUI贴图存放的位置:

VirusGeneratorScreen.java

package com.joy187.re8joymod.screen;import com.joy187.re8joymod.Main;import com.mojang.blaze3d.systems.RenderSystem;import com.mojang.blaze3d.vertex.PoseStack;import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;import net.minecraft.client.renderer.GameRenderer;import ponent;import net.minecraft.resources.ResourceLocation;import net.minecraft.world.entity.player.Inventory;public class VirusGeneratorScreen extends AbstractContainerScreen<VirusGeneratorMenu> {//指明我们材质的位置private static final ResourceLocation TEXTURE =new ResourceLocation(Main.MOD_ID, "textures/gui/virus_generator.png");public VirusGeneratorScreen(VirusGeneratorMenu pMenu, Inventory pPlayerInventory, Component pTitle) {super(pMenu, pPlayerInventory, pTitle);}@Overrideprotected void renderBg(PoseStack pPoseStack, float pPartialTick, int pMouseX, int pMouseY) {RenderSystem.setShader(GameRenderer::getPositionTexShader);RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);RenderSystem.setShaderTexture(0, TEXTURE);int x = (width - imageWidth) / 2;int y = (height - imageHeight) / 2;this.blit(pPoseStack, x, y, 0, 0, imageWidth, imageHeight);if(menu.isCrafting()) {//blit(pPoseStack, x + 102, y + 41, 176, 0, 8, menu.getScaledProgress());blit(pPoseStack, x + 8, y + 54+12-13, 176, 12-13, 14, menu.getScaledProgress());}}//this.drawTexturedModalRect(this.guiLeft + 8, this.guiTop + 54 + 12 - k, 176, 12 - k, 14, k + 1);@Overridepublic void render(PoseStack pPoseStack, int mouseX, int mouseY, float delta) {renderBackground(pPoseStack);super.render(pPoseStack, mouseX, mouseY, delta);renderTooltip(pPoseStack, mouseX, mouseY);}}

在我们项目主类的clientSetup()函数中将screen时间进行注册:

private void clientSetup(final FMLClientSetupEvent event) {//EntityRenderers.register(EntityInit.DUND1.get(), RenderDund::new);ItemBlockRenderTypes.setRenderLayer(BlockInit.EBONY_LEAVES.get(), RenderType.cutout());ItemBlockRenderTypes.setRenderLayer(BlockInit.HERB_BLOCK.get(), RenderType.cutout());ItemBlockRenderTypes.setRenderLayer(BlockInit.EBONY_SAPLING.get(), RenderType.cutout());//添加这个,第一个参数机器方块的GUI,后面是这个机器方块的screenMenuScreens.register(MenuInit.VIRUS_GENERATOR_MENU.get(), VirusGeneratorScreen::new);}

screen包中新建VirusGeneratorMenu类将所有的槽位的位置都指出来:

VirusGeneratorMenu.java

package com.joy187.re8joymod.screen;import work.FriendlyByteBuf;import net.minecraft.world.entity.player.Inventory;import net.minecraft.world.entity.player.Player;import net.minecraft.world.inventory.*;import net.minecraft.world.item.ItemStack;import net.minecraft.world.level.Level;import net.minecraft.world.level.block.entity.BlockEntity;import net.minecraftforge.items.CapabilityItemHandler;import net.minecraftforge.items.SlotItemHandler;import org.jetbrains.annotations.Nullable;import com.joy187.re8joymod.blocks.virusgenerator.VirusGeneratorBlock;import com.joy187.re8joymod.blocks.virusgenerator.VirusGeneratorBlockEntity;import com.joy187.re8joymod.init.BlockInit;import com.joy187.re8joymod.init.MenuInit;import com.joy187.re8joymod.screen.slot.ModResultSlot;public class VirusGeneratorMenu extends AbstractContainerMenu {private final VirusGeneratorBlockEntity blockEntity;private final Level level;private final ContainerData data;public VirusGeneratorMenu(int pContainerId, Inventory inv, FriendlyByteBuf extraData) {this(pContainerId, inv, inv.player.level.getBlockEntity(extraData.readBlockPos()), new SimpleContainerData(2));}public VirusGeneratorMenu(int pContainerId, Inventory inv, BlockEntity entity, ContainerData data) {super(MenuInit.VIRUS_GENERATOR_MENU.get(), pContainerId);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 -> {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//我们的进度条高13像素int progressArrowSize = 13;return maxProgress != 0 && progress != 0 ? progress * progressArrowSize / maxProgress : 0;}// CREDIT GOES TO: diesieben07 | /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 YOU HAVE TO DEFINE!private static final int TE_INVENTORY_SLOT_COUNT = 4; // must be the number of slots you have!@Overridepublic ItemStack quickMoveStack(Player playerIn, int index) {Slot sourceSlot = slots.get(index);if (sourceSlot == null || !sourceSlot.hasItem()) return ItemStack.EMPTY; //EMPTY_ITEMItemStack sourceStack = sourceSlot.getItem();ItemStack copyOfSourceStack = sourceStack.copy();// Check if the slot clicked is one of the vanilla container slotsif (index < VANILLA_FIRST_SLOT_INDEX + VANILLA_SLOT_COUNT) {// This is a vanilla container slot so merge the stack into the tile inventoryif (!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 inventoryif (!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 nullif (sourceStack.getCount() == 0) {sourceSlot.set(ItemStack.EMPTY);} else {sourceSlot.setChanged();}sourceSlot.onTake(playerIn, sourceStack);return copyOfSourceStack;}@Overridepublic boolean stillValid(Player pPlayer) {return stillValid(ContainerLevelAccess.create(level, blockEntity.getBlockPos()),pPlayer, BlockInit.VIRUS_GENERATOR_BLOCK.get());}//3行物品栏private void addPlayerInventory(Inventory 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));}}}//一行你的个人栏private void addPlayerHotbar(Inventory playerInventory) {for (int i = 0; i < 9; ++i) {this.addSlot(new Slot(playerInventory, i, 8 + i * 18, 142));}}}

我们的槽位对应关系,左上角为坐标原点:

我们13像素的进度条就是用右上角的图案覆盖左下角的图案。

在screen包中新建ModResultSlot类,将我们的产物放置进行预设。

ModResultSlot.java

public class ModResultSlot extends SlotItemHandler {public ModResultSlot(IItemHandler itemHandler, int index, int x, int y) {super(itemHandler, index, x, y);}@Overridepublic boolean mayPlace(ItemStack stack) {return false;}}

5.在init包中新建MenuInit类,将我们第四步中的菜单进行注册:

MenuInit.java

package com.joy187.re8joymod.init;import com.joy187.re8joymod.Main;import com.joy187.re8joymod.screen.VirusGeneratorMenu;import net.minecraft.world.inventory.AbstractContainerMenu;import net.minecraft.world.inventory.MenuType;import mon.extensions.IForgeMenuType;import net.minecraftforge.eventbus.api.IEventBus;import work.IContainerFactory;import net.minecraftforge.registries.DeferredRegister;import net.minecraftforge.registries.ForgeRegistries;import net.minecraftforge.registries.RegistryObject;public class MenuInit {public static final DeferredRegister<MenuType<?>> MENUS =DeferredRegister.create(ForgeRegistries.CONTAINERS, Main.MOD_ID);//注册我们的方块菜单界面public static final RegistryObject<MenuType<VirusGeneratorMenu>> VIRUS_GENERATOR_MENU =registerMenuType(VirusGeneratorMenu::new, "virus_generator_menu");private static <T extends AbstractContainerMenu>RegistryObject<MenuType<T>> registerMenuType(IContainerFactory<T> factory,String name) {return MENUS.register(name, () -> IForgeMenuType.create(factory));}public static void register(IEventBus eventBus) {MENUS.register(eventBus);}}

在我们的项目主类中的Main函数中将MenuInit类进行注册:

public Main() {IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();ItemInit.ITEMS.register(bus);BlockInit.BLOCKS.register(bus);EntityInit.ENTITY_TYPES.register(bus);EffectInit.EFFECTS.register(bus);PotionInit.POTIONS.register(bus);SoundInit.SOUNDS.register(bus);BlockEntityInit.register(bus);//添加这个MenuInit.register(bus);MinecraftForge.EVENT_BUS.register(this);}

6.在init包中新建RecipeInit类,将我们第三步中的配方类进行注册:

RecipeInit.java

package com.joy187.re8joymod.init;import com.joy187.re8joymod.Main;import com.joy187.re8joymod.blocks.virusgenerator.VirusGeneratorRecipe;import net.minecraft.world.item.crafting.RecipeSerializer;import net.minecraftforge.eventbus.api.IEventBus;import net.minecraftforge.registries.DeferredRegister;import net.minecraftforge.registries.ForgeRegistries;import net.minecraftforge.registries.RegistryObject;public class RecipeInit {public static final DeferredRegister<RecipeSerializer<?>> SERIALIZERS =DeferredRegister.create(ForgeRegistries.RECIPE_SERIALIZERS, Main.MOD_ID);public static final RegistryObject<RecipeSerializer<VirusGeneratorRecipe>> VIRUS_GENERATOR_SERIALIZER =SERIALIZERS.register("virus_generator", () -> VirusGeneratorRecipe.Serializer.INSTANCE);public static void register(IEventBus eventBus) {SERIALIZERS.register(eventBus);}}

在我们的项目主类中的Main函数中将RecipeInit类进行注册:

public Main() {IEventBus bus = FMLJavaModLoadingContext.get().getModEventBus();ItemInit.ITEMS.register(bus);BlockInit.BLOCKS.register(bus);EntityInit.ENTITY_TYPES.register(bus);EffectInit.EFFECTS.register(bus);PotionInit.POTIONS.register(bus);SoundInit.SOUNDS.register(bus);BlockEntityInit.register(bus);MenuInit.register(bus);//添加这个RecipeInit.register(bus);MinecraftForge.EVENT_BUS.register(this);}

ClientModEventSubscriber类中添加我们的配方类型的类进行注册

ClientModEventSubscriber.java

@SubscribeEventpublic static void registerRecipeTypes(final RegistryEvent.Register<RecipeSerializer<?>> event) {Registry.register(Registry.RECIPE_TYPE, VirusGeneratorRecipe.Type.ID, VirusGeneratorRecipe.Type.INSTANCE);}

7.代码部分结束,来到资源包制做。在src\main\resources\assets\你的modid\blockstates中新建我们的方块的状态文件:

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}}}

src\main\resources\assets\你的modid\models\block中新建两个我们的方块模型文件:

方块平时的模型

virus_generator.json

{"parent": "block/orientable","textures": {"top": "re8joymod:block/virus_generator_side","front": "re8joymod:block/virus_generator","side": "re8joymod:block/virus_generator_side"}}

方块工作时的模型

virus_generator_on.json

{"parent": "block/orientable","textures": {"top": "re8joymod:block/virus_generator_side","front": "re8joymod:block/virus_generator_on","side": "re8joymod:block/virus_generator_side"}}

models\item中添加我们手拿方块时的模型文件

virus_generator.json

{"parent": "re8joymod:block/virus_generator"}

textures\block中添加我们方块的侧面、正面不工作、正面工作时的贴图:

在textures包中新建gui包 -> gui包中把我们的gui(大小为256×256像素点)放进去:

在lang包中的en_us.json文件中加上我们方块实体的名称和打开机器后上面显示的名称:

"block.re8joymod.virus_generator":"Virus Analyser","container.virus_generator":"Virus Analyser",

8.在src\main\resources\data\你的modid\recipes中新建几个属于我们的方块实体的配方:

记得在第三步中我们把配方类型设置为virus_generator,所以配方的type就写为virus_generator

evirus.json

{"type":"re8joymod:virus_generator","ingredients":[{"item":"re8joymod:humus"},{"item":"re8joymod:herbglass"}],"output":{"item":"re8joymod:evirus"}}

9.保存所有文件 -> 进入游戏调试:

首先拿出我们的机器并放置下来,外观显示正常

将燃料和产物放入,成功产出了产物!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。