Jump to content

NBT Data - Specifically Client-Server Interaction


Samalot

Recommended Posts

 

First and foremost, I have been criticized in the past for not researching enough before posting; this is not the case – my question may seem simple to some, but I can assure you that my misunderstanding is no because I can’t be bothered to search for an answer (I have been all day). My problems usually stem from having no idea what to search for - feel free to give me any points and be as harsh as you want! I want to learn!

 

 

From what I understand, certain blocks of code (in my case - onEntityGetHurt event) should be run on the server only and vise versa. You essentially have the code for the server/client in one and control access with @Side or Remote world.

 

But how does the client interact with the server? - I am aware of packets, but have been avoiding them somewhat. Is a packet sent over the web? from the client's pc to the server?

 

I chose to share information between Client/Server sections of code using NBT data stored on the player.

 

Here is my problem

I have a mod:

  • Adds a suite of tokens to the game.
  • Tokens provide a passive effect to the player, you just need to have them on your inventory to get the effect.
  • The effects are not necessarily potion effects, for example - prevent block damage from explosions (tapping into the event bus).

 

The game (client and server) has to know which tokens the player currently has - I opted to do this by adding a new NBT Tag to the player for each token:

 

EntityPlayer player = (EntityPlayer) event.entityLiving; /*Get player*/

tags = player.getEntityData(); /*Get tag cloud*/

tags.setBoolean("amplifyingToken", false); /*Create a new tag*/

...

player.writeToNBT(tags); /*Save the tag cloud*/

 

Every tick (on player update event), the players NBT tags are updated to match the inventory - this is done CLIENT SIDE only.

 

@SubscribeEvent
@SideOnly(Side.CLIENT)
public void onPlayerUpdate(PlayerTickEvent event) 
{	
	/*Collect the world.*/
	World world = Minecraft.getMinecraft().theWorld;
	/*Token stuff*/
	if(event.phase == Phase.START){Profile.scan(event.player);}/*Update Inventory*/			
}

 

 

Scan code (for those interested)

 

 

/*Update inventory*/
public static void scan(EntityPlayer player) {
	tags = player.getEntityData();

	/*Create temp values*/
	boolean amplifyingTokenTemp = false;

	/*Iterate over inventory*/
	for(int i=0; i<39; i++)
	{
		if(player.inventory.getStackInSlot(i) != null)
		{
			/*Check item*/
			ItemStack currentItemStack = player.inventory.getStackInSlot(i);
			Item currentItem = currentItemStack.getItem();
			if(currentItem instanceof AmplifyingToken){amplifyingTokenTemp = true;}
		}
	}
	/*Evaluate*/
	if(amplifyingTokenTemp != tags.getBoolean("amplifyingToken")){tags.setBoolean("amplifyingToken", amplifyingTokenTemp);}

	player.writeToNBT(tags);
}

 

 

 

However, if the server then tries to read the players NBT Data - it does not show the updated version.

 

  • Is NBT data suitable for sharing information client-to-server?
  • Am I correctly writing and saving the NBT data? - player.writeToNBT(tags);

 

 

Sorry if this is trivial. If you need more info, please let me know - I am painfully aware how how vague some of this may seem.

 

Thanks in advance!

Link to comment
Share on other sites

Okay, you are basically doing everything wrong (literally everything). :)

 

Don't fear young padawan! Teach you, we shall.

 

1. SIDES:

 

First some stuff about sides. Read link before continuing.

http://mcforge.readthedocs.io/en/latest/concepts/sides/

I have never read this, but it's official so it must be somehow useful.

 

Anyway if you didn't grasp the idea:

Client.jar always has client thread.

Server thread can be on either dedicated server (Server.jar) or integrated one (which can be either started "next to" your client thread by SP, or by other client which would launch LAN).

Putting it in nicer words: SP is MP with only one player online.

 

Now, @SideOnly is a thing affecting physical side only (.jar). Marking something as such means that it will only be loaded by VM on given side (e.g: Minecraft.class doesn't exist on Dedicated.jar).

 

The world.isRemote is for logical checks.

 

Now - if you think about it client thread can't do SHIT on its own - there is always server (dedic, integrated, LAN).

That means there are always packets - also in SP (integrated server).

 

Now that I basically restated what was in the link:

 

Yes - different code fires for different logical sides. LivingHurtEvent is that case (server thread handles damaging, client only receives health change and other stuff like knockback/color change. Ofc. there are many more of those events.

 

General rule:

Whenever you do shit - you do it on server. If this shit needs to be displayed to some or all clients - you need to send it (always via packet).

 

2. NBT

 

First of all - NBT has nothing (kinda) to do with syncing or any other shit for that matter. It is literally a Map<String, NBTBase>.

It can be used as a format for sending packets (but shouldn't) or to even hold data sometimes (not recommended), BUT general purpose of it is serializing (kinda like json) data to objects that can be written to files (HDD).

 

3. Per-player data:

 

You should never access "getEntityData();" for other things than reading or modifying values that are handled by vanilla (e.g: change position or inventory). If you want to hold you shit per-player you will use @Capability (or IExtendedEntityProperties for earlier than 1.8.9).

http://mcforge.readthedocs.io/en/latest/datastorage/capabilities/

 

4. Syncing shit:

 

Only thing that gets synced, is the shit that vanilla does - ItemStacks (their NBT), Entities and other shit.

If you ever attach additional info to say Entity (@Capability) - it will never be synced unless you send packets to do so.

 

Note: @Capability can be attached on server, client or both.

Note to note: If you havent got it yet - each thread has its own entity (client has one which corresponds to one on server, whatever server is).

Logically - your attached data object (Capability) can be on either of those sides.

 

When you change value, you do it on server (generally) and then send packet to client to change its.

 

Here is my problem

I have a mod:

  • Adds a suite of tokens to the game.
  • Tokens provide a passive effect to the player, you just need to have them on your inventory to get the effect.
  • The effects are not necessarily potion effects, for example - prevent block damage from explosions (tapping into the event bus).

 

Why do you need to attach additional data to player, if you have your tokens in format of Items? Just override Item#onUpdate() to act upon player. Or you can access player's inventory from event to check if given item is there.

 

For more direct help - more direct questions.

 

ONE DAY - I will write tut on this shit. Getting tired of repeating myself. :P

Note to OP: If you want to know stuff - read this forum and posts of popular helpers.

1.7.10 is no longer supported by forge, you are on your own.

Link to comment
Share on other sites

Thanks for all of that! :)

 

(and for being patient, I get the impression there must be 10 people like my asking similar questions each day)

I'll have a read through the recourses you linked!

 

As, for why I don't just check the players inventory each time - ill start doing that now!

 

The issues was that these tokens are not just stored in the players inventory, but in other inventories too - such as a token pouch! (however, the more I think about it, the more I realise it is a non-issue)

 

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.