Отображение прогресса механизма

Версия Minecraft
1.12.2
47
1
Привет всем) Вообщем не могу никак.
Нужно равномерно рисовать прогресс, в зависимости от того, сколько времени работы еще осталось.
У меня простенький механизм с двумя слотами: вход и выход.
Код печки смотрел, но понять, как там это все происходит достаточно сложно.
Тупо скопировать и вставить, конечно, можно, но я хочу разобраться в этом получше.
Может есть у кого хороший подробный пример? Или кто может мне подробно описать метод drawTexturedModalRect в той же печке.

Спасибо!)
 
47
1
Если я правильно понял, то первые два параметра - это координаты места, где нужно рисовать, вторая пара - это координаты текстуры, которую нужно рисовать, ну и последние две пары собственно рисуют. Вроде бы так. В любом случае спасибо, буду разбираться.
 
47
1
Еще такой технический вопросик: насколько мне известно, то не всегда нужно перезапускать игру, чтобы принять некоторые изменения в коде? Если да, то что нужно сделать? Просто сохранение не помогает.
 
7,099
324
1,510
В режиме дебага запускай(кнопка с жуком), для применения изменений собирай проект(кнопочка build, в ide с молоточком)
 
47
1
Спасибо) Я почти разобрался. Возникла какая-то странная проблема: мне для того чтобы реализовать формулу, которуб мне описал выше
Agravaine , нужно передавать в класс гуи максимальное время работы. Я делаю это на примере, как в печке. Но почему-то именно это поле передается некорректно. Но в самом тайле все хорошо. На скриншоте в консоли можно заметить, что максимум в гуи почему-то начинает тикать с нуля, как и текущее время работы. Так не должно быть.Без имени-1.jpg

Код:
public class TileEntitySpoilMachine extends TileEntityLockable implements ITickable, ISidedInventory{

    private NonNullList<ItemStack> machineStacks = NonNullList.<ItemStack>withSize(2, ItemStack.EMPTY);
    
    private int workTime;
    private int currentSpoilTime;
    private int spoilTime;
    private int totalSpoilTime;
    
    private String customName;
    
    @Override
    public int getSizeInventory() {
        return 2;
    }
    @Override
    public boolean isEmpty() {
        for (ItemStack itemstack : this.machineStacks)
        {
            if (!itemstack.isEmpty())
            {
                return false;
            }
        }

        return true;
    }
    @Override
    public ItemStack getStackInSlot(int index) {
        return this.machineStacks.get(index);
    }
    @Override
    public ItemStack decrStackSize(int index, int count) {
        return ItemStackHelper.getAndSplit(this.machineStacks, index, count);
    }
    @Override
    public ItemStack removeStackFromSlot(int index) {
        return ItemStackHelper.getAndRemove(this.machineStacks, index);
    }
    @Override
    public void setInventorySlotContents(int index, ItemStack stack) {
        ItemStack itemstack = this.machineStacks.get(index);
        boolean flag = !stack.isEmpty() && stack.isItemEqual(itemstack) && ItemStack.areItemStackTagsEqual(stack, itemstack);
        this.machineStacks.set(index, stack);

        if (stack.getCount() > this.getInventoryStackLimit())
        {
            stack.setCount(this.getInventoryStackLimit());
            this.totalSpoilTime = this.getSpoilTime(stack);
        }
    }
    @Override
    public int getInventoryStackLimit() {
        return 64;
    }
    @Override
    public boolean isUsableByPlayer(EntityPlayer player) {
        if (this.world.getTileEntity(this.pos) != this)
        {
            return false;
        }
        else
        {
            return player.getDistanceSq((double)this.pos.getX() + 0.5D, (double)this.pos.getY() + 0.5D, (double)this.pos.getZ() + 0.5D) <= 64.0D;
        }
    }
    
    @Override
    public void openInventory(EntityPlayer player) {
        
    }
    @Override
    public void closeInventory(EntityPlayer player) {
        
    }
    @Override
    public boolean isItemValidForSlot(int index, ItemStack stack) {
        return false;
    }
    @Override
    public int getField(int id) {
        switch (id)
        {
            case 0:
                return this.workTime;
            case 1:
                return this.currentSpoilTime;
            case 2:
                return this.spoilTime;
            case 3:
                return this.totalSpoilTime;
            default:
                return 0;
        }
    }
    @Override
    public void setField(int id, int value) {
        switch (id)
        {
            case 0:
                this.workTime=value;
            case 1:
                this.currentSpoilTime=value;
            case 2:
                this.spoilTime=value;
            case 3:
                this.totalSpoilTime=value;
            default:
        }       
    }
    @Override
    public int getFieldCount() {
        return 4;
    }
    @Override
    public void clear() {
        this.machineStacks.clear();       
    }
    @Override
    public String getName() {
        return null;
    }
    
    public void setCustomInventoryName(String name)
    {
        this.customName = name;
    }
    
    @Override
    public boolean hasCustomName() {
        return this.customName != null && !this.customName.isEmpty();
    }
    @Override
    public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn) {
        return new ContainerSpoilMachine(playerInventory, this);
    }
    @Override
    public String getGuiID() {
        return "expproject:spoilmachgui";
    }
    
    public boolean isWorking()
    {
        return this.workTime > 0;
    }
    
    
    @Override
    public void update()
    {       
        if (!this.world.isRemote)
        {
            ItemStack itemstack= this.getStackInSlot(0);
            ItemStack currentOut = this.getStackInSlot(1);   
            
            if(this.isWorking())
            {
                this.workTime--;
                if (!itemstack.isEmpty())
                {
                    this.currentSpoilTime++;
                    System.out.println("[В тайле механизма]Текущее = " + this.getField(1) + " Максимум = " + this.getField(3));
                if(this.currentSpoilTime == this.totalSpoilTime)
                {
                    
                    this.totalSpoilTime = this.getSpoilTime(this.machineStacks.get(0));
                    this.spoilItem();       
                    this.workTime = 0;
                    this.currentSpoilTime = 0;
                }
                }
                else
                {
                    this.workTime=0;
                    this.currentSpoilTime = 0;
                }
            }
            if(!this.isWorking() && !itemstack.isEmpty())
            {
                if(this.isItemCanSpoiled(itemstack) && currentOut.getCount()<currentOut.getMaxStackSize() && (currentOut.getItem().equals(Items.ROTTEN_FLESH) || currentOut.isEmpty()))
                {
                    this.workTime = this.getSpoilTime(itemstack);
                    this.currentSpoilTime=0;
                    this.totalSpoilTime=this.workTime;
                }
            }
            
            SpoilMachine.setState(this.isWorking(), this.world, this.pos);
        }
        
    }
    
    private void spoilItem()
    {
        if (this.isItemCanSpoiled(this.machineStacks.get(0)))
        {
            ItemStack input = this.machineStacks.get(0);
            ItemStack out = new ItemStack(Items.ROTTEN_FLESH);
            ItemStack currentOut = this.machineStacks.get(1);
            
            if (currentOut.isEmpty())
            {
                this.machineStacks.set(1, out.copy());
                input.shrink(1);
                return;
            }
            else if (currentOut.getItem().equals(out.getItem()) && currentOut.getCount()<currentOut.getMaxStackSize())
            {
                currentOut.grow(out.getCount());
                input.shrink(1);
                return;
            }
            
        }
    }
    
    @Override
    public void readFromNBT(NBTTagCompound compound)
    {
        super.readFromNBT(compound);
        this.machineStacks = NonNullList.<ItemStack>withSize(this.getSizeInventory(), ItemStack.EMPTY);
        ItemStackHelper.loadAllItems(compound, this.machineStacks);
        this.workTime = compound.getInteger("WorkTime");
        this.spoilTime = compound.getInteger("SpoilTime");
        this.totalSpoilTime = compound.getInteger("TotalSpoilTotal");
        this.currentSpoilTime = compound.getInteger("CurrentSpoilTime");
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound)
    {
        super.writeToNBT(compound);
        compound.setInteger("WorkTime", (short)this.workTime);
        compound.setInteger("SpoilTime", (short)this.spoilTime);
        compound.setInteger("TotalSpoilTotal", (short)this.totalSpoilTime);
        ItemStackHelper.saveAllItems(compound, this.machineStacks);

        return compound;
    }
    
    @Override
    public int[] getSlotsForFace(EnumFacing side) {
        return null;
    }
    @Override
    public boolean canInsertItem(int index, ItemStack itemStackIn, EnumFacing direction)
    {
        return false;
    }
    @Override
    public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction)
    {
        return true;
    }
    @SideOnly(Side.CLIENT)
    public static boolean isWorking1(IInventory inv) {
        return inv.getField(0) > 0;
    }
    
    public static boolean isItemCanSpoiled(ItemStack itemstack1)
    {
        if(!itemstack1.isEmpty())
        {
            if(itemstack1.getItem() instanceof ItemFood) return true;
        }   
        return false;
    }
    
    public static int getSpoilTime(ItemStack itemstack1)
    {
        if(!itemstack1.isEmpty())
        {
            if(itemstack1.getItem().equals(Items.APPLE)) return 120;
            if(itemstack1.getItem() instanceof ItemFood)
            {
                ItemFood food = (ItemFood) itemstack1.getItem();
                
                int t=20;
                
                if(food.getHealAmount(itemstack1)<=2.0F)
                {
                    return 8*t;
                }
                if(food.getHealAmount(itemstack1)<=4.0F)
                {
                    return 12*t;
                }
                if(food.getHealAmount(itemstack1)<=6.0F)
                {
                    return 16*t;
                }
                if(food.getHealAmount(itemstack1)>6.0F)
                {
                    return 20*t;
                }
            }
        }
        return 0;       
    }
    
}

Код:
public class GuiSpoilMachine extends GuiContainer
{
    
    private static final ResourceLocation SPOIL_MACHINE_GUI_TEXTURES = new ResourceLocation(ExperimentalProject.MODID, "textures/gui/gui_spoil_machine.png");
    private final InventoryPlayer playerInv;
    private final TileEntitySpoilMachine tileentity;
    private float oldMouseX;
    private float oldMouseY;
    
    public GuiSpoilMachine(InventoryPlayer playerInv, TileEntitySpoilMachine tileentity)
     {
        super(new ContainerSpoilMachine(playerInv, tileentity));
        this.playerInv = playerInv;
        this.tileentity = tileentity;               
    }
    
    @Override
    public void drawScreen(int mouseX, int mouseY, float partialTicks)
    {
        this.drawDefaultBackground();
        super.drawScreen(mouseX, mouseY, partialTicks);
        this.renderHoveredToolTip(mouseX, mouseY);
    }
    
    @Override
    protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY)
    {
        this.fontRenderer.drawString("Food Disposer", this.xSize / 2 - this.fontRenderer.getStringWidth("Food Disposer") / 2, 6, 4210752);
        this.fontRenderer.drawString(this.playerInv.getDisplayName().getUnformattedText(), 8, this.ySize - 96 + 2, 4210752);
    }
    
    @Override
    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY)
    {
        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
        this.mc.getTextureManager().bindTexture(SPOIL_MACHINE_GUI_TEXTURES);       
        
        int i = (this.width - this.xSize) / 2;
        int j = (this.height - this.ySize) / 2;
        
        this.drawTexturedModalRect(i, j, 0, 0, this.xSize, this.ySize);       
        
        if (TileEntitySpoilMachine.isWorking1(this.tileentity))
        {         
            int k = this.getWorkLeftScaled(13);
        
            if(k>0) this.drawTexturedModalRect(i + 56, j + 37 + 13-k, 176, 13-k, 14, k+1);           
        }   
        
      
    }
    
    private int getWorkLeftScaled(int pixels)
    {
        int i = this.tileentity.getField(1); //Поле с текущим временем
        int j = this.tileentity.getField(3); //Поле с максимумом
              
        if (j==0) return 0;
        
        System.out.println("Вывод максимума в Гуи "+j);
        
        return i*pixels/j;
    }   
}
 

timaxa007

Модератор
5,831
409
672
Есть TileEntity и Gui, но нету Container. Возможно ты не добавил нужных методов в твой Container, который есть у печки.
Весь процесс приготовления происходит на серверной стороне, но на клиентской это не происходит, так как:
- между сервером и клиентом могут возникнуть проблемы, такие как лагание и на один или несколько тиков будет отставать.
- на клиенте не обязательно знать, что происходит процесс, особенно когда этот процесс можно только увидеть в GUI. (Если нет, то тут пакеты понадобиться.)
 
47
1
Вот контейнер
Код:
public class ContainerSpoilMachine extends Container
{

    private IInventory tileMachine;
    private int workTime;
    private int currentSpoilTime;
    private int spoilTime;
    private int totalSpoilTime;
    
    public ContainerSpoilMachine(InventoryPlayer playerInventory, IInventory machineInventory)
    {
        this.tileMachine =  machineInventory;
        this.addSlotToContainer(new Slot(machineInventory, 0, 56, 53));
        this.addSlotToContainer(new Slot(machineInventory, 1, 56, 17));

        for (int i = 0; i < 3; ++i)
        {
            for (int j = 0; j < 9; ++j)
            {
                this.addSlotToContainer(new Slot(playerInventory, j + i * 9 + 9, 8 + j * 18, 84 + i * 18));
            }
        }

        for (int k = 0; k < 9; ++k)
        {
            this.addSlotToContainer(new Slot(playerInventory, k, 8 + k * 18, 142));
        }
    }
    
    @Override
    public void addListener(IContainerListener listener)
    {
        super.addListener(listener);
        listener.sendAllWindowProperties(this, this.tileMachine);
    }
    
    @Override
    public void detectAndSendChanges()
    {
       super.detectAndSendChanges();

        for (int i = 0; i < this.listeners.size(); ++i)
        {
            IContainerListener icontainerlistener = this.listeners.get(i);

            if (this.spoilTime != this.tileMachine.getField(2))
            {
                icontainerlistener.sendWindowProperty(this, 2, this.tileMachine.getField(2));
            }

            if (this.workTime != this.tileMachine.getField(0))
            {
                icontainerlistener.sendWindowProperty(this, 0, this.tileMachine.getField(0));
            }

            if (this.currentSpoilTime != this.tileMachine.getField(1))
            {
                icontainerlistener.sendWindowProperty(this, 1, this.tileMachine.getField(1));
            }

            if (this.totalSpoilTime != this.tileMachine.getField(3))
            {
                icontainerlistener.sendWindowProperty(this, 3, this.tileMachine.getField(3));
            }
        }

        this.spoilTime = this.tileMachine.getField(2);
        this.workTime = this.tileMachine.getField(0);
        this.currentSpoilTime = this.tileMachine.getField(1);
        this.totalSpoilTime = this.tileMachine.getField(3);
    }
    
    @SideOnly(Side.CLIENT)
    public void updateProgressBar(int id, int data)
    {
        this.tileMachine.setField(id, data);
    }

    
    @Override
    public boolean canInteractWith(EntityPlayer playerIn) {
        return this.tileMachine.isUsableByPlayer(playerIn);
    }
    
    @Override
    public ItemStack transferStackInSlot(EntityPlayer playerIn, int index)
    {
        ItemStack itemstack = ItemStack.EMPTY;
        Slot slot = this.inventorySlots.get(index);

        if (slot != null && slot.getHasStack())
        {
            ItemStack itemstack1 = slot.getStack();
            itemstack = itemstack1.copy();

            if (index == 1)
            {
                if (!this.mergeItemStack(itemstack1, 2, 38, true))
                {
                    return ItemStack.EMPTY;
                }

                slot.onSlotChange(itemstack1, itemstack);
            }
            else if (index != 0)
            {
                if (TileEntitySpoilMachine.isItemCanSpoiled(itemstack1))
                {
                    if (!this.mergeItemStack(itemstack1, 0, 1, false))
                    {
                        return ItemStack.EMPTY;
                    }
                }
                else if (index >= 2 && index <= 28)
                {
                    if (!this.mergeItemStack(itemstack1, 29, 38, false))
                    {
                        return ItemStack.EMPTY;
                    }
                }
                else if (index >= 29 && index <= 37 && !this.mergeItemStack(itemstack1, 2, 29, false))
                {
                    return ItemStack.EMPTY;
                }
            }
            else if (!this.mergeItemStack(itemstack1, 2, 38, false))
            {
                return ItemStack.EMPTY;
            }

            if (itemstack1.isEmpty())
            {
                slot.putStack(ItemStack.EMPTY);
            }
            else
            {
                slot.onSlotChanged();
            }

            if (itemstack1.getCount() == itemstack.getCount())
            {
                return ItemStack.EMPTY;
            }

            slot.onTake(playerIn, itemstack1);
        }

        return itemstack;
    }
}
 

timaxa007

Модератор
5,831
409
672
7,099
324
1,510
Тайл то с клиентом синхронизируется? Еще можно попробовать вычислять значение прогресса на клиенте параллельно с сервером
 
47
1
Тайл то с клиентом синхронизируется? Еще можно попробовать вычислять значение прогресса на клиенте параллельно с сервером
Походу нет)) Тайл всегда обновляется на сервере, а гуи только тогда, когда я его открываю. Но как это исправить, пока что не могу понять.
 
47
1
Добавил в тайл следующее, но все равно не работает
Java:
@Override
    @Nullable
    public SPacketUpdateTileEntity getUpdatePacket() {

        return new SPacketUpdateTileEntity(this.pos, 3, this.getUpdateTag());
    }

    @Override
    public NBTTagCompound getUpdateTag() {

        return this.writeToNBT(new NBTTagCompound());
    }

    @Override
    public void onDataPacket(NetworkManager networkManager, SPacketUpdateTileEntity packet) {

        super.onDataPacket(networkManager, packet);

        this.handleUpdateTag(packet.getNbtCompound());
    }
 

timaxa007

Модератор
5,831
409
672
Тайл всегда обновляется на сервере, а гуи только тогда, когда я его открываю.
Ну как-бы так и есть. Даже у печи, а когда завершается процесс или начинается процесс - это просто блок меняется.
Но как это исправить, пока что не могу понять.
А зачем? Какие-то переменные участвуют в визуальном изменении твоего блока? То тогда когда у тебя завершается или начинается процесс готовки, то отправляй пакеты об этом.
Добавил в тайл следующее, но все равно не работает
Если это примерно такие-же методы как и на 1.7.10 (просто по другому выглядят), то это обновление будет только когда обновиться чанк, а не каждый тик.
 
7,099
324
1,510
Но как это исправить, пока что не могу понять.
sendUpdates - мне это было норм, т.к. не часто тайл изменялся, а тебе лучше вычислять прогресс на клиенте параллельно с сервером, т.к. он у тебя каждый тик обновляется
 
47
1
Я попробовал так. Но опять ничего. Что-то я уже перестал понимать. Может есть у кого готовый пример, чтобы разобрать.

sendUpdates() вызываю в апдейте тайла.

Java:
@Override
    @Nullable
    public SPacketUpdateTileEntity getUpdatePacket()
    {
        NBTTagCompound nbt = new NBTTagCompound();
        writeToNBT(nbt);
        return new SPacketUpdateTileEntity(this.pos, 3, nbt);
    }

    public void sendUpdates()
    {
        SPacketUpdateTileEntity packet = this.getUpdatePacket();
        if(packet!=null && this.world instanceof WorldServer)
        {
            PlayerChunkMapEntry playerCMP = ((WorldServer) world).getPlayerChunkMap().getEntry(this.pos.getX(), this.pos.getZ());
            if(playerCMP != null) playerCMP.sendPacket(packet);         
        }
    }
 
47
1
Появились признаки правильной работы! Как только я кладу или извлекаю входной стак, выводится верное значение, но потом оно сбрасывается и начинает тикать с единицы. Что-то мне подсказывает, что проблема видимо уже не в пакетах, а в моей криворукости. Сейчас воткнул для работы с пакетами вот это:
Java:
 @Override
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
        super.onDataPacket(net, pkt);
        NBTTagCompound tag = pkt.getNbtCompound();
        this.readFromNBT(tag);
    }
   
    @Override
    public SPacketUpdateTileEntity getUpdatePacket() {
        SPacketUpdateTileEntity packet = super.getUpdatePacket();
        NBTTagCompound tag = new NBTTagCompound();

        this.writeToNBT(tag);

        return new SPacketUpdateTileEntity(this.pos, 3, tag);
    }
Без имени-1.jpg
 
Сверху