Tuesday, September 3, 2013

Forge - Sync Progress Bars

At the time you read this, I'll be thoroughly enjoying myself in a camp in northern Wisconsin.  Enjoy this scheduled post!

Synchronizing GUI progress bars between server and client may seem complicated at first, but it's actually very simple.  If you've set up a GUI renderer and container already, you're ready for this tutorial.

First, make sure the client-side tile entity isn't doing anything with progress bars besides having a variable for it.  Open up the container class and create some variables for the previous state of all the progress bars (like burn time and cooking progress).  Let's use ContainerFurnace to explain stuff.

public void addCraftingToCrafters(ICrafting par1ICrafting)
    {
        super.addCraftingToCrafters(par1ICrafting);
        par1ICrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
        par1ICrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
        par1ICrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
    }

The super call is necessary to sync inventory; the sendProgressBarUpdate calls are more interesting.  This is where the server tells the client what it knows about the GUI.  The numbers (0, 1, 2) are IDs of the progress bars and the final argument is the value of the progress bar as an integer (taken from the represented tile entity).

public void detectAndSendChanges()
    {
        super.detectAndSendChanges();
        for (int i = 0; i < this.crafters.size(); ++i)
        {
            ICrafting icrafting = (ICrafting)this.crafters.get(i);

            if (this.lastCookTime != this.furnace.furnaceCookTime)
            {
                icrafting.sendProgressBarUpdate(this, 0, this.furnace.furnaceCookTime);
            }

            if (this.lastBurnTime != this.furnace.furnaceBurnTime)
            {
                icrafting.sendProgressBarUpdate(this, 1, this.furnace.furnaceBurnTime);
            }

            if (this.lastItemBurnTime != this.furnace.currentItemBurnTime)
            {
                icrafting.sendProgressBarUpdate(this, 2, this.furnace.currentItemBurnTime);
            }
        }
        this.lastCookTime = this.furnace.furnaceCookTime;
        this.lastBurnTime = this.furnace.furnaceBurnTime;
        this.lastItemBurnTime = this.furnace.currentItemBurnTime;

    }

The loop iterates through all the crafters (the players viewing this container) and sends an update on any progress bars that have changed.  The calls are exactly the same as in addCraftingToCrafters.  After informing all the crafters, it updates its cache of the progress bar states from the tile entity.

@SideOnly(Side.CLIENT)
    public void updateProgressBar(int par1, int par2)
    {
        if (par1 == 0)
        {
            this.furnace.furnaceCookTime = par2;
        }
        if (par1 == 1)
        {
            this.furnace.furnaceBurnTime = par2;
        }
        if (par1 == 2)
        {
            this.furnace.currentItemBurnTime = par2;
        }

    }

This is where the client fixes its progress bars.  It receives the ID of the bar to update and the value.  With that, it decides which tile entity variable to set.

So there you go!  The GUI class does not need to be changed, it will reflect the tile entity's opinion on the progress bars, which is now in sync with the server.

No comments:

Post a Comment