Jump to content

[1.10.2] [SOLVED] Waila Support with Forge Energy Capabilities


Bektor

Recommended Posts

Hi,

 

I'm currently having the problem that my solar panels show with Waila how many Forge Energy is stored in them, but they only update

the value when you right click on the solar panel and open the GUI.

 

@Optional.Interface(iface = "mcp.mobius.waila.api.IWailaDataProvider", modid = Constants.MODID_WAILA)
public class WailaCompat implements IWailaDataProvider {
    
    public static final WailaCompat INSTANCE = new WailaCompat();
    
    public static void load(IWailaRegistrar registrar) {
        registrar.registerBodyProvider(INSTANCE, TileEntityEnergy.class);
        registrar.registerNBTProvider(INSTANCE, TileEntityEnergy.class);
    }

    @Override
    @Nullable
    public ItemStack getWailaStack(IWailaDataAccessor accessor, IWailaConfigHandler config) {
        return null;
    }

    @Override
    @Nullable
    public List<String> getWailaHead(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor,
            IWailaConfigHandler config) {
        return currenttip;
    }

    @Override
    @Nullable
    public List<String> getWailaBody(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor,
            IWailaConfigHandler config) {
        
        TileEntity tile = accessor.getTileEntity();
        
        if(tile instanceof TileEntityEnergy) {
            TileEntityEnergy tileEnergy = (TileEntityEnergy) tile;
            
            if(tileEnergy.container != null) {
                if(currenttip.size() > 4)
                    currenttip.add("");
                
                int stored = tileEnergy.container.getEnergyStored();
                int max = tileEnergy.container.getMaxEnergyStored();
                
                currenttip.add(String.format("%s%s%s / %s%s%s %s", TextFormatting.WHITE, stored, TextFormatting.RESET,
                        TextFormatting.WHITE, max, TextFormatting.RESET, ModConfig.ENERGY_NAME));
            }
        }
        
        return currenttip;
    }

    @Override
    @Nullable
    public List<String> getWailaTail(ItemStack itemStack, List<String> currenttip, IWailaDataAccessor accessor,
            IWailaConfigHandler config) {
        return currenttip;
    }

    @Override
    @Nullable
    public NBTTagCompound getNBTData(EntityPlayerMP player, TileEntity te, NBTTagCompound tag, World world,
            BlockPos pos) {
        return tag;
    }
}

 

So, how can I fix this problem?

Just to note, the container of my TileEntityEnergy is the EnergyManager which stores all the energy and provides methods for extracting and receiving energy while also supporting other Energy systems like Tesla and handling the transition between them.

 

Thx in advance.

Bektor

Edited by Bektor

Developer of Primeval Forest.

Link to comment
Share on other sites

If I were to guess I'd say it's a syncing issue. Are you by chance syncing up your server and client tileentity the moment you open the gui / right click the block? In any case I would like to see the block and tileentity classes (:

Link to comment
Share on other sites

14 minutes ago, tommyte said:

If I were to guess I'd say it's a syncing issue. Are you by chance syncing up your server and client tileentity the moment you open the gui / right click the block? In any case I would like to see the block and tileentity classes (:

Spoiler

public class TileEntitySolarPanel extends TileEntityEnergy {
    
    private int inputRate;
    private boolean twoTick = false;
    
    public TileEntitySolarPanel() {
        super(250, 10);
        this.getEnergyManager().setTransferMode(EnergyTransfer.PRODUCER);
    }
    
    @Override
    public void update() {
        boolean flag = false;
        
        if(!this.hasWorld() || this.getWorld().isRemote)
            return;
        
        this.twoTick = !this.twoTick;
        this.inputRate = 10;
        
        this.container.receiveEnergy(this.inputRate, false);
        
        if(this.world.getTileEntity(this.getPos().down()) != null)
            EnergyUtils.sendEnergy(this, this.world.getTileEntity(this.getPos().down()), EnumFacing.DOWN, 10);
        
        if(flag)
            this.markDirty();
    }
    
    @Override
    public SPacketUpdateTileEntity getUpdatePacket() {
        return super.getUpdatePacket();
    }
    
    @Override
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
        super.onDataPacket(net, pkt);
        this.readFromNBT(pkt.getNbtCompound());
    }
    
    public int getField(int id) {
        if(id == 0) return this.container.getEnergyStored();
        else if(id == 1) return this.inputRate;
        else return 0;
    }
    
    public void setField(int id, int value) {
        if(id == 0) this.container.setEnergyStored(value);
        else if(id == 1) this.inputRate = value;
    }
    
    public boolean isUsableByPlayer(EntityPlayer player) {
        return this.getWorld().getTileEntity(this.getPos()) != this ? false : 
                        player.getDistanceSq((double)this.getPos().getX() + .5d, 
                        (double)this.getPos().getY() + .5d, 
                        (double)this.getPos().getZ() + .5d) <= 64.d;
    }
}

 

Thats the basic tile entity class, the block class does actually nothing, except for creating the tile entity.

 

And here are the main methods of the TileEntityEnergy. There are some other methods, but they are not important as they are

mostly getters etc.

Spoiler

    public final EnergyManager container;

    @Override
    public void readFromNBT(NBTTagCompound compound) {
        super.readFromNBT(compound);
        this.container.deserializeNBT(compound.getCompoundTag("Energy"));
    }
    
    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound compound) {
        compound.setTag("Energy", this.container.serializeNBT());
        return super.writeToNBT(compound);
    }
    
    @Override
    public <T> T getCapability(Capability<T> capability, @Nullable EnumFacing facing) {
        T cap = this.container.getCapability(capability, facing);
        
        return cap != null ? cap : super.getCapability(capability, facing); 
    }
    
    @Override
    public boolean hasCapability(Capability<?> capability, @Nullable EnumFacing facing) {
        return this.container.hasCapability(capability, facing) || 
                super.hasCapability(capability, facing);
    }

 

 

Developer of Primeval Forest.

Link to comment
Share on other sites

I can't find any networking here. I'd really like to see where you are syncing up your client side with your server side. 

 

4 minutes ago, Bektor said:

if(!this.hasWorld() || this.getWorld().isRemote) return;

 

You are, logically, only changing the amount of energy stored on server side, so the client side, what waila is displaying (I think), doesn't know of any changes in the amount of energy stored until you send a packet there ;)

Link to comment
Share on other sites

32 minutes ago, tommyte said:

I can't find any networking here. I'd really like to see where you are syncing up your client side with your server side. 

 

 

You are, logically, only changing the amount of energy stored on server side, so the client side, what waila is displaying (I think), doesn't know of any changes in the amount of energy stored until you send a packet there ;)

The only other stuff there is is the Container for the GUI:

public class ContainerSolarPanel extends Container {
	
	private int energyStored;
	private int productionAmount;
	private TileEntitySolarPanel panel;
	
	public ContainerSolarPanel(InventoryPlayer playerInv, TileEntitySolarPanel panel) {
		this.panel = panel;
		
		for(int y = 0; y < 3; ++y)
			for(int x = 0; x < 9; ++x)
				this.addSlotToContainer(new Slot(playerInv, x + y * 9 + 9, 8 + x * 18, 84 + y * 18));
		
		for(int x = 0; x < 9; ++x)
			this.addSlotToContainer(new Slot(playerInv, x, 8 + x * 18, 142));
	}
	
	@Override
	public void detectAndSendChanges() {
		super.detectAndSendChanges();
		
		for(int i = 0; i < this.listeners.size(); i++) {
			IContainerListener listener = (IContainerListener) this.listeners.get(i);
			
			if(this.energyStored != this.panel.getField(0))
				listener.sendProgressBarUpdate(this, 0, this.panel.getField(0));
			if(this.productionAmount != this.panel.getField(1))
				listener.sendProgressBarUpdate(this, 1, this.panel.getField(1));
		}
		
		this.energyStored = this.panel.getField(0);
		this.productionAmount = this.panel.getField(1);
	}
	
	@Override
	@SideOnly(Side.CLIENT)
	public void updateProgressBar(int id, int data) {
		super.updateProgressBar(id, data);
		this.panel.setField(id, data);
	}
	
    @Override
    public boolean canInteractWith(EntityPlayer playerIn) {
        return this.panel.isUsableByPlayer(playerIn);
    }
}

 

Developer of Primeval Forest.

Link to comment
Share on other sites

WAILA doesn't load the container, so the container's synchronization code doesn't work for displaying information to WAILA, ergo, you are not syncing the information except when the player opens the gui by right clicking the block. 

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

2 minutes ago, Bektor said:

@Override public void detectAndSendChanges()

{

super.detectAndSendChanges();

for(int i = 0; i < this.listeners.size(); i++)

{

IContainerListener listener = (IContainerListener)

this.listeners.get(i);

if(this.energyStored != this.panel.getField(0)) listener.sendProgressBarUpdate(this, 0, this.panel.getField(0));

if(this.productionAmount != this.panel.getField(1)) listener.sendProgressBarUpdate(this, 1, this.panel.getField(1));

}

this.energyStored = this.panel.getField(0);

this.productionAmount = this.panel.getField(1);

}

There you go :) This method, as the name implies detects and sends changes (on server side) and sends them to the client. This then only occurs when the container is activated, aka when the player open the gui. You should set up your own networking to sync properly between server and client. Here is an article about in on the docs: https://mcforge.readthedocs.io/en/latest/networking/

 

Read all the articles there about networking and then you should be good to go ;)

Link to comment
Share on other sites

Ok, I just got now my network message done.

But how can I access in the message handler the tile entity to change the energy value on the client?

Just to note, my message only sends a basic integer value.

 

I'm also wondering to which players I should send the message for the best performance.

I also guess I should just send the update every time when I call markDirty() in the tile entity itself, am I right?

Edited by Bektor

Developer of Primeval Forest.

Link to comment
Share on other sites

I usually do it like this: 

data.setIntArray("ints", new int[]{pos.getX(), pos.getY(), pos.getZ(), amount});

Here I set an array of integers with the three coords of the tile entity and the number i'd like to transfer. 

 

int[] values = message.data.getIntArray("ints");
final String name = message.data.getString("string");
final BlockPos pos = new BlockPos(values[0], values[1], values[2]);
final int amount = values[3];

Then in the messagehandler I read these values like this.

TileEntity entity = theplayer.getEntityWorld().getTileEntity(pos);
				
if(entity != null && entity.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, null))
{
//here do something like entity.getCapability(etc., etc.).setEnergy(amount);
}

You'd put something like this into your run method.

Link to comment
Share on other sites

1 minute ago, Bektor said:

Hm, how can I get the client world and the client player entitiy from my MessageContext#getClientHandler() as the message gets send to the client from the server.?

You can get the singleplayer player by calling Minecraft.getMinecraft().player. 

Link to comment
Share on other sites

Seriously?

 

Minecraft.getMinecraft().player.getWorld() was too hard?

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

  • Like 1

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

1 minute ago, Bektor said:

And how do I get the world?

player.getEntityWorld(); (or something like that)

 

1 minute ago, Bektor said:

Also, how can I send the new data only to all players currently looking at the block?

you can use this:

PacketDispatcher.sendToAllAround(message, new NetworkRegistry.TargetPoint(dimension, x, y, z, range));

Just set the range to a value that would make sure no one outside it can hover over the block.

Link to comment
Share on other sites

2 minutes ago, Draco18s said:

wow thank you! I actually didn't know this myself (:

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.