Jump to content

Recommended Posts

Posted

I have a block which, when collided with, checks for a certain item in the player's hand. If found, it uses the item's data tags to get a coordinate, and then teleports the player there.

 

This *almost* works. Except when the teleportation occurs, I get a server warning in the console saying "[Playername] moved wrongly!" and end up getting teleported right back next to the block instead of the proper coordinates. I tried looking into the EntityEnderPearl code to see how that handles teleportation, and it seems to just use EntityPlayerMP#setPositionAndUpdate...but that's what I'm using and the server is complaining about it.

 

I've found online other people who've had this trouble, but the solutions were for older versions of Forge which no longer apply; how do I teleport the player properly without it complaining and rubber-banding them?

 

Here's the code in question:

 

]@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayer player = (EntityPlayer) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			NBTTagCompound tag = mainItem.getTagCompound();
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			mainItem.damageItem(1, player);
			player.setPositionAndUpdate(x, y, z);
			player.setFire(1);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {

			NBTTagCompound tag = offItem.getTagCompound();
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			offItem.damageItem(1, player);
			player.setPositionAndUpdate(x, y, z);
			EntityEnderPearl p;
			player.setFire(1);
		}
	}
}

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

EntityPlayerMP does override

Entity#setPositionAndUpdate()

, so try changing this

EntityPlayer player = (EntityPlayer) entity;

to this

EntityPlayerMP player = (EntityPlayerMP) entity;

 

Currently you are actually calling

Entity#setPositionAndUpdate()

rather than

EntityPlayerMP#setPositionAndUpdate()

. This is becasuee the field player is of the type EntityPlayer, not EntityPlayerMP; EntityPlayer does not override

setPositionAndUpdate()

and neither does EntityLivingBase, so

Entity#setPositionAndUpdate()

is called.

 

Posted

Thanks for the pointer, but no dice. I changed the cast to EntityPlayerMP, but nothing changed: I still get the "Player moved wrongly" warning and the rubber-band effect.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

same problem here  :-\

If you figure out a solution, please post here; I can't for the life of me get this working properly, and it's ruining my mod's development!

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

Have you tryed and changed this property

"player.velocityChanged=true"

Has no effect, whether I add it before or after the teleportation (setPositionAndUpdate) line. Still get the same warning and rubber-banding.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

Its sound like a client server sync issue to me. After looking at your code you are call it both on the client and server which causes sync issue. Try wrapping your block with if(!world.isRemove) { ... } and try again. This will call that line of code on the server only.

Posted

The entire method is wrapped in a conditional that checks if

!entity.worldObj.isRemote

....the whole thing runs only on the server.

 

A bit of file searching shows this warning occurs under the following conditions:

 

1) The player is not in creative or spectator mode.

2) The player is not sleeping.

3) The player has not just switched dimensions.

4) The server update packet shows the player is more than 0.25 blocks away from the player's last known location.

 

Which, of course, is the current situation when teleporting. But I don't understand why, then, it doesn't trigger the warning when using an Ender Pearl, since the EntityEnderPearl uses the same method to teleport the player on the server just as I'm doing...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

Ok I figured it out. You need to call it in both the client and server. That means remove the if(!world.isRemove) {} then that error will stop.

 

Here is my example.

@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	super.onEntityCollidedWithBlock(world, pos, state, entity);
	if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	}
}

@Override
public void onEntityWalk(World world, BlockPos pos, Entity entity) {
	// TODO Auto-generated method stub
	super.onEntityWalk(world, pos, entity);


	//if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	//}

}

 

However, I ran into a weird problem with the onEntityCollidedWithBlock event. It was firing so I used the onEntityWalk even and it worked.

Posted

Ok I figured it out. You need to call it in both the client and server. That means remove the if(!world.isRemove) {} then that error will stop.

 

Here is my example.

@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	super.onEntityCollidedWithBlock(world, pos, state, entity);
	if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	}
}

@Override
public void onEntityWalk(World world, BlockPos pos, Entity entity) {
	// TODO Auto-generated method stub
	super.onEntityWalk(world, pos, entity);


	//if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	//}

}

 

However, I ran into a weird problem with the onEntityCollidedWithBlock event. It was firing so I used the onEntityWalk even and it worked.

If I use onEntityWalk, the method is never called; keep in mind this is a fire-based block with no collision box.

 

Using onEntityCollidedWithBlock, but moving the isRemote check around just the damageItem lines (which is required or else there's weird damage desync problems with the item) and not around the teleportation line, still gives the warning/rubber banding...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Posted

That might be your problem. I'm currently using version 12.18.2.2107 which is the version that I did my testing with. I did receive the error message but I wasn't rubber banning back to the same location with the test example I created. I think it could be a forge bug cause the issue. Try updating to the latest version of forge and I think it should because when I compared your code to my code they look almost identical for the exception you are store your location an items nbt and my was hard-coded. I think its a forge bug so updating forge should fix the issue.

Posted

Look at

CommandTeleport

on how to do teleportation properly. It most certainly should not be happening client-side at all.

Thanks for the info and I agree that teleportation should not be happening on the client.

 

Look at the setPlayerLocation method, its the one that changes the player location.

Posted

Look at

CommandTeleport

on how to do teleportation properly. It most certainly should not be happening client-side at all.

 

It seems like all that command does is call EntityPlayerMP's connection.setPlayerLocation() for the teleport. So I tried using that, and I still get the "Player Moved Wrongly" warning and rubber-banding...

 

Here's the current code:

 

	protected void teleport(EntityPlayerMP player, BlockPos destination) {
	teleport(player, destination.getX(), destination.getY(), destination.getZ());
}

protected void teleport(EntityPlayerMP player, int x, int y, int z) {
	player.connection.setPlayerLocation(x, y, z, player.rotationYaw, player.rotationPitch);
}

// Teleport the player when they walk through the flames with a linked
// portkey
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayerMP player = (EntityPlayerMP) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();

		NBTTagCompound tag = null;
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			tag = mainItem.getTagCompound();
			mainItem.damageItem(1, player);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {
			tag = offItem.getTagCompound();
			offItem.damageItem(1, player);
		}

		if (tag != null) {
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			player.velocityChanged = true;
			teleport(player, x, y, z);
			player.setFire(1);
		}
	}
}

 

Next I'll try using the latest version of Forge and see if that helps, but for now, I'm doing exactly what the teleport command does but it's still complaining.

Whatever Minecraft needs, it is most likely not yet another tool tier.

  • 6 months later...
Posted (edited)
On 10/18/2016 at 0:21 AM, IceMetalPunk said:

 

It seems like all that command does is call EntityPlayerMP's connection.setPlayerLocation() for the teleport. So I tried using that, and I still get the "Player Moved Wrongly" warning and rubber-banding...

 

Here's the current code:

 

 


	protected void teleport(EntityPlayerMP player, BlockPos destination) {
	teleport(player, destination.getX(), destination.getY(), destination.getZ());
}

protected void teleport(EntityPlayerMP player, int x, int y, int z) {
	player.connection.setPlayerLocation(x, y, z, player.rotationYaw, player.rotationPitch);
}

// Teleport the player when they walk through the flames with a linked
// portkey
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayerMP player = (EntityPlayerMP) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();

		NBTTagCompound tag = null;
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			tag = mainItem.getTagCompound();
			mainItem.damageItem(1, player);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {
			tag = offItem.getTagCompound();
			offItem.damageItem(1, player);
		}

		if (tag != null) {
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			player.velocityChanged = true;
			teleport(player, x, y, z);
			player.setFire(1);
		}
	}
}
 

 

 

Next I'll try using the latest version of Forge and see if that helps, but for now, I'm doing exactly what the teleport command does but it's still complaining.

 
 

 

 

I've tried the basically same thing, taken straight from the command, in multiple game versions, and the results I get a very, very weird.  I implemented my TP in an abstract base class, and had four classes that inherited it (for short vs. long range, and one-way vs. two-way teleporters).  All inherited directly, no changes.  It works perfectly 100% of the time for both one-way teleporters but not the two-way (always the error if in survival, even with cheats on, works if used in creative). 

 

So, this way can work, sometimes, but why it sometimes doesn't is a mystery that needs some explaining (and probably a fix) -- will anyone else answer this?

Edited by JaredBGreat

Developer of Doomlike Dungeons.

  • 4 months later...
Posted

Apologies for the minor necro, but I have some information to add to this thread which I figured might be useful...

 

I hit this same problem today while porting PneumaticCraft's air cannon to 1.12 - one of the air cannon's modes allows players to be launched into the air.  Worked fine if I triggered the cannon via a button, but I got the "player moved wrongly!" message when triggering with a pressure plate.  The reason for this is that the pressure plate's redstone signal (and the resulting actions) is directly triggered by entity movement, so EntityPlayerMP#setPositionAndUpdate() effectively ends up getting called from within Entity#move().  This is sufficient to trigger the server's move validation checks, since the player has moved further than expected.

 

I got around it with a bit of a gross hack: using reflection to set EntityMP's private invulnerableDimensionChange field to true right before calling setPositionAndUpdate() - the server validation code will be ignored if this field is true.  This at least has the nice side effect of being automatically switched off pretty much straight away; as soon as the server receives a CPacketConfirmTeleport packet, which happens as soon as the client gets the SPacketPlayerPosLook packet.

 

It's not pretty, but it works.

  • Like 1
Posted
On 10/15/2016 at 8:27 PM, Leviathan143 said:

EntityPlayerMP does override


Entity#setPositionAndUpdate()
 

, so try changing this

 


EntityPlayer player = (EntityPlayer) entity;
 

 

to this

 


EntityPlayerMP player = (EntityPlayerMP) entity;
 

 

 

Currently you are actually calling


Entity#setPositionAndUpdate()
 

rather than


EntityPlayerMP#setPositionAndUpdate()
 

. This is becasuee the field player is of the type EntityPlayer, not EntityPlayerMP; EntityPlayer does not override


setPositionAndUpdate()
 

and neither does EntityLivingBase, so


Entity#setPositionAndUpdate()
 

is called.

 

This doesn't sound right to me. Isn't the whole point of virtual methods that you don't have to worry about this?

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.