- Версия(и) Minecraft
- 1.7.10
Пользовательский блок хранения
Я чувствую, что есть огромная нехватка учебников, которая охватывает это в удобном для чтения формате. Я сам действительно пытался написать свой первый код для блока хранения. После большого количества проб и ошибок, я, наконец, сделал это, и я решил поделиться им, с вами, ребята.
Я сделаю новый блок, он будет иметь те же свойства, что и сундук, за исключением того, что он имеет только 15 слотов. Я буду делиться текстурой графического интерфейса, но я не буду выдавать фактические текстуры блоков, чтобы дать как можно больше места для манёвров/кастомизаций, чтобы вы действительно создали свой собственный блок. Давайте начнем.
Сначала создайте блок. У меня не будет никаких текстур, как я уже говорил, но вы должны поместить свои собственные текстуры в свой проект. Я также добавлю дополнительный код, который я объясню через минуту,
Здесь вы можете увидеть, что я унаследовал
Вы получите несколько ошибок в этом коде, но это потому, что у нас пока нет класса
Большинство этих кодов просто копируются и вставляются из кода ванили с некоторыми изменениями. Я еще не реализовал пользовательские имена инвентаря, которые могут появиться в другом учебнике. На данный момент имя gui всегда будет «container.storage», поэтому вы можете добавить это в свой файл с локализацией.
Теперь давайте начнем возиться с файлами графического интерфейса. Но прежде чем делать графический интерфейс, нам нужен класс для нашего мода для обработки графических интерфейсов, а «Forge» предоставляет интерфейс для так называемого
Это наш класс
Кроме того, обратите внимание, что чем больше графических интерфейсов вы добавляете, вы также не должны забывать их зарегистрировать в своем классе
Теперь, давайте наконец сделаем графический интерфейс нашего блока хранения.
Если вы хотите текстуру графического интерфейса, то вот она:
Теперь давайте сделаем сам контейнер, где он регистрирует слоты графического интерфейса.
Опять же, как обычно, это в основном копия и вставка кода из ванили с изменениями.
Ниже
// Хранение комментариев, где я регистрирую слоты, у меня 5 в широну и 3 в высоту. Если вам нужен другой размер слотов, вы можете изменить числа в цикле
Вот и все готово! Это довольно длинный учебник, так что если кто-то замечает какие-либо неправильные или неполные данные в учебнике, пожалуйста, добавьте свой комментарий ниже!
Я чувствую, что есть огромная нехватка учебников, которая охватывает это в удобном для чтения формате. Я сам действительно пытался написать свой первый код для блока хранения. После большого количества проб и ошибок, я, наконец, сделал это, и я решил поделиться им, с вами, ребята.
Я сделаю новый блок, он будет иметь те же свойства, что и сундук, за исключением того, что он имеет только 15 слотов. Я буду делиться текстурой графического интерфейса, но я не буду выдавать фактические текстуры блоков, чтобы дать как можно больше места для манёвров/кастомизаций, чтобы вы действительно создали свой собственный блок. Давайте начнем.
Сначала создайте блок. У меня не будет никаких текстур, как я уже говорил, но вы должны поместить свои собственные текстуры в свой проект. Я также добавлю дополнительный код, который я объясню через минуту,
Java:
public class BlockStorage extends BlockContainer
{
private static final String name = "storage";
private final Random rand = new Random();
public BlockStorage()
{
super(Material.wood);
GameRegistry.registerBlock(this, name);
setBlockName(name);
setCreativeTab(CreativeTabs.tabDecorations);
}
@Override
public boolean onBlockActivated(World world, int x, int y, int z, EntityPlayer player, int side, float lx, float ly, float lz)
{
if (world.isRemote) return true;
TileEntity te = world.getTileEntity(x, y, z);
if (te != null && te instanceof TileEntityStorage)
{
player.openGui(StorageMod.instance, 0, world, x, y, z);
return true;
}
return false;
}
@Override
public void breakBlock(World world, int x, int y, int z, Block block, int par6)
{
if (world.isRemote) return;
ArrayList drops = new ArrayList();
TileEntity teRaw = world.getTileEntity(x, y, z);
if (teRaw != null && teRaw instanceof TileEntityStorage)
{
TileEntityStorage te = (TileEntityStorage) teRaw;
for (int i = 0; i < te.getSizeInventory(); i++)
{
ItemStack stack = te.getStackInSlot(i);
if (stack != null) drops.add(stack.copy());
}
}
for (int i = 0;i < drops.size();i++)
{
EntityItem item = new EntityItem(world, x + 0.5, y + 0.5, z + 0.5, drops.get(i));
item.setVelocity((rand.nextDouble() - 0.5) * 0.25, rand.nextDouble() * 0.5 * 0.25, (rand.nextDouble() - 0.5) * 0.25);
world.spawnEntityInWorld(item);
}
}
public TileEntity createNewTileEntity(World world, int par2)
{
return new TileEntityStorage();
}
}
Здесь вы можете увидеть, что я унаследовал
BlockContainer
и добавил createNewTileEntity ()
. После этого я создал класс сущности элемента. Я добавил несколько дополнительных методов: onBlockActivated
и breakBlock
.onBlockActivated ()
служит для указания «Minecraft» , что щелкнув правой кнопкой мыши по блоку откроется графический интерфейс, и «активируется» блок. В основном это несколько проверок, а затем, наконец, вызов openGui
. Он имеет несколько параметров, первый экземпляр мод, мой - StorageMod.instance
, это должен быть экземпляр под аннотацией @Mod.Instance
или @Instance
в нашем основном классе мода. Следующий параметр - ноль (zero/0), это ваш идентификатор графического интерфейса. Это зависит от совместимости модификаций, поэтому вам не придется беспокоиться об этом, сталкиваясь с другими модами или ванильным «Minecraft». Это должно быть одинаковым во всех классах графического интерфейса блока, поэтому помните об этом. Или, если хотите, вы можете перечислить его и использовать ordinal ()
для получения целого числа. Но я не буду освещать это в этом уроке.breakBlock ()
дает возможность выбрасывать элементы внутри блока, если вы его сломаете, чтобы не потерять элементы. Это в основном копирование и вставка из кода ванили.Вы получите несколько ошибок в этом коде, но это потому, что у нас пока нет класса
TileEntityStorage
. Теперь пришло время сделать класс Tile Entity
.
Java:
public class TileEntityStorage extends TileEntity implements IInventory
{
private ItemStack[] items = new ItemStack[15];
public int getSizeInventory()
{
return items.length;
}
public ItemStack getStackInSlot(int slot)
{
return items[slot];
}
public ItemStack decrStackSize(int slot, int amount)
{
if (items[slot] != null)
{
ItemStack itemstack;
if (items[slot].stackSize == amount)
{
itemstack = items[slot];
items[slot] = null;
markDirty();
return itemstack;
}
else
{
itemstack = items[slot].splitStack(amount);
if (items[slot].stackSize == 0) items[slot] = null;
markDirty();
return itemstack;
}
}
else
{
return null;
}
}
public ItemStack getStackInSlotOnClosing(int slot)
{
if (items[slot] != null)
{
ItemStack itemstack = items[slot];
items[slot] = null;
return itemstack;
}
else
{
return null;
}
}
public void setInventorySlotContents(int slot, ItemStack stack)
{
items[slot] = stack;
if (stack != null && stack.stackSize > getInventoryStackLimit())
{
stack.stackSize = getInventoryStackLimit();
}
markDirty();
}
public String getInventoryName()
{
return "container.storage";
}
public boolean hasCustomInventoryName()
{
return false;
}
@Override
public void readFromNBT(NBTTagCompound nbt)
{
super.readFromNBT(nbt);
NBTTagList list = nbt.getTagList("Items", Constants.NBT.TAG_COMPOUND);
items = new ItemStack[getSizeInventory()];
for (int i = 0; i < list.tagCount(); ++i) { NBTTagCompound comp = list.getCompoundTagAt(i); int j = comp.getByte("Slot") & 255; if (j >= 0 && j < items.length)
{
items[j] = ItemStack.loadItemStackFromNBT(comp);
}
}
}
@Override
public void writeToNBT(NBTTagCompound nbt)
{
super.writeToNBT(nbt);
NBTTagList list = new NBTTagList();
for (int i = 0; i < items.length; ++i)
{
if (items[i] != null)
{
NBTTagCompound comp = new NBTTagCompound();
comp.setByte("Slot", (byte)i);
items[i].writeToNBT(comp);
list.appendTag(comp);
}
}
nbt.setTag("Items", list);
}
public int getInventoryStackLimit()
{
return 64;
}
public boolean isUseableByPlayer(EntityPlayer player)
{
return worldObj.getTileEntity(xCoord, yCoord, zCoord) != this ? false : player.getDistanceSq((double)xCoord + 0.5D, (double)yCoord + 0.5D, (double)zCoord + 0.5D) <= 64.0D;
}
public void openInventory() {}
public void closeInventory() {}
public boolean isItemValidForSlot(int slot, ItemStack stack)
{
return true;
}
}
Большинство этих кодов просто копируются и вставляются из кода ванили с некоторыми изменениями. Я еще не реализовал пользовательские имена инвентаря, которые могут появиться в другом учебнике. На данный момент имя gui всегда будет «container.storage», поэтому вы можете добавить это в свой файл с локализацией.
Теперь давайте начнем возиться с файлами графического интерфейса. Но прежде чем делать графический интерфейс, нам нужен класс для нашего мода для обработки графических интерфейсов, а «Forge» предоставляет интерфейс для так называемого
IGuiHandler
.
Java:
public class GuiHandler implements IGuiHandler
{
public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{
TileEntity te = world.getTileEntity(x, y, z);
if (te != null)
{
if (ID == 0) //ID графического интерфейса для блока хранения, добавят позже
{
return new ContainerStorage((TileEntityStorage)te, player);
}
}
return null;
}
public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z)
{
TileEntity te = world.getTileEntity(x, y, z);
if (te != null)
{
if (ID == 0) //ID графического интерфейса для блока хранения, добавят позже
{
return new GuiStorage((TileEntityStorage)te, player);
}
}
return null;
}
}
Это наш класс
GuiHandler
. Mы должны зарегистрировать это в своем CommonProxy
с помощью этой строки:
Java:
NetworkRegistry.INSTANCE.registerGuiHandler(StorageMod.instance, new GuiHandler());
Кроме того, обратите внимание, что чем больше графических интерфейсов вы добавляете, вы также не должны забывать их зарегистрировать в своем классе
GuiHandler
с соответствующими идентификаторами графического интерфейса.Теперь, давайте наконец сделаем графический интерфейс нашего блока хранения.
Java:
public class GuiStorage extends GuiContainer
{
private ResourceLocation texture = new ResourceLocation(StorageMod.MODID, "textures/gui/container/storage.png");
private InventoryPlayer inventory;
private TileEntityStorage te;
public GuiStorage(TileEntityStorage te, EntityPlayer player)
{
super(new ContainerStorage(te, player));
inventory = player.inventory;
this.te = te;
}
@Override
protected void drawGuiContainerBackgroundLayer(float par1, int par2, int par3)
{
Minecraft.getMinecraft().renderEngine.bindTexture(texture);
GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
int x = (width - xSize) / 2;
int y = (height - ySize) / 2;
drawTexturedModalRect(x, y, 0, 0, xSize, ySize);
}
@Override
protected void drawGuiContainerForegroundLayer(int par1, int par2)
{
fontRendererObj.drawString(I18n.format(te.getInventoryName()), (xSize / 2) - (fontRendererObj.getStringWidth(I18n.format(te.getInventoryName())) / 2), 6, 4210752, false);
fontRendererObj.drawString(I18n.format(inventory.getInventoryName()), 8, ySize - 96 + 2, 4210752);
}
}
drawGuiContainerBackgroundLayer ()
рисует наш реальный фон, поэтому нужен только один прямоугольник. drawGuiContainerForegroundLayer ()
рисует любые другие вещи, такие как текст. Две строки в этом методе добавляют имя графического интерфейса и "инвентарь" на инвентаре игрока.Если вы хотите текстуру графического интерфейса, то вот она:
Теперь давайте сделаем сам контейнер, где он регистрирует слоты графического интерфейса.
Java:
public class ContainerStorage extends Container
{
private TileEntityStorage te;
private int slotID = 0;
public ContainerStorage(TileEntityStorage te, EntityPlayer player)
{
this.te = te;
//Хранение
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
addSlotToContainer(new Slot(te, slotID++, 44 + j * 18, 17 + i * 18));
}
}
//Инвентарь
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 9; j++)
{
addSlotToContainer(new Slot(player.inventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
}
}
//Хотбар
for (int i = 0; i < 9; i++)
{
addSlotToContainer(new Slot(player.inventory, i, 8 + i * 18, 142));
}
}
@Override
public ItemStack transferStackInSlot(EntityPlayer player, int slotRaw)
{
ItemStack stack = null;
Slot slot = (Slot)inventorySlots.get(slotRaw);
if (slot != null && slot.getHasStack())
{
ItemStack stackInSlot = slot.getStack();
stack = stackInSlot.copy();
if (slotRaw < 3 * 9)
{
if (!mergeItemStack(stackInSlot, 3 * 9, inventorySlots.size(), true))
{
return null;
}
}
else if (!mergeItemStack(stackInSlot, 0, 3 * 9, false))
{
return null;
}
if (stackInSlot.stackSize == 0)
{
slot.putStack((ItemStack)null);
}
else
{
slot.onSlotChanged();
}
}
return stack;
}
@Override
public boolean canInteractWith(EntityPlayer player)
{
return te.isUseableByPlayer(player);
}
}
Опять же, как обычно, это в основном копия и вставка кода из ванили с изменениями.
Ниже
// Хранение комментариев, где я регистрирую слоты, у меня 5 в широну и 3 в высоту. Если вам нужен другой размер слотов, вы можете изменить числа в цикле
for
.Вот и все готово! Это довольно длинный учебник, так что если кто-то замечает какие-либо неправильные или неполные данные в учебнике, пожалуйста, добавьте свой комментарий ниже!