Jump to content

[1.15.2] [Solved] Sync energy level of a TileEntity's EnergyStorage to a GUI


GenElectrovise

Recommended Posts

Solution:

https://www.minecraftforge.net/forum/topic/85900-1152-sync-energy-level-of-a-tileentitys-energystorage-to-a-gui/?do=findComment&comment=405145

(This is just the my final comment with a link to the commit. For the actual infos, you'll have to look through everyone else's comments :))

 

===

 

Pretty common issue, but I can't seem to suss it out.

I have a TileEntity with a custom EnergyStorage implementation (enabling me to change its capacity more easily). I need to be able to display that energy level on a GUI (AltarScreen). Once that data is in the screen, I can display it, so the issue is in getting it there. I have passing the values down from the TileEntity, but when the AltarScreenManager creates the AltarScreen, the current- and maxAmethystFlux are always their default values of 0 and 50.

 

Pretty sure this isn't good practise -- reaching across sides, with the Screen being on the client and the Container on the server -- but either way it doesn't work.

 

I believe I need to be sending packets whenever the stored energy of the AltarTileEntity changes, but I can't work out how to do that. I've put some of the framework down, but how are the messages sent and received? How do I ensure that only the correct AltarScreen receives the data? It wouldn't do for all of the Altars in a world to display the same energy all the time! :) 

 

Here is a link to the altar package of my GitHub repo.

Edited by GenElectrovise
added version

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

Howdy

 

Synchronisation of GUI and TileEntity has some subtleties to be aware of.

 

You might find this example tutorial useful (look at the parts related to trackedInts, used for fuel burn time).

https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe31_inventory_furnace

 

You can use custom packets instead, but it might be easier to use the vanilla synchronisation mechanism, even if your GUI doesn't need to use any item slots.

 

-TGG

Link to comment
Share on other sites

Hi @TheGreyGhost! Yes that's quite helpful, but I've tried implementing it and I'm still getting all defaults on the AltarContainerScreen (renamed from AltarScreen for greater accuracy). I noticed that you're not using capabilities, but that shouldn't affect data synchronisation, should it?

 

The AltarContainer is updating correctly, and also now saving to NBT properly, but, as I said, the AltarScreenContainer continues to default... Any ideas?

 

 

Quote

even if your GUI doesn't need to use any item slots

Btw it has 4 item slots in addition to energy

Edited by GenElectrovise

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

I've fiddled with it a little bit and pushed up to GitHub... Do you know how I would go about receiving a packet in the AltarContainerScreen ? Unlike a Container, it does not appear to have an onPacket method...

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

Hi

Your screen doesn't receive the packet information, the container (on the client side) does.  The ContainerScreen asks the client container for the synchronised information. 

This all happens automatically if you use Slots and trackedInts; if you want to send other information then you need to register a packet-receiving method on the client side which writes the information into the client container.  See SWindowPropertyPacket for how vanilla does it.

 

In your case, it sounds like trackedInts should be fine for what you want to do.

 

>I noticed that you're not using capabilities, but that shouldn't affect data synchronisation, should it?

I haven't used those yet but no I don't think it should affect your screen synchronisation.

 

-TGG

 

 

 

 

 

Link to comment
Share on other sites

Hi @TheGreyGhost!

Sorry for the lengthy reply time! trackedInts haven't worked for me thus far -- an error in my implementation...

After the lack of success with that, I decided to try packets (figured I'd have to learn eventually), but as yet, they too are evading me, this time by showering me in compiler errors... As I register the packet, I get this error on the ::onMessageRecieved and ::encode , though as far as I can see I give the correct args.

Spoiler

The type AltarMessageHandlerOnClient does not define onMessageReceived(MSG, Supplier<NetworkEvent.Context>) that is applicable here

 

The type AltarEnergyUpdateMessageToClient does not define encode(MSG, PacketBuffer) that is applicable here

I tried removing some of the arguments, as I thought they might be inferred from the method reference, but again to no avail.

 

I fiddled around with the ::decode method a bit more, and the error changed to this:

Spoiler

The type of decode(PacketBuffer) from the type AltarEnergyUpdateMessageToClient is AltarEnergyUpdateMessageToClient, this is incompatible with the descriptor's return type: MSG

... which is even more perplexing. As MSG is a generic type specified in the SimpleChannel#register method, I thought perhaps this could be caused by the other compiler errors making the compiler unable to tell if AltarEnergyUpdateMessageToClient is a valid/consistant type?

 

I have been using @Draco18s's reasonable realism repository  for good-practise reference, as well as the forge docs and your MinecraftByExample  section on network messages for reference...

 

Again sorry for the slow reply, but at least I haven't been idle! :) 

Many thanks.

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

howdy

 

Some of your method signatures weren't right and one of your imports (for Supplier) was wrong.

 

The fixed classes (compiles fine now):

 

/**
 * 
 */
package genelectrovise.magiksmostevile.common.network.altar;

import com.google.common.base.Optional;

import genelectrovise.magiksmostevile.common.main.MagiksMostEvile;
import net.minecraft.network.play.server.SWindowPropertyPacket;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;

/**
 * @author GenElectrovise 23 May 2020
 */
public class AltarNetworkingManager {
	public static SimpleChannel channel;
	public static final ResourceLocation channelRL = new ResourceLocation(MagiksMostEvile.MODID, "altar_channel");
	public static final String MESSAGE_PROTOCOL_VERSION = "1.0";

	public static final int ALTAR_ENERGY_TO_SERVER = 35; // a unique ID for this message type. It helps detect errors if you don't use
														// zero!
	public static final int ALTAR_ENERGY_TO_CLIENT = 63;

	@SubscribeEvent
	public static void onCommonSetupEvent(FMLCommonSetupEvent event) {
		channel = NetworkRegistry.newSimpleChannel(channelRL, () -> MESSAGE_PROTOCOL_VERSION, AltarMessageHandlerOnClient::isProtocolAccepted, AltarMessageHandlerOnServer::isProtocolAccepted);

		//channel.registerMessage(ALTAR_ENERGY_TO_SERVER, AltarEnergyUpdateMessageToServer.class, AltarEnergyUpdateMessageToServer::encode, AltarEnergyUpdateMessageToServer::decode, Optional.of(NetworkDirection.PLAY_TO_SERVER));
		channel.registerMessage(ALTAR_ENERGY_TO_CLIENT, AltarEnergyUpdateMessageToClient.class, AltarEnergyUpdateMessageToClient::encode, AltarEnergyUpdateMessageToClient::decode, AltarMessageHandlerOnClient::onMessageReceived);
	}
}

 

/**
 * 
 */
package genelectrovise.magiksmostevile.common.network.altar;

import genelectrovise.magiksmostevile.common.main.MagiksMostEvile;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.fml.network.NetworkEvent;

import java.util.function.Supplier;

/**
 * @author GenElectrovise 24 May 2020
 */
public class AltarMessageHandlerOnClient {

	/**
	 * Called when a message is received of the appropriate type. CALLED BY THE
	 * NETWORK THREAD, NOT THE CLIENT THREAD
	 */
	public static void onMessageReceived(final AltarEnergyUpdateMessageToClient message, Supplier<NetworkEvent.Context> ctxSupplier) {

		MagiksMostEvile.LOGGER.dev("Message recieved on client!");

		ctxSupplier.get().setPacketHandled(true);
		
		if (!message.isValid()) {
			MagiksMostEvile.LOGGER.warn("Invalid message received on client.");
			return;
		}
		
		if (ctxSupplier.get().getDirection().getReceptionSide() != LogicalSide.CLIENT) {
			MagiksMostEvile.LOGGER.warn("Message recieved on incorrect side. (client) ");
		}

		// Creates a new task for the client for next tick
		ctxSupplier.get().enqueueWork(() -> processMessage(message));
	}

	// This message is called from the Client thread.
	private static void processMessage(AltarEnergyUpdateMessageToClient message) {

	}

	public static boolean isProtocolAccepted(String protocolVersion) {
		return AltarNetworkingManager.MESSAGE_PROTOCOL_VERSION.equals(protocolVersion);
	}
}

 

/**
 * 
 */
package genelectrovise.magiksmostevile.common.network.altar;

import genelectrovise.magiksmostevile.common.main.MagiksMostEvile;
import net.minecraft.network.PacketBuffer;

/**
 * This Network Message is sent from the client to the server, to tell it to
 * spawn projectiles at a particular location. Typical usage: PREQUISITES: have
 * previously setup SimpleChannel, registered the message class and the
 * handler.<br>
 * <br>
 *
 * 1) User creates an AltarEnergyUpdateMessageToServer(targetCoordinates) <br>
 * 2) simpleChannel.sendToServer(airstrikeMessageToServer); <br>
 * 3) Forge network code calls message.encode() to copy the message member
 * variables to a PacketBuffer, ready for sending ... bytes are sent over the
 * network and arrive at the server.... <br>
 * 4) Forge network code calls message.decode() to recreate the
 * airstrickeMessageToServer instance by reading from the PacketBuffer into the
 * member variables <br>
 * 5) the handler.onMessage(message) is called to process the message
 * 
 * @author GenElectrovise 24 May 2020
 */
public class AltarEnergyUpdateMessageToClient {

	private static boolean messageIsValid;

	public AltarEnergyUpdateMessageToClient() {
		messageIsValid = true;
	}

	public boolean isMessageValid() {
		return messageIsValid;
	}

	/**
	 * Called by the network code. Used to write the contents of your message member
	 * variables into the ByteBuf, ready for transmission over the network.
	 *
	 * @param buf
	 */
	public void encode(PacketBuffer buf) {
		MagiksMostEvile.LOGGER.dev("Encoding message to client");
		if (!messageIsValid)
			return;
		buf.writeString("example");
	}

	/**
	 * Called by the network code once it has received the message bytes over the
	 * network. Used to read the ByteBuf contents into your member variables
	 *
	 * @param buf
	 */
	public static AltarEnergyUpdateMessageToClient decode(PacketBuffer buf) {
		MagiksMostEvile.LOGGER.dev("Decoding message to client");
		return new AltarEnergyUpdateMessageToClient();
	}

	public String toString() {
		return "AltarEnergyUpdateMessageToClient{TODO toString}";
	}

	public boolean isValid() {
		return messageIsValid;
	}
}

 

Cheers

  -TGG

Link to comment
Share on other sites

Btw the only thing my packet system handles is a Prospecting effect to tell the client to draw some particles. You want to transfer TE info, getUpdatePacket and getUpdateTag exist.

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

Good news: Packet is now sent and recieved!

 

How do I now get this new data into the ContainerScreen? I suppose you would receive the packet in the ContainerScreen? I can think of how to do it with static methods, but not with the right instance.... Still, that doesn't seem like the solution... ?

 

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

Ok, so can I clarify this is actually what I need to do:

 

==

I'm sending the packet in AltarContainer#detectAndSendChanges, which means that I have an instance of the player accessing it through inv#player.

 

I send the packet to that player, but when I receive that packet, I need an instance of either a World or a PlayerEntity to work with. If I have a World, I can get the PlayerEntity using their UUID; if I have a PlayerEntity I can use that directly.

 

I need to access the currently openContainer, because then, if the openContainer is an instanceof AltarContainer, I can cast it and access the AltarContainerScreen? Because if this is taking place on the client, openContainer will give a ContainerScreen, as the Player should not directly interact with the Container itself?

 

From there, I can update the values of the maxAmethystFlux and the currentAmethystFlux.

==

 

Does this make any sense whatsoever? Am I doing everything totally wrong?

If this is, in fact, the case, which simple method to get an instance of a World or the Player am I missing?

Pushing changes to GitHub now... Thanks!

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

Link to comment
Share on other sites

Woohoo! It works! Although I've found that my packet code can be replaced by the (now working) trackedInts, I'm sure I'll need this packet knowledge soon!

 

Many thanks to you all!

 

===

 

For anyone from the future:

This link is to this commit. For reference to the rest of the Altar code, see the next link.

https://github.com/GenElectrovise/MagiksMostEvile/commit/d2ae6d39bdadf06f5078d6fe095887b6acf9f1d2

This is the full, latest, repo.

https://github.com/GenElectrovise/MagiksMostEvile/tree/1.15.2

 

 

Ps. As the altar networking code is currently unused, I have deprecated it. It will be removed at a later date when I have a better networking example.

How to ask a good coding question: https://stackoverflow.com/help/how-to-ask

Give logs, code, desired effects, and actual effects. Be thorough or we can't help you. Don't post code without putting it in a code block (the <> button on the post - select "C-type Language"): syntax highlighting makes everything easier, and it keeps the post tidy.

 

My own mod, Magiks Most Evile: GitHub (https://github.com/GenElectrovise/MagiksMostEvile) Wiki (https://magiksmostevile.fandom.com/wiki/Magiks_Most_Evile_Wiki)

Edit your own signature at https://www.minecraftforge.net/forum/settings/signature/

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.

×
×
  • Create New...

Important Information

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