Отрисовка значения из тайлентити в GUI

Версия Minecraft
1.10.2

Eifel

Модератор
1,624
79
609
Привет

Появилась такая проблема: у меня есть тайлэнтити, который хранит некий заряд и заряжает предметы. При тесте этого блока на форджевском сервере, значение заряда в гуи у меня хаотично изменяется(от рандомных минусовых до плюсовых, потом обратно по колу), при том что на сервере все нормально. Контейнер вроде настроил нормально, гуи хендлер все дела... В общем не могу найти проблемы, надеюсь на помощь или совет, может кто с этим сталкивался

Коды:
Код:
public class TileEntityUltimateCharger extends TileEntityLockable implements ITickable, ISidedInventory {
 
private static final int[] SLOTS_TOP = new int[] {0, 1, 2, 3, 4};
    private static final int[] SLOTS_BOTTOM = new int[] {0, 1, 2, 3, 4};
    private static final int[] SLOTS_SIDES = new int[] {0, 1, 2, 3, 4};
    
private ItemStack[] inventoryStacks = new ItemStack [6];
    
    private int max_charge = Constants.MAX_CHARGE_ULTIMATE_CHARGER;
    private int curr_charge = 0;
    
    private int ticker = 0;

@Override
public void update() {


if(!this.worldObj.isRemote){

this.incrementTicker();

boolean flag = false;

if(this.ticker % 600 == 0 && this.worldObj.canBlockSeeSky(this.pos.up()) && this.worldObj.isRaining() && Utils.getRandom(80)){
NetworkHandler.network.sendToAllAround(new LightningBoltMessage(this.pos.getX(), this.pos.getY(), this.pos.getZ()), new TargetPoint(this.worldObj.provider.getDimension(), (double)this.pos.getX(), (double)this.pos.getY(), (double)this.pos.getZ(), 100));
EntityLightningBolt lightning = new EntityLightningBolt(this.worldObj, this.pos.getX(), this.pos.getY(), this.pos.getZ(), true);
this.worldObj.spawnEntityInWorld(lightning);
this.charge(500000 + 100000 * Utils.getRandom().nextInt(5));
flag = true;
}

System.out.println(this.getCharge());

if(flag){
if(Utils.getRandom(35)){
this.worldObj.spawnEntityInWorld(new EntityItem(this.worldObj, this.pos.getX(), this.pos.getY() + 1, this.pos.getZ(), new ItemStack(ItemRegistry.ItemLightningShard)));
}
}

for(int i = 0; i < 4; i++){
if(this.inventoryStacks[i] != null){
this.chargeItem(this.inventoryStacks[i], 1000);
}
}

if(this.inventoryStacks[4] != null && this.inventoryStacks[5] != null && !this.worldObj.isRemote){
ItemStack upgrade = this.inventoryStacks[4];
ItemStack modifier = this.inventoryStacks[5];
for(int i = 0; i < upgrade.stackSize; i++){
if(modifier.getItem() instanceof IModifiable){
if(upgrade.getItem() instanceof ItemPowerUpgrade && NBTItemProvider.getPower(modifier) < NBTItemProvider.getMaxPower(modifier) && this.curr_charge >= 500000){
upgrade.stackSize--;
this.discharge(500000);
if(upgrade.stackSize <= 0) this.setInventorySlotContents(4, null);
NBTItemProvider.addPower(modifier, 1);
}else
if(upgrade.getItem() instanceof ItemCapacityUpgrade && NBTItemProvider.getMaxCharge(modifier) < 100000000 && this.curr_charge >= 1000000){
upgrade.stackSize--;
this.discharge(1000000);
if(upgrade.stackSize <= 0) this.setInventorySlotContents(4, null);
NBTItemProvider.setMaxCharge(modifier, NBTItemProvider.getMaxCharge(modifier) + 1000000);
}
}
}

}

}

this.markDirty(); 
}

private void updateCharger(){

}

private void incrementTicker(){

this.ticker++;
if(this.ticker >= 240000) ticker = 0;
}

private void charge(int amount){

this.curr_charge += amount;
if(this.curr_charge > this.max_charge)
this.curr_charge = this.max_charge;
}

private void discharge(int amount){

this.curr_charge -= amount;
if(this.curr_charge < 0)
this.curr_charge = 0;

}

public int getCharge(){

return this.curr_charge;
}

private void chargeItem(ItemStack stack, int transfer){

int charge = NBTItemProvider.getMaxCharge(stack) - NBTItemProvider.getCharge(stack);
if(charge == 0) return;

if(transfer > charge){
if(charge <= this.curr_charge){
NBTItemProvider.charge(stack, charge);
this.discharge(charge);
}
}else if(transfer <= this.curr_charge){
NBTItemProvider.charge(stack, transfer);
this.discharge(transfer);
}
}

@Override
    public void readFromNBT(NBTTagCompound compound){
    
    super.readFromNBT(compound);
        NBTTagList nbttaglist = compound.getTagList("Items", 10);
        this.inventoryStacks = new ItemStack[this.getSizeInventory()];

        for (int i = 0; i < nbttaglist.tagCount(); ++i){
            NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i);
            int j = nbttagcompound.getByte("Slot");

            if (j >= 0 && j < this.inventoryStacks.length){
                this.inventoryStacks[j] = ItemStack.loadItemStackFromNBT(nbttagcompound);
            }
        }
        
        this.curr_charge = compound.getInteger("Current_Charge");
        this.max_charge = compound.getInteger("Max_Charge");
        this.ticker = compound.getInteger("Ticker");
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound){
    
    super.writeToNBT(compound);
        NBTTagList nbttaglist = new NBTTagList();
        
        compound.setInteger("Current_Charge", this.curr_charge);
        compound.setInteger("Max_Charge", this.max_charge);
        compound.setInteger("Ticker", this.ticker);

        for (int i = 0; i < this.inventoryStacks.length; ++i){
            if (this.inventoryStacks[i] != null){
                NBTTagCompound nbttagcompound = new NBTTagCompound();
                nbttagcompound.setByte("Slot", (byte)i);
                this.inventoryStacks[i].writeToNBT(nbttagcompound);
                nbttaglist.appendTag(nbttagcompound);
            }
        }

        compound.setTag("Items", nbttaglist);
              
        return compound;
    }
    
@Override
public int[] getSlotsForFace(EnumFacing side) {

return side == EnumFacing.DOWN ? SLOTS_BOTTOM : (side == EnumFacing.UP ? SLOTS_TOP : SLOTS_SIDES);
}

@Override
public int getField(int id) {

switch (id){
       
         case 0:
             return this.curr_charge;
         case 1:
             return this.max_charge;
         default:
             return 0;
}
}

@Override
public void setField(int id, int value) {

switch (id){
        
        case 0:
            this.curr_charge = value;
            break;
        case 1:
            this.max_charge = value;
}
}

@Override
public int getFieldCount() {

return 2;
}

@Override
public Container createContainer(InventoryPlayer playerInventory, EntityPlayer playerIn) {

 return new ContainerUltimateCharger(playerInventory, this);
}

@Override
public int getSizeInventory() {

return this.inventoryStacks.length;
}

@Override
public ItemStack getStackInSlot(int index) {

 return this.inventoryStacks[index];
}

@Override
public ItemStack decrStackSize(int index, int count) {

return ItemStackHelper.getAndSplit(this.inventoryStacks, index, count);
}

@Override
public ItemStack removeStackFromSlot(int index) {

return ItemStackHelper.getAndRemove(this.inventoryStacks, index);
}

@Override
public void setInventorySlotContents(int index, ItemStack stack) {

boolean flag = stack != null && stack.isItemEqual(this.inventoryStacks[index]) && ItemStack.areItemStackTagsEqual(stack, this.inventoryStacks[index]);
        this.inventoryStacks[index] = stack;

        if (stack != null && stack.stackSize > this.getInventoryStackLimit()){
        
            stack.stackSize = this.getInventoryStackLimit();
        }

        if (index == 0 && !flag){
        
            this.markDirty();
        }
}

@Override
public int getInventoryStackLimit() {

return 64;
}

@Override
public boolean isUseableByPlayer(EntityPlayer player) {

        return this.worldObj.getTileEntity(this.pos) != this ? false : 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) {

if(index == 4 && (stack.getItem() instanceof ItemCapacityUpgrade || stack.getItem() instanceof ItemPowerUpgrade)) return true;
    if(!(stack.getItem() instanceof IModifiable)) return false;
    return true;
}

@Override
public void clear() {

for (int i = 0; i < this.inventoryStacks.length; ++i){
this.inventoryStacks[i] = null;
   }
}

@Override
public String getName() {

return "tileentity.ultimatecharger.name";
}

@Override
public boolean hasCustomName() {

return true;
}



@Override
public String getGuiID() {

return "";
}


@Override
public boolean canInsertItem(int index, ItemStack itemStackIn, EnumFacing direction) {

return this.isItemValidForSlot(index, itemStackIn);
}

@Override
public boolean canExtractItem(int index, ItemStack stack, EnumFacing direction) {

        return true;
}

net.minecraftforge.items.IItemHandler handlerTop = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.UP);
    net.minecraftforge.items.IItemHandler handlerBottom = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.DOWN);
    net.minecraftforge.items.IItemHandler handlerSide = new net.minecraftforge.items.wrapper.SidedInvWrapper(this, net.minecraft.util.EnumFacing.WEST);

    @SuppressWarnings("unchecked")
    @Override
    public <T> T getCapability(net.minecraftforge.common.capabilities.Capability<T> capability, net.minecraft.util.EnumFacing facing){
    
        if (facing != null && capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
            if (facing == EnumFacing.DOWN)
                return (T) handlerBottom;
            else if (facing == EnumFacing.UP)
                return (T) handlerTop;
            else
                return (T) handlerSide;
        return super.getCapability(capability, facing);
    }

}
Код:
public class ContainerUltimateCharger extends Container{
 
    private final IInventory tileUltimateCharger;
    private int curr_charge;
    private int max_charge;


    public ContainerUltimateCharger(InventoryPlayer playerInventory, IInventory chargerInventory){
     
        this.tileUltimateCharger = chargerInventory;

        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 0, 62, 8));//0
 
        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 1, 62, 26));//1

        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 2, 62, 44));//2

        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 3, 62, 62));//3
        
        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 4, 98, 62));//4
        
        this.addSlotToContainer(new SlotStandartCharger(playerInventory.player, chargerInventory, 5, 152, 62));//5
              

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

    public void addListener(IContainerListener listener){
     
        super.addListener(listener);
        listener.sendAllWindowProperties(this, this.tileUltimateCharger);
    }

    public void detectAndSendChanges(){
     
        super.detectAndSendChanges();

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

            if (this.curr_charge != this.tileUltimateCharger.getField(0)){
                icontainerlistener.sendProgressBarUpdate(this, 0, this.tileUltimateCharger.getField(0));
            }

            if (this.max_charge != this.tileUltimateCharger.getField(1)){
             icontainerlistener.sendProgressBarUpdate(this, 1, this.tileUltimateCharger.getField(1));
            }

        }

        this.curr_charge = this.tileUltimateCharger.getField(0);
        this.max_charge = this.tileUltimateCharger.getField(1);
    }

    @SideOnly(Side.CLIENT)
    public void updateProgressBar(int id, int data){
     
        this.tileUltimateCharger.setField(id, data);
    }

    public boolean canInteractWith(EntityPlayer playerIn){
     
        return this.tileUltimateCharger.isUseableByPlayer(playerIn);
    } 

    @Nullable
    public ItemStack transferStackInSlot(EntityPlayer playerIn, int index){
     
     ItemStack itemstack = null;
        Slot slot = (Slot)this.inventorySlots.get(index);

        if (slot != null && slot.getHasStack()){
            ItemStack itemstack1 = slot.getStack();
            itemstack = itemstack1.copy();
                        
            if (index < 6){
       
                if (!this.mergeItemStack(itemstack1, 6, 42, true)){
                    return null;
                }

                slot.onSlotChange(itemstack1, itemstack);
            }
            else if (index != 0 && index != 1 && index != 2 && index != 3 && index != 4 && index != 5){
             
             if (itemstack1.getItem() instanceof IModifiable){
                    if (!this.mergeItemStack(itemstack1, 0, 6, false)){
                        return null;
                    }
                }else if (index >= 6 && index < 33){
                    if (!this.mergeItemStack(itemstack1, 33, 42, false)){
                        return null;
                    }
                }else if (index >= 33 && index < 42 && !this.mergeItemStack(itemstack1, 6, 32, false)){
                    return null;
                }
            }else if (!this.mergeItemStack(itemstack1, 6, 42, false)){
                return null;
            }                  

            if (itemstack1.stackSize == 0){
                slot.putStack((ItemStack)null);
            }
            else{
                slot.onSlotChanged();
            }

            if (itemstack1.stackSize == itemstack.stackSize){
                return null;
            }

            slot.onPickupFromSlot(playerIn, itemstack1);
        }

        return itemstack;
    }
}

Код:
@SideOnly(Side.CLIENT)
public class GuiUltimateCharger extends GuiContainer {
 
    private static final ResourceLocation ULTIMATE_CHARGER_GUI_TEXTURE = new ResourceLocation(Reference.MOD_ID + ":textures/gui/gui_ultimate_charger.png");
    private final InventoryPlayer playerInventory;
    private final IInventory tileUltimateCharger;
    private final EntityPlayer player;
    
 private float oldMouseX;
 private float oldMouseY;

    public GuiUltimateCharger(InventoryPlayer playerInv, IInventory tileInv){
     
        super(new ContainerUltimateCharger(playerInv, tileInv));
        this.playerInventory = playerInv;
        this.tileUltimateCharger = tileInv;
        this.player = playerInv.player;
    }
    
    public void drawScreen(int mouseX, int mouseY, float partialTicks) {
        super.drawScreen(mouseX, mouseY, partialTicks);
        this.oldMouseX = (float)mouseX;
        this.oldMouseY = (float)mouseY;
    }


    protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY){
     
        String s = I18n.format(this.tileUltimateCharger.getDisplayName().getUnformattedText());
        this.fontRendererObj.drawString(s, 38 + this.xSize / 2 - this.fontRendererObj.getStringWidth(s) / 2, 6, 4210752);
        this.fontRendererObj.drawString(this.tileUltimateCharger.getField(0) + "/1B", 96, this.ySize - 118, 4210752);
    }

    protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY){
     
        GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
        this.mc.getTextureManager().bindTexture(ULTIMATE_CHARGER_GUI_TEXTURE);
        int i = (this.width - this.xSize) / 2;
        int j = (this.height - this.ySize) / 2;
        this.drawTexturedModalRect(i, j, 0, 0, this.xSize, this.ySize);
   
        int k = (int)(66.0F * this.getChargeScaled());
        this.drawTexturedModalRect(i + 100, j + 27, 176, 0, k, 14);
        
        drawEntityOnScreen(i + 32, j + 75, 30, (float)(i + 32) - this.oldMouseX, (float)(j + 75 - 30) - this.oldMouseY, this.mc.thePlayer);
        
    }

    private float getChargeScaled(){
     
        return (float)this.tileUltimateCharger.getField(0) / (float)this.tileUltimateCharger.getField(1);
    }
    
    public static void drawEntityOnScreen(int posX, int posY, int scale, float mouseX, float mouseY, EntityLivingBase ent) {
 
    GlStateManager.enableColorMaterial();
    GlStateManager.pushMatrix();
    GlStateManager.translate((float)posX, (float)posY, 50.0F);
    GlStateManager.scale((float)(-scale), (float)scale, (float)scale);
    GlStateManager.rotate(180.0F, 0.0F, 0.0F, 1.0F);
    float f = ent.renderYawOffset;
    float f1 = ent.rotationYaw;
    float f2 = ent.rotationPitch;
    float f3 = ent.prevRotationYawHead;
    float f4 = ent.rotationYawHead;
    GlStateManager.rotate(135.0F, 0.0F, 1.0F, 0.0F);
    RenderHelper.enableStandardItemLighting();
    GlStateManager.rotate(-135.0F, 0.0F, 1.0F, 0.0F);
    GlStateManager.rotate(-((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F, 1.0F, 0.0F, 0.0F);
    ent.renderYawOffset = (float)Math.atan((double)(mouseX / 40.0F)) * 20.0F;
    ent.rotationYaw = (float)Math.atan((double)(mouseX / 40.0F)) * 40.0F;
    ent.rotationPitch = -((float)Math.atan((double)(mouseY / 40.0F))) * 20.0F;
    ent.rotationYawHead = ent.rotationYaw;
    ent.prevRotationYawHead = ent.rotationYaw;
    GlStateManager.translate(0.0F, 0.0F, 0.0F);
    RenderManager rendermanager = Minecraft.getMinecraft().getRenderManager();
    rendermanager.setPlayerViewY(180.0F);
    rendermanager.setRenderShadow(false);
    rendermanager.doRenderEntity(ent, 0.0D, 0.0D, 0.0D, 0.0F, 1.0F, false);
    rendermanager.setRenderShadow(true);
    ent.renderYawOffset = f;
    ent.rotationYaw = f1;
    ent.rotationPitch = f2;
    ent.prevRotationYawHead = f3;
    ent.rotationYawHead = f4;
    GlStateManager.popMatrix();
    RenderHelper.disableStandardItemLighting();
    GlStateManager.disableRescaleNormal();
    GlStateManager.setActiveTexture(OpenGlHelper.lightmapTexUnit);
    GlStateManager.disableTexture2D();
    GlStateManager.setActiveTexture(OpenGlHelper.defaultTexUnit);
 }
}
Код:
public class GuiHandler implements IGuiHandler {
 
 public static final int ENHANCER_GUI_ID = 0;
 public static final int ULTIMATE_CHARGER_GUI_ID = 1;

 @Override
 public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
 
 IEnhancedInventory inv = player.getCapability(EnhancedInventoryProvider.INVENTORY_CAP, null);
 
 if(ID == ENHANCER_GUI_ID) {
 return new ContainerEnhancedInventory(player.inventory, inv.getInventory(), player);
 }else
 if(ID == ULTIMATE_CHARGER_GUI_ID) {
 return new ContainerUltimateCharger(player.inventory, (TileEntityUltimateCharger)world.getTileEntity(new BlockPos(x, y, z)));
 }
 return null;
 }

 @Override
 public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
 
 IEnhancedInventory inv = player.getCapability(EnhancedInventoryProvider.INVENTORY_CAP, null);
 
 if(ID == ENHANCER_GUI_ID) {
 return new GuiEnhancedInventory(player, player.inventory, inv.getInventory());
 }else
 if(ID == ULTIMATE_CHARGER_GUI_ID) {
 return new GuiUltimateCharger(player.inventory, (TileEntityUltimateCharger)world.getTileEntity(new BlockPos(x, y, z)));
 }
 return null;
 }

}

Скрин:
0ZzPrH3.png
Хотя на самом деле там 600к. А когда заряжаю что-то то вообще скачет как сумасшедший, то -10к то +10к и т.д.
 
Решение
Решил проблему. Не пользуюсь контейнером для синхронизации данных, так как у меня инты больше 32к, преобразование их в шорт и вызывало такую хрень. Для чтого чтоб данные отсылались на клиент использую методы:

Код:
private void updateCharger(){//вызов при изменении заряда
 
 this.markDirty(); 
 IBlockState iblockstate = this.worldObj.getBlockState(pos);
        worldObj.notifyBlockUpdate(pos, iblockstate, iblockstate, 3);
 }
 
 @Override
 public SPacketUpdateTileEntity getUpdatePacket() {
     
 NBTTagCompound tag = getUpdateTag();
 return new SPacketUpdateTileEntity(this.pos, this.getBlockMetadata(), tag);
 }

 @Override
 public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
 
 handleUpdateTag(pkt.getNbtCompound())...
3,005
192
592
Если на сервере тот же int через System.out.println - все ок, а на сервере все плохо - то просто нужно обновить тайл на клиенте.


public void markDirtyClient() {
markDirty();
if (getWorld() != null) {
IBlockState state = getWorld().getBlockState(getPos());
getWorld().notifyBlockUpdate(getPos(), state, state, 3);
}
}


И в decrStackSize тоже нужно использовать маркдирти (c) ванильный код.
 

Eifel

Модератор
1,624
79
609
В общем думаю нашел проблему: sendProgressBarUpdate
В описании:
Sends two ints to the client-side Container. Used for furnace burning time, smelting progress, brewing progress, and enchanting level. Normally the first int identifies which variable to update, and the second contains the new value. Both are truncated to shorts in non-local SMP.

Соответственно на клиенте я получал шорт...
 

Eifel

Модератор
1,624
79
609
Решил проблему. Не пользуюсь контейнером для синхронизации данных, так как у меня инты больше 32к, преобразование их в шорт и вызывало такую хрень. Для чтого чтоб данные отсылались на клиент использую методы:

Код:
private void updateCharger(){//вызов при изменении заряда
 
 this.markDirty(); 
 IBlockState iblockstate = this.worldObj.getBlockState(pos);
        worldObj.notifyBlockUpdate(pos, iblockstate, iblockstate, 3);
 }
 
 @Override
 public SPacketUpdateTileEntity getUpdatePacket() {
     
 NBTTagCompound tag = getUpdateTag();
 return new SPacketUpdateTileEntity(this.pos, this.getBlockMetadata(), tag);
 }

 @Override
 public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
 
 handleUpdateTag(pkt.getNbtCompound());
 }
 
 @Override
 public NBTTagCompound getUpdateTag(){
 
 NBTTagCompound tag = new NBTTagCompound();
 writeToNBT(tag);
 return tag;
 }
 
 @Override
 public void handleUpdateTag(NBTTagCompound tag) {
 
    this.readFromNBT(tag);
 }

Спасибо Док`у за помощь
 
Сверху