Jump to content

Severe Inventory Glitch - Server/Client desync?


Reika

Recommended Posts

I have been experiencing a severe glitch with the inventory under seemingly random circumstances. It appears to be causing a desynchronization between the server and the client.

Here is what I am experiencing:

With one TileEntity (machine) in the world, the changes made in the inventory by a player (like moving things between slots) do not seem to be reflected in the server-side inventory. This manifests as situations like the following:

Player A has a hotbar full of the following, left to right: Dirt, dirt, cobble, wood, glass, empty, piston, redstone, torch. They go around and do stuff, and in the process they have rearranged their hotbar to look like the following (they have not interacted with a chest): cobble, cobble, stone, redstone, empty, empty, empty, torch, dirt.

They try to place the dirt block. Instead, a dirt block appears for a split second, and then a torch appears in that place instead. If they were to try to place the piston, what they would have seen is the piston appear for a second and then disappear, with the piston seemingly disappearing from their inventory.

When the world is reloaded, the GUI is totally rearranged to reflect what the server had in mind all along, the original hotbar.

 

That is, it seems like the client and server are disagreeing on player-GUI-made changes to the location of items in the player inventory, and since the server controls the placing of blocks, it always "wins out", causing it to look like the inventory is scrambling itself or placing different things than are intended.

 

Similarly, trying to toss items from an inventory can cause them to just disappear without spawning the item entities. When reloading the world, they reappear in the inventory, as if the "drop event" was never processed server-side.

 

Also worth noting is that block breaking exhibits a related glitch - blocks can be broken and their items picked up (making the popping noise), but they do not appear in the inventory, as the client is not getting the update that says "item is in slot x now". Again, reloading resyncs them.

 

I must emphasize that this bug is NOT consistent - its behavior is, but it exhibits itself at random times and it was only with great effort that I was able to link it to being (probably) dependent on one TileEntity existing in the world.

 

The TE Code. Note that is has NO functions for editing inventories or player data.

@Override
public void updateEntity(World world, int x, int y, int z, int meta) {
	super.updateTileEntity();
	tickcount++;
	this.getIOSides(world, x, y, z, meta);
	this.getPower(false, false);
	power = omega*torque;
	boolean nodig = true;
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++) {
			if (cutShape[i][j]) {
				nodig = false;
				i = j = 7;
			}
		}
	}
	if (nodig)
		return;
	//ModLoader.getMinecraftInstance().thePlayer.addChatMessage(String.valueOf(cutShape[0][0]));
	if (omega <= 0)
		return;
	if (this.operationComplete(tickcount, 0)) {
		this.calcReqPower(world, x, y, z, meta);
		//ModLoader.getMinecraftInstance().ingameGUI.addChatMessage(String.format("%d", this.reqpow));
		if (power > reqpow && reqpow != -1)
			this.dig(world, x, y, z, meta);
		tickcount = 0;
		if (reqpow == -1)
			step = ReikaMathLibrary.extrema(step-1, 1, "max");
	}
}

public void reqPowAdd(World world, int xread, int yread, int zread, int metadata) {
	if (world.getBlockId(xread, yread, zread) != 0) {
		reqpow += (int)(DIGPOWER*10*Block.blocksList[world.getBlockId(xread, yread, zread)].getBlockHardness(world, xread, yread, zread));
		if (ReikaMathLibrary.ceil2exp((int)(16*10*Block.blocksList[world.getBlockId(xread, yread, zread)].getBlockHardness(world, xread, yread, zread))) > mintorque)
			mintorque = ReikaMathLibrary.ceil2exp((int)(16*10*Block.blocksList[world.getBlockId(xread, yread, zread)].getBlockHardness(world, xread, yread, zread)));
		if (world.getBlockId(xread, yread, zread) == 7)
			reqpow = -1;
	}
}

public void calcReqPower(World world, int x, int y, int z, int metadata) {
	reqpow = 0;
	int mintorque = -1;
	int a = 0;
	if (metadata > 1)
		a = 1;
	int b = 1-a;
	int xread;
	int yread;
	int zread;
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++) {
			if (cutShape[i][j] || step == 1) {
				xread = x+step*xstep+a*(i-3); yread = y+step*ystep+(4-j); zread = z+step*zstep+b*(i-3);
				this.reqPowAdd(world, xread, yread, zread, metadata);
			}
		}
	}

	if (torque < mintorque)
		reqpow = -1;
	//ModLoader.getMinecraftInstance().ingameGUI.addChatMessage(String.format("%d", mintorque));
}

public void support(World world, int x, int y, int z, int metadata) {
	int a = 0;
	if (metadata > 1)
		a = 1;
	int b = 1-a;
	int xread;
	int yread;
	int zread;
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++) {
			if (cutShape[i][j] || step == 1) {
				xread = x+step*xstep+a*(i-3); yread = y+step*ystep+(4-j); zread = z+step*zstep+b*(i-3);
				int id = world.getBlockId(xread, yread+1, zread);
				if (id == Block.sand.blockID || id == Block.gravel.blockID)
					if (this.checkTop(i, j))
						if (id == Block.sand.blockID)
							ReikaWorldHelper.legacySetBlockWithNotify(world, xread, yread, zread, Block.sandStone.blockID);
						else
							ReikaWorldHelper.legacySetBlockWithNotify(world, xread, yread, zread, Block.stone.blockID);
			}
		}
	}
}

private boolean checkTop(int i, int j) {
	while (j > 0) {
		j--;
		if (cutShape[i][j])
			return false;
	}
	return true;
}

public void dropBlocks(int xread, int yread, int zread, World world, int x, int y, int z, int id, int meta) {
	if (drops && id != 0) {

		if (id == Block.mobSpawner.blockID) {
			TileEntityMobSpawner spw = (TileEntityMobSpawner)world.getBlockTileEntity(xread, yread, zread);
			if (spw != null) {
				if (world.isRemote)
					return;
				MobSpawnerBaseLogic lgc = spw.func_98049_a();
				String mob = lgc.getEntityNameToSpawn();
				//ModLoader.getMinecraftInstance().thePlayer.addChatMessage(String.format("%s", mob));
				int dmg = -1;
				if (mob == "Zombie")
					dmg = 0;
				if (mob == "Spider")
					dmg = 1;
				if (mob == "CaveSpider")
					dmg = 2;
				if (mob == "Skeleton")
					dmg = 3;
				if (mob == "Silverfish")
					dmg = 4;
				if (mob == "Blaze")
					dmg = 5;

				if (dmg == -1)
					return;
				ItemStack is = new ItemStack(mod_RotaryCraft.spawner.itemID, 1, dmg);
				EntityItem ent = new EntityItem(world, x, y, z, is);
				ent.delayBeforeCanPickup = 10;
				world.spawnEntityInWorld(ent);
				return;
			}
		}

		Block.blocksList[id].dropBlockAsItem(world, x, y+1, z, world.getBlockMetadata(xread, yread, zread), 0);
	}
}

public void dig(World world, int x, int y, int z, int metadata) {
	this.support(world, x, y, z, metadata);
	int a = 0;
	if (metadata > 1)
		a = 1;
	int b = 1-a;
	int xread;
	int yread;
	int zread;

	if (step == 1) {
		pipemeta2 = pipemeta;
		pipemeta = 3;
	}
	else if (pipemeta > 2 && pipemeta2 != 3)
		pipemeta = pipemeta2;

	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++) {
			if (cutShape[i][j] || step == 1) {
				xread = x+step*xstep+a*(i-3); yread = y+step*ystep+(4-j); zread = z+step*zstep+b*(i-3);
				this.dropBlocks(xread, yread, zread, world, x, y, z, world.getBlockId(xread, yread, zread), world.getBlockMetadata(xread, yread, zread));
				ReikaWorldHelper.legacySetBlockAndMetadataWithNotify(world, xread, yread, zread, mod_RotaryCraft.miningpipe.blockID, pipemeta);
			}
		}
	}
	step++;
}

@Override
public void writeToNBT(NBTTagCompound NBT)
{
	super.writeToNBT(NBT);
	NBT.setInteger("mode", mode);
	NBT.setBoolean("drops", drops);
	NBT.setInteger("step", step);
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++)
			NBT.setBoolean("cut"+String.valueOf(i*7+j), cutShape[i][j]);
	}
}

/**
 * Reads a tile entity from NBT.
 */
@Override
public void readFromNBT(NBTTagCompound NBT)
{
	super.readFromNBT(NBT);
	mode = NBT.getInteger("mode");
	drops = NBT.getBoolean("drops");
	step = NBT.getInteger("step");
	for (int i = 0; i < 7; i++) {
		for (int j = 0; j < 5; j++)
			cutShape[i][j] = NBT.getBoolean("cut"+String.valueOf(i*7+j));
	}
}

Link to comment
Share on other sites

I've seen this too, but only on anti-cheat servers. It's probably paranoid anti-cheat code ruining the game experience yet again. You can get back the vanished item stack back from that thieving server by opening a crafting table, btw.

 

Some hacked clients have a "steal all" button for swift snatching of valuables from others' chests. I guess this behavior is supposed to foil that, but it really seems overkill to me. And the problem is in chests being emptied, not in how quickly the attacker can do it. Just makes things hard for the players, while griefers continue to gank your diamonds and blow up your base.

 

Seriously, most servers have this "faction" or "towny" mod which encourages players to gang up on each other because if you kill someone enough you are allowed by the server to destroy their house and steal their stuff. It's to evoke a sense of epic tension between factions I guess. But the admins actively encourage that terrible grief, yet won't even let you sort your inventory claiming it's griefing. What a situation!

Link to comment
Share on other sites

I've seen this too, but only on anti-cheat servers. It's probably paranoid anti-cheat code ruining the game experience yet again. You can get back the vanished item stack back from that thieving server by opening a crafting table, btw.

 

Some hacked clients have a "steal all" button for swift snatching of valuables from others' chests. I guess this behavior is supposed to foil that, but it really seems overkill to me. And the problem is in chests being emptied, not in how quickly the attacker can do it. Just makes things hard for the players, while griefers continue to gank your diamonds and blow up your base.

 

Seriously, most servers have this "faction" or "towny" mod which encourages players to gang up on each other because if you kill someone enough you are allowed by the server to destroy their house and steal their stuff. It's to evoke a sense of epic tension between factions I guess. But the admins actively encourage that terrible grief, yet won't even let you sort your inventory claiming it's griefing. What a situation!

 

Um...not to be rude, but did you even read my post? I am having a problem with a mod I am writing in single-player. This has nothing to do with servers or admins or AntiCheat.

Link to comment
Share on other sites

If I hadn't read your post, how would I know to talk about vanishing items and inventories? Yes that was very rude! You should have said "You missed the part where I'm playing SSP."

 

So yes I missed the part where you're playing SSP. I've never had the problem in SSP nor in SMP where the server wasn't doing that mysterious anti-cheat. Even servers with lag and high latency don't seem to do it if I'm the one setting them up. Can't help you, sorry.

Link to comment
Share on other sites

Have you tried making a packet to sync the client with the server? That may help xD

 

Or is it vanilla tile-entities? Then I don't whats wrong...

I am Mew. The Legendary Psychic. I behave oddly and am always playing practical jokes.

 

I have also found that I really love making extremely long and extremely but sometimes not so descriptive variables. Sort of like what I just did there xD

Link to comment
Share on other sites

Have you tried making a packet to sync the client with the server? That may help xD

 

Or is it vanilla tile-entities? Then I don't whats wrong...

How do I sync an inventory? I know how to use 250 Custom Payload and 132 TE Data, but inventory?

 

use containerInstance.detectAndSendChanges(); (or was it inventoryInstance instead of containerInstance? Try it out for yourself, one should work)

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Link to comment
Share on other sites

i think that is rather for blocks like furnaces, to update their contents.

 

packets seem to be the problem that you have,  or, (didn't read trought the whole code) delete the tile entity together with your block. that can cause problems too sometimes. deleting the block but not the tile entity causes the tile entity to stay at the very same place. tile entities are entities, and can exist without block. they are just bound together when the block is placed, and should be destroyed likewise too.

 

i've had similar problems with gui's (client side only) consuming or giving items with a button click, but when using/rightclicking the new item, or empty itemslot , the item would reapear, or disapear, because the server never recieved the info about the change.

 

packets for giving the player items, as well as removing them, from out of a gui, is the (only) solution.

 

double check your proxies, and block code, for eventual things you might have missed. you never know.

 

 

Link to comment
Share on other sites

i think that is rather for blocks like furnaces, to update their contents.

 

packets seem to be the problem that you have,  or, (didn't read trought the whole code) delete the tile entity together with your block. that can cause problems too sometimes. deleting the block but not the tile entity causes the tile entity to stay at the very same place. tile entities are entities, and can exist without block. they are just bound together when the block is placed, and should be destroyed likewise too.

 

i've had similar problems with gui's (client side only) consuming or giving items with a button click, but when using/rightclicking the new item, or empty itemslot , the item would reapear, or disapear, because the server never recieved the info about the change.

 

packets for giving the player items, as well as removing them, from out of a gui, is the (only) solution.

 

double check your proxies, and block code, for eventual things you might have missed. you never know.

 

No, it's for ALL Inventories / Containers. I know that, because I update the player's inventory with that (and the player, as we all know, isn't a block).

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Link to comment
Share on other sites

i think that is rather for blocks like furnaces, to update their contents.

packets seem to be the problem that you have,  or, (didn't read trought the whole code) delete the tile entity together with your block. that can cause problems too sometimes. deleting the block but not the tile entity causes the tile entity to stay at the very same place. tile entities are entities, and can exist without block. they are just bound together when the block is placed, and should be destroyed likewise too.

i've had similar problems with gui's (client side only) consuming or giving items with a button click, but when using/rightclicking the new item, or empty itemslot , the item would reapear, or disapear, because the server never recieved the info about the change.

packets for giving the player items, as well as removing them, from out of a gui, is the (only) solution.

double check your proxies, and block code, for eventual things you might have missed. you never know.

use containerInstance.detectAndSendChanges(); (or was it inventoryInstance instead of containerInstance? Try it out for yourself, one should work)

Here is the thing. Even when the machine has no GUI or container - and thus does not interact with inventories in any way - the problem still persists.

Link to comment
Share on other sites

i think that is rather for blocks like furnaces, to update their contents.

packets seem to be the problem that you have,  or, (didn't read trought the whole code) delete the tile entity together with your block. that can cause problems too sometimes. deleting the block but not the tile entity causes the tile entity to stay at the very same place. tile entities are entities, and can exist without block. they are just bound together when the block is placed, and should be destroyed likewise too.

i've had similar problems with gui's (client side only) consuming or giving items with a button click, but when using/rightclicking the new item, or empty itemslot , the item would reapear, or disapear, because the server never recieved the info about the change.

packets for giving the player items, as well as removing them, from out of a gui, is the (only) solution.

double check your proxies, and block code, for eventual things you might have missed. you never know.

use containerInstance.detectAndSendChanges(); (or was it inventoryInstance instead of containerInstance? Try it out for yourself, one should work)

Here is the thing. Even when the machine has no GUI or container - and thus does not interact with inventories in any way - the problem still persists.

 

Then what I suggest is that you send a packet if the "inventory" you have in place (the itemstack array) changes. To do so, create a NBTTagCompound instance and write all of your items from the array into it (look at the TileEntityChest or TileEntityDispenser for code examples - writeToNBT / readFromNBT).

To send the NBT to the client, look at this code: https://github.com/SanAndreasP/TurretModv3/blob/master/sanandreasp/mods/TurretMod3/registry/CommonProxy.java#L74-L86

To receive the NBT client-side, use this: https://github.com/SanAndreasP/TurretModv3/blob/master/sanandreasp/mods/TurretMod3/client/packet/PacketRecvPlayerNBT.java#L19

Don't ask for support per PM! They'll get ignored! | If a post helped you, click the "Thank You" button at the top right corner of said post! |

mah twitter

This thread makes me sad because people just post copy-paste-ready code when it's obvious that the OP has little to no programming experience. This is not how learning works.

Link to comment
Share on other sites

Then what I suggest is that you send a packet if the "inventory" you have in place (the itemstack array) changes. To do so, create a NBTTagCompound instance and write all of your items from the array into it (look at the TileEntityChest or TileEntityDispenser for code examples - writeToNBT / readFromNBT).

To send the NBT to the client, look at this code: https://github.com/SanAndreasP/TurretModv3/blob/master/sanandreasp/mods/TurretMod3/registry/CommonProxy.java#L74-L86

To receive the NBT client-side, use this: https://github.com/SanAndreasP/TurretModv3/blob/master/sanandreasp/mods/TurretMod3/client/packet/PacketRecvPlayerNBT.java#L19

Thank you - this seems promising. :)

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.